Giter Club home page Giter Club logo

isctl's Introduction

User Guide Build status Go Report

isctl - CLI for Cisco Intersight

isctl is a kubectl-insipired CLI for the Cisco Intersight service.

Features

  • Generated automatically from the Intersight OpenAPI v3 spec - it should be easy to keep up with new Intersight features.
  • Written in Go and distributed as MacOS, Linux and Windows binaries - should work anywhere
  • Human, JSON or YAML output
  • JSONpath support for extraction and transformation of the data returned from the API

Installation

MacOS

If you use Homebrew, the easiest way to install isctl is:

brew install cgascoig/isctl/isctl

If you don't use Homebew:

  • Download the latest release from the Releases page.
  • Unzip and move the isctl binary somewhere that is on your path (e.g. /usr/local/bin).

Windows

The easiest way is using the scoop.sh installer:

scoop install https://github.com/cgascoig/isctl/raw/devel/isctl.json

Otherwise:

  • Download the latest release from the Releases page.
  • Unzip and move the isctl.exe binary somewhere that is on your path.

Linux

  • Download the latest release from the Releases page.
  • Extract the .tar.gz and move the isctl binary somewhere that is on your path (e.g. /usr/local/bin).

Documentation

The Quick Start below covers the basics but you should review the Users Guide for complete documentation.

Quick Start

Initial configuration

Obtain your API Key

isctl interacts with the Cisco Intersight REST API, so it needs an API key.

  1. Login to the Intersight GUI.
  2. Generate a new API Key (under Settings -> API Keys). Choose "API key for OpenAPI schema version 2" as the API Key Purpose.
  3. Save the key somewhere on your desktop and make a note of the key ID.

Configure isctl

Run isctl configure to configure it to use your API key. Follow the prompts for your key ID and path to the key file. (Note: the path to the key file should be an absolute path and doesn't support shell metacharacters such as "~")

keyID is currently ''
Enter new keyID or press Enter to keep existing: 123456789012345678901234/123456789012345678901234/123456789012345678901234
key filename is currently ''
Enter new key file name or press Enter to keep existing: /Users/chris/intersight-key.pem
2020/06/25 17:28:22 Writing config file

Querying Intersight

To retrieve resources from Intersight, use the isctl get ... commands.

For example, to query all objects of a certain type:

isctl get ntp policy

Output:

------------  -----------------------------  ------------------------  -----------------------------
    Enabled                           Moid                      Name                     NtpServers
------------  -----------------------------  ------------------------  -----------------------------
      False       5ecb069c6275722d3143e668           test-ntp-policy

       True       5ee1aa076275722d3122a944          cg-tf-ntp-test-1       10.10.10.10, 10.10.10.12
------------  -----------------------------  ------------------------  -----------------------------

For detailed documentation, see the isctl Users Guide.

Development

How is this built?

There are a number of steps in the build process as the majority of the code is generated automatically:

  1. OpenAPITools OpenAPI Generator is used to generate the Go models and API client from the Intersight OpenAPI v3 spec. The OpenAPI Generator Go templates are customised to also generate an operations.yaml file.
  2. The Go program in generator-postprocess is used to parse the operations.yaml file and generate the command line structure in cmd/cli.go. This postprocess step also cleans up the command naming and creates the help text.
  3. Finally, the isctl command is built from the generated cmd/cli.go along with some supporting code.

Creating a release

The Makefile is used for most of the post processing and building isctl for the local system but GoReleaser is used for creating releases on GitHub.

# Create tag and push to GitHub
git tag vX.Y.Z
git push origin --tags

# Create the release
goreleaser --rm-dist

isctl's People

Contributors

baelen-git avatar cgascoig avatar dependabot[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

isctl's Issues

JSONPath doesn't work with default output

./build/isctl get ntp policy moid 5ee1aa076275722d3122a944 --jsonpath '$.Name'
panic: runtime error: slice bounds out of range [1:0]

goroutine 1 [running]:
github.com/bndr/gotabulate.(*Tabulate).Render(0xc0001c7000, 0xc00018b918, 0x1, 0x1, 0x0, 0x3a8ee00)
	/Users/cgascoig/dev/go/pkg/mod/github.com/bndr/[email protected]/tabulate.go:223 +0x1189
main.printResultDefault(0x27f56e0, 0xc0003ce910)
	/Users/cgascoig/AAA-CG-Documents/Cisco/demo-lab/dev/starship/isctl/cmd/output.go:242 +0x148
main.resultHandler(0x27f56e0, 0xc0003ce910, 0xc0004d8000, 0x0, 0x0)
	/Users/cgascoig/AAA-CG-Documents/Cisco/demo-lab/dev/starship/isctl/cmd/output.go:45 +0x1d3
main.GetCommands.func1.3.35.1.2.1(0xc00029cdc0, 0xc00019ced0, 0x1, 0x3)
	/Users/cgascoig/AAA-CG-Documents/Cisco/demo-lab/dev/starship/isctl/cmd/cli.go:27179 +0x25a
github.com/spf13/cobra.(*Command).execute(0xc00029cdc0, 0xc00019cea0, 0x3, 0x3, 0xc00029cdc0, 0xc00019cea0)
	/Users/cgascoig/dev/go/pkg/mod/github.com/spf13/[email protected]/command.go:846 +0x2c2
github.com/spf13/cobra.(*Command).ExecuteC(0xc0000c6840, 0xc00018bf08, 0x1, 0x1)
	/Users/cgascoig/dev/go/pkg/mod/github.com/spf13/[email protected]/command.go:950 +0x375
github.com/spf13/cobra.(*Command).Execute(...)
	/Users/cgascoig/dev/go/pkg/mod/github.com/spf13/[email protected]/command.go:887
main.main()
	/Users/cgascoig/AAA-CG-Documents/Cisco/demo-lab/dev/starship/isctl/cmd/main.go:63 +0x8ff

Improve formatting of tags in table outputs

Instead of:

----------------------------  -----------------------------------------------------------------------  ------------------------------------
                       Name                                                                     Tags                               Version
----------------------------  -----------------------------------------------------------------------  ------------------------------------
             cisg-team-call       map[Key:intersight.kubernetes.SupportStatus Value:UpgradeRequired]                         1.19.16-iks.0

Should be something like:

----------------------------  -----------------------------------------------------------------------  ------------------------------------
                       Name                                                                     Tags                               Version
----------------------------  -----------------------------------------------------------------------  ------------------------------------
             cisg-team-call       intersight.kubernetes.SupportStatus: UpgradeRequired                         1.19.16-iks.0

Improve credential source options

  • Add support for supplying credentials as environment variables
  • Order of precedence for credentials:
    1. --keyID/--keyFile
    2. Environment variables
    3. Config file
  • Support key (instead of just keyfile) in config file / isctl configure

MoRef syntax should support more complex filters

In some scenarios MoRef needs to filter on more than 1 attribute. For example an asset.DeviceRegistration reference might need to filter on DeviceHostname=XYZ and PlatformType=IWE because there are 2 registrations with the same DeviceHostname (one PlatformType=HX and one PlatformType=IWE)

Show error message when failed to create resource

See the output of the command below

❯ isctl --config ~/.isctl-ocp2.yaml apply -f vnic_ethif.yaml   
INFO[0000] Performing create operation on new MO (Name: eth0, ClassId: vnic.EthIf) 
FATA[0003] Error while applying MOs: Error executing operation: 400 Bad Request 

I would like to know the reason of the failed API POST. You can get this by enabling verbose mode.

❯ isctl --config ~/.isctl-ocp2.yaml apply -f vnic_ethif.yaml   -v
INFO[0000] Performing create operation on new MO (Name: eth0, ClassId: vnic.EthIf) 
.....
{"code":"InvalidRequest","message":"The request body contains the 'SpVnics' relationship, which is read-only. Do not include read-only relationships in the request body","messageId":"barcelona_request_cannot_modify_read_only_relationships","messageParams":{"1":"SpVnics"},"traceId":"zHDFd14jBvtLVtzIN-wrgUQ1Fo3SG2PVj4KnkT2uMOyYnM2ku0n1Kg=="}
FATA[0002] Error while applying MOs: Error executing operation: 400 Bad Request 

Please grep the message from the response when there is an error and show that message (without enabling verbose mode)

re-apply creates new resource

When changing the name of the Kubernetes cluster profile it will create a new cluster profile instead of just changing the name

Don't capitalize the first letter of the word

When I query for workflows and select the Internal field it shows "False" but the value actually is "false" without the capital F

❯ isctl --config ~/.isctl-dev.yaml -k get workflow workflowinfo --filter "Status eq 'RUNNING' AND Internal eq false" --select Status,Internal
-----------------------------  -------------  ------------
                        Moid       Internal        Status
-----------------------------  -------------  ------------
    62d056f6696f6e2d3052b36b          False       RUNNING
    62d056fb696f6e2d3052b4af          False       RUNNING
-----------------------------  -------------  ------------

Input field is missing in WorkflowInfo

❯ isctl create workflow workflowinfo --help
Create a 'workflow.WorkflowInfo' resource.

Provide resource body as JSON on standard input

Usage:
  isctl create workflow workflowinfo [flags]

Flags:
      --Account string                       Account
      --AccountMoid string                   AccountMoid
      --Action string                        Action
      --Ancestors json                       Ancestors as JSON
      --AssociatedObject string              AssociatedObject
      --ClassId string                       ClassId
      --CleanupTime string                   CleanupTime
      --CreateTime string                    CreateTime
      --DomainGroupMoid string               DomainGroupMoid
      --Email string                         Email
      --EndTime string                       EndTime
      --FailedWorkflowCleanupDuration int    FailedWorkflowCleanupDuration
      --InstId string                        InstId
      --Internal                             Internal
      --LastAction string                    LastAction
      --Message json                         Message as JSON
      --MetaVersion int                      MetaVersion
      --ModTime string                       ModTime
      --Moid string                          Moid
      --Name string                          Name
      --ObjectType string                    ObjectType
      --Organization string                  Organization
      --Owners strings                       Owners
      --Parent string                        Parent
      --ParentTaskInfo string                ParentTaskInfo
      --PauseReason string                   PauseReason
      --PendingDynamicWorkflowInfo string    PendingDynamicWorkflowInfo
      --Permission string                    Permission
      --PermissionResources json             PermissionResources as JSON
      --Progress float32                     Progress
      --Properties json                      Properties as JSON
      --RetryFromTaskName string             RetryFromTaskName
      --SharedScope string                   SharedScope
      --Src string                           Src
      --StartTime string                     StartTime
      --Status string                        Status
      --SuccessWorkflowCleanupDuration int   SuccessWorkflowCleanupDuration
      --Tags json                            Tags as JSON
      --TaskInfos json                       TaskInfos as JSON
      --TraceId string                       TraceId
      --Type string                          Type
      --UserActionRequired                   UserActionRequired
      --UserId string                        UserId
      --VersionContext json                  VersionContext as JSON
      --WaitReason string                    WaitReason
      --WorkflowCtx json                     WorkflowCtx as JSON
      --WorkflowDefinition string            WorkflowDefinition
      --WorkflowMetaType string              WorkflowMetaType
      --WorkflowTaskCount int                WorkflowTaskCount
      --WorkflowWorkerTaskCount int          WorkflowWorkerTaskCount
      --bodyformat string                    Format of request body passed on stdin (e.g. "json"). Default: don't read from stdin
  -h, --help                                 help for workflowinfo

Global Flags:
      --config string     config file (default is $HOME/.isctl.yaml)
  -k, --insecure          Allow insecure server connections (disable SSL certificate validation)
      --jsonpath string   JSONPath filter to apply to the result (e.g. "$.Name")
      --keyFile string    API Private Key Filename
      --keyID string      API Key ID
  -o, --output string     Output format. One of default|yaml|json|table|jsonpath|custom-columns|csv. Examples:
                          	Get Name attribute from all NTP policies: isctl get ntp policy -o jsonpath="[*].Name"
                          	Table with just Name and Enabled attributes: isctl get ntp policy -o custom-columns=NAME:.Name,ENABLED:.Enabled
                          	See [https://isctl.netlify.app/1-basic-queries/#output-customisation] (default "default")
      --server string     Intersight API Server Address (e.g."intersight.com") (default "intersight.com")
  -v, --verbose           verbose logging

Creating Targets doesn't work

This body works through the API docs but when I try it with

cat vcenter-claim.json | isctl create asset target --bodyformat json

it gives me this error
FATA[0000] ERROR: Generating API body: Error retreiving relationship: 6295dc5c7564612d309659ad

{
    "Connections": [
        {
            "ManagementAddress": "198.18.133.30",
            "Port": 443,
            "Credential": {
                "Username": "[email protected]",
                "Password": "yourpassword",
                "ObjectType": "asset.UsernamePasswordCredential"
            },
            "IsSecure": true,
            "ObjectType": "asset.HttpConnection"
        }
    ],
    "TargetType": "VmwareVcenter",
    "Account": "6295dc5c7564612d309659ad",
    "Assist": {
        "Moid": "6295e4096f72612d30d1ae25",
        "ObjectType": "asset.Target"
    },
    "Name": "198.18.133.30",
    "Services": [
        {
            "ObjectType": "asset.WorkloadOptimizerService",
            "Options": {
                "ObjectType": "asset.WorkloadOptimizerVmwareVcenterOptions",
                "GuestMetricsEnabled": false
            }
        },
        {
            "ObjectType": "asset.OrchestrationService",
            "Options": {
                "ObjectType": "asset.OrchestrationHsmVmwareVcenterOptions",
                "hsmEnabled": false
            }
        }
    ]
}

I grabbed this body when creating a target through the UI and using the browser debugger.
You can do the same for your vCenter target.

Improve command line help

  • Include some examples in get and its subcommands. (See kubectl for example)
  • Link to isctl user guide where appropriate
  • Improve help text for create/update command flags, e.g. this should be better:
--AccountMoid string               AccountMoid

isctl version should work with no/invalid configuration

chris@Chriss-iMac Downloads % isctl version
Error: Unable to create request context with authentication: Cannot load private key '/Users/chris/intersight-key.pem'. Error: open /Users/chris/intersight-key.pem: no such file or directory

Fix long delay before each query

On MacOS and Windows in many situations, there is a long delay before the request is sent. This appears to be due to DNS resolution using the Go builtin resolver:

time="2022-05-19T15:54:12+10:00" level=info msg="DNSStart {intersight.com}\n"
go package net: built with netgo build tag; using Go's DNS resolver
time="2022-05-19T15:54:17+10:00" level=info msg="DNS Info: {Addrs:[{IP:65.8.133.110 Zone:} …] Err:<nil> Coalesced:false}\n" 

Fixing cross compiling to use CGO on all platforms should fix this

Improve documentation

Add documentation on expand, custom-colums, select, ...

examples to include:

❯ isctl get equipment tpm  --expand 'ComputeBoard($expand=ComputeRackUnit,ComputeBlade)' -o custom-columns=Serial:.Serial,BladeSerial:.ComputeBoard.ComputeBlade.Serial,RackSerial:.ComputeBoard.ComputeRackUnit.Serial,ActivationStatus:.ActivationStatus,Admi
nState:.AdminState
----------------  ----------------  ----------------  ---------------------  ---------------
         Serial       BladeSerial        RackSerial       ActivationStatus       AdminState
----------------  ----------------  ----------------  ---------------------  ---------------
             NA            <none>       FCH2035V0CP                unknown          unknown
    FCH1807J9V6       FCH18097X4Z            <none>                unknown          unknown
    FCH1803JEVA       FCH18097X4Z            <none>              activated          enabled
             NA            <none>       FCH2002V21L                unknown          unknown
    FCH221173Z3            <none>       WZP21520P1Y                     NA          enabled
             NA            <none>       FCH1810V1C4                unknown          unknown
    FCH2041774F       FCH2046736C            <none>              activated          enabled
    FCH20337FE5       FCH210977GZ            <none>              activated          enabled
             NA            <none>       FCH2002V21J                unknown          unknown
             NA            <none>       FCH2002V1NL                unknown          unknown
             NA            <none>       FCH2132V15A                unknown          unknown
             NA            <none>       WZP22440MUW                unknown          unknown
             NA            <none>       WZP22441AT6                unknown          unknown
             NA            <none>       FCH2108V0NU                unknown          unknown
             NA            <none>       FCH2002V1ZP                unknown          unknown
    FCH1906J0U6            <none>       FCH1902V1FX              activated          enabled
----------------  ----------------  ----------------  ---------------------  --------------- 
❯ isctl get kubernetes clusterprofile --expand 'NodeGroups($expand=KubernetesVersion($expand=Version))' -o custom-columns='Name:.Name,Version:.NodeGroups[0].KubernetesVersion.Version.Name,Tags:.NodeGroups[0].KubernetesVersion.Version.Tags'
----------------------------  ------------------------------------  ---------------------------------------------------------
                       Name                               Version                                                       Tags
----------------------------  ------------------------------------  ---------------------------------------------------------
             cisg-team-call                         1.19.16-iks.0       intersight.kubernetes.SupportStatus: UpgradeRequired
                saju-demo-1                         1.19.16-iks.0       intersight.kubernetes.SupportStatus: UpgradeRequired
                   saj-demo                                <none>                                                     <none>

Improve error messages

❯ isctl create ntp policy --Name cg-deleteme-1 --Organization default
FATA[0006] ERROR: 400 Bad Request

should include the API error message: ""Cannot create NTP Policy 'cg-deleteme-1'. NTP Policy with at least one NTP Server has to be specified"

no able to get the view server list

❯ isctl get view server
FATA[0001] ERROR applying jsonPath filter: JSON marshalling error: json: error calling MarshalJSON for type *intersight.ViewServerResponse: unexpected end of JSON input

Add shortcut commands to simplify common IKS tasks

Examples:

  • isctl iks cluster create --name XYZ --version 1.18.2 --worker-nodes 3 --master-nodes 1 --worker-node-spec medium --ippool XYZ --vm-provider XYZ
  • isctl iks cluster kubeconfig --name XYZ
  • isctl iks cluster deploy --name XYZ
  • isctl iks cluster undeploy --name XYZ
  • ...

Column order in custom-column output is random

[cgascoig@cg-linux-1 isctl]$ ./build/isctl ${ISCTL_OPTIONS} get ntp policy -o custom-columns='NAME:.Name,TAGS:.Tags' --filter "Name eq 'cg-tf-ntp-test'"
-------------------  ---------------------------------------------
              NAME                                           TAGS
-------------------  ---------------------------------------------
    cg-tf-ntp-test       Automation: Terraform, Creator: cgascoig
-------------------  ---------------------------------------------

[cgascoig@cg-linux-1 isctl]$ ./build/isctl ${ISCTL_OPTIONS} get ntp policy -o custom-columns='NAME:.Name,TAGS:.Tags' --filter "Name eq 'cg-tf-ntp-test'"
---------------------------------------------  -------------------
                                        TAGS                 NAME
---------------------------------------------  -------------------
    Automation: Terraform, Creator: cgascoig       cg-tf-ntp-test
---------------------------------------------  -------------------

Support list of MoRefs

In YAML for apply, should be able to do:

ClusterIpPools:
- MoRef[ip-pool-1]
- MoRef[ip-pool-2]

Perform JSONpath filtering before collapsing single element lists

When querying the API and using JSONpath to manipulate the result, different JSONpath is needed depending on whether there is a single item returned or multiple. e.g.:

This works if there is more than 1 vmwarecluster object:

isctl get virtualization vmwarecluster --jsonpath='$[*].Name'

But will fail (silently return nothing) if there is only 1 object returned.

Similarly, if there is more than 1, this will fail:

isctl get virtualization vmwarecluster --jsonpath='$.Name'
FATA[0000] ERROR applying jsonPath filter: JSONPath parsing error: could not select value, invalid key: expected number but got Name (string)

Should move JSONPath processing to happen before collapsing/simplifying results

ISCTL fails with error on self signed certificates for intersight api.

This can be allowed by modifying the client.go in openapi with the snippit below, but it would be good to have as a cli option:
in imports add :
"crypto/tls"
in func NewAPIClient(cfg *Configuration) *APIClient {
add the code block below before the if cfg.HTTPClient == nil {
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{InsecureSkipVerify: true}
_, err := http.Get("https://golang.org/")
if err != nil {
fmt.Println(err)

see my fork :
https://github.com/bshapiro4254/isctl

Brew install not working on Monterey 12.3

(venv) KEITHH-M-RMYN:src keithh$ brew --version
Homebrew 3.4.3
Homebrew/homebrew-core (git revision a57b31329bc; last commit 2022-03-24)
Homebrew/homebrew-cask (git revision c38da9fc2e; last commit 2022-03-24)
(venv) KEITHH-M-RMYN:src keithh$ brew install cgascoig/isctl/isctl
==> Tapping cgascoig/isctl
Cloning into '/usr/local/Homebrew/Library/Taps/cgascoig/homebrew-isctl'...
remote: Enumerating objects: 24, done.
remote: Counting objects: 100% (24/24), done.
remote: Compressing objects: 100% (22/22), done.
remote: Total 24 (delta 6), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (24/24), done.
Resolving deltas: 100% (6/6), done.
Error: Invalid formula: /usr/local/Homebrew/Library/Taps/cgascoig/homebrew-isctl/isctl.rb
isctl: Calling bottle :unneeded is disabled! There is no replacement.
Please report this issue to the cgascoig/isctl tap (not Homebrew/brew or Homebrew/core):
/usr/local/Homebrew/Library/Taps/cgascoig/homebrew-isctl/isctl.rb:9

Error: Cannot tap cgascoig/isctl: invalid syntax in tap!
(venv) KEITHH-M-RMYN:src keithh$

Screen Shot 2022-03-24 at 10 39 33 AM

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.