Skip to content

Commit

Permalink
Merge pull request #3 from uempfel/add-apply-command
Browse files Browse the repository at this point in the history
Add apply command
  • Loading branch information
uempfel authored Apr 29, 2021
2 parents e9e8d91 + 092a9af commit abe8e8c
Show file tree
Hide file tree
Showing 6 changed files with 261 additions and 47 deletions.
115 changes: 115 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,28 @@ Nsxtea is a small CLI to interact with the VMware NSX-T Search API. Sip a cup of
The CLI will only work with NSX-T versions `3.0` and above. Unfortunately, the API endpoints `nsxtea` relies on are not available in previous versions.

## Installation
The CLI can be installed via two methods.

### Installation via binary
Binaries for Linux, macOS and Windows are available on the [repos's release page](https://github.com/uempfel/nsxtea/releases).
To the install `nsxtea` this way, follow these steps:

```bash
# Set a variable to the release version you want to download
export NSXTEA_VERSION=0.1.0
# Download the release for your platform (macOS in this example)
curl -L https://github.com/uempfel/nsxtea/releases/download/v${NSXTEA_VERSION}/nsxtea_${NSXTEA_VERSION}_Darwin_x86_64.tar.gz -o nsxtea.tar.gz

# Unpack the compressed folder
tar -xvzf nsxtea.tar.gz
x LICENSE
x README.md
x nsxtea
# Move the binary to your PATH
mv nsxtea /usr/local/bin
```

### Installation via go
Assuming you have already [installed go](https://golang.org/doc/install):

```sh
Expand Down Expand Up @@ -37,6 +59,10 @@ export NSXTEA_INSECURE='true'


## Usage
Currently, nsxtea supports two commands, which are documented below:
* [search](#search-command)
* [apply](#apply-command)

Simply type `nsxtea --help` to get help about `nsxtea`'s usage

```bash
Expand All @@ -51,6 +77,7 @@ Usage:
nsxtea [command]

Available Commands:
apply Interact with the Hierarchical Policy API
help Help about any command
search Interact with the Policy or Manager Search API

Expand Down Expand Up @@ -141,6 +168,94 @@ The reserved characters are: `+ - = && || > < ! ( ) { } [ ] ^ " ~ * ? : \ /`
Failing to escape these reserved characters correctly would lead to syntax errors and prevent the query from running.


### Apply command
This command lets you interact with Hierarchical Policy API. It's enables declarative creation, updates and deletion of Policy Objects. To get an overview on how to create objects with the Hierarchical API, this [VMware Blog by Madhukar Krishnarao](https://blogs.vmware.com/networkvirtualization/2020/06/navigating-nsxt-policy-apis.html/) is highly recommended.
Please refer to [the official API docs](https://vdc-download.vmware.com/vmwb-repository/dcr-public/d6de7a5e-636f-4677-8dbd-6f4ba91fa5e0/36b4881c-41cd-4c46-81d1-b2ca3a6c693b/api_includes/method_PatchInfra.html) for all objects that can be created.

```bash
Decalaratively apply configurations via yaml or json
files.

Examples:
nsxtea apply -f infra.yaml
nsxtea apply -f infra.json

Usage:
nsxtea apply [flags]

Flags:
-f, --filepath string Path to the file that contains the configuration to apply
-h, --help help for apply
```

#### Example
The following example is taken from the Blog referenced above. It creates a Tier0 and a connected Tier1 Router in one call.

1) Create a file containing the Objects you want to create. The `apply` command accepts json and yaml input.
* Example as yaml: `infra.yaml`
```yaml
resource_type: Infra
display_name: infra
children:
- resource_type: ChildTier1
marked_for_delete: "false"
Tier1:
resource_type: Tier1
display_name: my-Tier-1-GW-Prod
id: my-Tier-1-GW-Prod
tier0_path: /infra/tier-0s/Tier-0-GW-West-01
- resource_type: ChildTier0
marked_for_delete: "false"
Tier0:
resource_type: Tier0
display_name: Tier-0-GW-West-01-Disconnected
id: Tier-0-GW-West-01
```
* The same Objects a json (taken from [Madhukar Krishnarao's Blog](https://blogs.vmware.com/networkvirtualization/2020/06/navigating-nsxt-policy-apis.html/)): `infra.json`
```json
{
"resource_type": "Infra",
"display_name": "infra",
"children": [
{
"resource_type": "ChildTier1",
"marked_for_delete": "false",
"Tier1": {
"resource_type": "Tier1",
"display_name": "my-Tier-1-GW-Prod",
"id": "my-Tier-1-GW-Prod",
"tier0_path": "/infra/tier-0s/Tier-0-GW-West-01"
}
},
{
"resource_type": "ChildTier0",
"marked_for_delete": "false",
"Tier0": {
"resource_type": "Tier0",
"display_name": "Tier-0-GW-West-01-Disconnected",
"id": "Tier-0-GW-West-01"
}
}
]
}
````
2) Run the apply command providing the path to the file you created
```bash
# Apply as yaml
nsxtea apply -f path/to/infra.yaml
# Apply as json
nsxtea apply -f path/to/infra.json
```

That's it! The objects should be created and be available after a short time.

#### Updating and deleting objects
To update objects, simply adapt the file with the necessary configuration and re-run `nsxtea apply`.

Deleting the objects created in the example above is as simple as changing the `marked_for_delete` properties from `true` to `false`. Once you've done that, simply re-run `nsxtea apply` and the objects should be deleted after a short time.

### Image Credits
* Gopher: [Maria Letta - Free Gophers Pack](https://github.com/MariaLetta/free-gophers-pack)
* Teacup: [RROOK, NL](https://thenounproject.com/term/cup-of-tea/2870740/)
87 changes: 87 additions & 0 deletions cmd/apply.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
Copyright © 2021 NAME HERE <EMAIL ADDRESS>
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package cmd

import (
"bytes"
"fmt"
"github.com/ghodss/yaml"
"github.com/spf13/cobra"
"io/ioutil"
"net/http"
"os"
)

var filePath string

var applyCmd = &cobra.Command{
Use: "apply",
Short: "Interact with the Hierarchical Policy API",
Long: `Decalaratively apply configurations via yaml or json
files.
Examples:
nsxtea apply -f infra.yaml
nsxtea apply -f infra.json`,
Run: handleApply,
}

func handleApply(cmd *cobra.Command, args []string) {

fileContent, err := ioutil.ReadFile(filePath)
if err != nil {
fmt.Println("Error parsing file\n", err)
os.Exit(1)
}

fileContent, err = yaml.YAMLToJSON(fileContent)
if err != nil {
fmt.Println(err)
os.Exit(1)
}

endpoint := "/policy/api/v1/infra"
body := bytes.NewBuffer(fileContent)
req, err := http.NewRequest("PATCH", "https://"+url+endpoint, body)
if err != nil {
fmt.Println(err)
os.Exit(1)
}
req.Header.Set("Content-Type", "application/json")
req.SetBasicAuth(userName, password)

client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println(err)
os.Exit(1)
}

if resp.StatusCode != 200 {
bodyText, err := ioutil.ReadAll(resp.Body)
printErrIfNotNil(err)
s := string(bodyText)
fmt.Println(s)
os.Exit(1)
}
fmt.Println(resp.Status)
}

func init() {
rootCmd.AddCommand(applyCmd)
applyCmd.PersistentFlags().StringVarP(&filePath, "filepath", "f", "", "Path to the file that contains the configuration to apply")
cobra.MarkFlagRequired(applyCmd.PersistentFlags(), "filepath")
}
11 changes: 9 additions & 2 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,16 @@ package cmd
import (
"crypto/tls"
"fmt"
"github.com/spf13/cobra"
"net/http"
"os"
"strconv"
"github.com/spf13/cobra"
)

var cfgFile string
var userName string
var password string
var url string
var nsxtInsecure bool

// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Expand All @@ -48,6 +51,10 @@ func Execute() {

func init() {

userName = os.Getenv("NSXTEA_USERNAME")
password = os.Getenv("NSXTEA_PASSWORD")
url = os.Getenv("NSXTEA_URL")

nsxtInsecure, err := strconv.ParseBool(os.Getenv("NSXTEA_INSECURE"))
if err != nil {
nsxtInsecure = false
Expand Down
85 changes: 41 additions & 44 deletions cmd/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,11 @@ import (
"fmt"

"github.com/spf13/cobra"
"os"
"net/http"
"io/ioutil"
"net/http"
"os"
"strconv"
"strings"
"strings"
)

var includedFields string
Expand All @@ -33,8 +33,6 @@ var cursor string
var pageSize string
var useManagerApi bool



// searchCmd represents the search command
var searchCmd = &cobra.Command{
Use: "search <query>",
Expand Down Expand Up @@ -96,57 +94,57 @@ To search for (a+b)=c
The reserved characters are: + - = && || > < ! ( ) { } [ ] ^ " ~ * ? : \ /
Failing to escape these reserved characters correctly would lead to syntax errors and prevent the query from running.
`,
Run: handleSearch,
Args: cobra.MinimumNArgs(1),
Run: handleSearch,
Args: cobra.MinimumNArgs(1),
}

func handleSearch(cmd *cobra.Command, args []string) {

endpoint := "/api/v1/search/query?"
if !useManagerApi {
endpoint = "/policy" + endpoint
}
req, err := http.NewRequest("GET", "https://"+ os.Getenv("NSXTEA_URL")+ endpoint, nil)

query := concatArgs(args)
q := req.URL.Query()
q.Add("query", query)
q.Add("included_fields", includedFields)
q.Add("sort_ascending", strconv.FormatBool(sortAscending))
q.Add("sort_by", sortBy)
q.Add("cursor", cursor)
q.Add("page_size", pageSize)
req.URL.RawQuery = q.Encode()

req.SetBasicAuth(
os.Getenv("NSXTEA_USERNAME"),
os.Getenv("NSXTEA_PASSWORD"),
)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil{
fmt.Println(err)
os.Exit(1)
}

bodyText, err := ioutil.ReadAll(resp.Body)
printErrIfNotNil(err)
s := string(bodyText)
fmt.Println(s)
endpoint := "/api/v1/search/query?"
if !useManagerApi {
endpoint = "/policy" + endpoint
}
req, err := http.NewRequest("GET", "https://"+url+endpoint, nil)

query := concatArgs(args)
q := req.URL.Query()
q.Add("query", query)
q.Add("included_fields", includedFields)
q.Add("sort_ascending", strconv.FormatBool(sortAscending))
q.Add("sort_by", sortBy)
q.Add("cursor", cursor)
q.Add("page_size", pageSize)
req.URL.RawQuery = q.Encode()

req.SetBasicAuth(
userName,
password,
)
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println(err)
os.Exit(1)
}

bodyText, err := ioutil.ReadAll(resp.Body)
printErrIfNotNil(err)
s := string(bodyText)
fmt.Println(s)
}

func init() {

rootCmd.AddCommand(searchCmd)
searchCmd.PersistentFlags().StringVarP(&includedFields, "included_fields", "f", "", "Comma separated list of fields that should be included in query result")
searchCmd.PersistentFlags().StringVarP(&sortBy, "sort_by", "s", "", "Field by which records are sorted")
searchCmd.PersistentFlags().BoolVarP(&sortAscending, "sort_ascending","a", true, "Sorting order of the query results")
searchCmd.PersistentFlags().StringVarP(&cursor, "cursor", "c", "", "Opaque cursor to be used for getting next page of records (supplied by current result page)")
searchCmd.PersistentFlags().StringVarP(&pageSize, "page_size", "p", "1000", "Maximum number of results to return in this page \nMin: 0, Max: 1000")
searchCmd.PersistentFlags().BoolVarP(&useManagerApi, "manager", "m", false, "Use the Manager API for the search request")
searchCmd.PersistentFlags().BoolVarP(&sortAscending, "sort_ascending", "a", true, "Sorting order of the query results")
searchCmd.PersistentFlags().StringVarP(&cursor, "cursor", "c", "", "Opaque cursor to be used for getting next page of records (supplied by current result page)")
searchCmd.PersistentFlags().StringVarP(&pageSize, "page_size", "p", "1000", "Maximum number of results to return in this page \nMin: 0, Max: 1000")
searchCmd.PersistentFlags().BoolVarP(&useManagerApi, "manager", "m", false, "Use the Manager API for the search request")
}

func concatArgs(args[] string) string {
func concatArgs(args []string) string {
var concatArgs string
for i := 0; i < len(args); i++ {
concatArgs += args[i] + " "
Expand All @@ -159,4 +157,3 @@ func printErrIfNotNil(err error) {
fmt.Println(err)
}
}

5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@ module github.com/uempfel/nsxtea

go 1.15

require github.com/spf13/cobra v1.1.3
require (
github.com/ghodss/yaml v1.0.0
github.com/spf13/cobra v1.1.3
)
Loading

0 comments on commit abe8e8c

Please sign in to comment.