CWM XDK for Cisco NSO

The CWM XDK for NSO (cwm-nsox) is an application that helps you generate interfaces and logic for custom adapters intended to interact with the Cisco Network Services Orchestrator(NSO).

The primary purpose of cwm-nsox is to reduce the time-consuming and error-prone manual process of constructing paths and payloads required for CWM to communicate with NSO.

The tool complements the Adapter SDK and is able to automatically define interfaces in .proto files and implementation of logic in the adapter go module. This is achieved by parsing yang files and points of interest provided by the Adapter Developer.

Prerequisites

  • Installed CWM SDK and dependencies.
  • The NSO src/ncs/yang folder for yang module imports. If you don't have it, you may install Cisco NSO to get it as part of a full installation.

Get cwm-nsox

The cwm-nsox is a binary that comes with the Crosswork Workflow Manager Software Package.

Go to Cisco Software Download page to download the .tar file with the CWM Software Package, where the cwm-nsox resides. Unpack the .tar and move the contents of the adapters folder to a desired location

tip.gif

Tipblank.gifIt's recommended that you put the binary in a common folder, with the cwm-sdk and other extension binaries like cwm-oasx.


Remember to include the location of the cwm-nsox binary by setting the environment variable path:

export PATH=/path/to/adapter-dev-binaries:$PATH

Use cwm-nsox for creating custom NSO adapter

The cwm-nsox works with yang models of NSO services and NEDs files to identfiy yang paths that you'd like to address using the adapter.

Step 1: Create an adapter stub with Adapter SDK

Run the following command to create a new adapter using SDK:

cwm-sdk create-adapter \
-vendor cisco \
-product nsox \
-feature services \
-ignore-template
note.gif

Noteblank.gifThe ignore-template option eliminates tips and descriptions from the generated .proto files.


Step 2: Display yang paths and adapter code

display-paths

Use the cwm-nsox display-paths command to extract paths for activities from a source yang file. With the -src option, you specify the desired yang configuration file:

cwm-nsox display-paths -src ../path/to/source/file.yang

You will see a list of yang paths based on which you can generate adapter activities.

display-proto

Optionally, use the display-proto command with the -poi option to display the output for the activity based on your chosen point of interest:

cwm-nsox display-proto \
-src ../path/to/source/file.yang \
-poi your-nsoservice:your-nsoservice-list=%s/example-leaf

The output will look similar to this:

service Activities {
    /*
     * Description for activity NsoActivity
     */
    rpc NsoActivity (NsoActivityRequest) returns (cisco.cwmlib.nso.Response);
}

/*
 * Description for NsoActivityRequest
 */
message NsoActivityRequest {
    string deviceName = 1; // devices/device={deviceName}
    optional string dummyLeaf = 2; // tailf-ned-cwm-dmycli:dummy-leaf
    cisco.cwmlib.nso.PutQuery queries = 3;
}

The following options are available:

Option Data type Description Status
-deps string Define paths to yang imports (comma separated list). optional
-poi string Point to desired yang path (point of interest) required
-src string Point to path of yang configuration file. required
-verbose string Show command progress info. Options are: off, on, or very. optional

display-json

Optionally, use the display-json command with the required -poi and -src options to display the data payload for the activity based on your chosen point of interest (path):

cwm-nsox display-json \
-src ../path/to/source/file.yang \
-poi your-nsoservice:your-nsoservice-list=%s/example-leaf
Option Data type Description Status
-deps string Define paths to yang imports (comma separated list). optional
-poi string Point to desired yang path (point of interest) required
-src string Point to path of yang configuration file. required
-verbose string Show command progress info. Options are: off, on, or very. optional

Step 3: Generate activity

Using the path defined in the previous section, you can now run the generate-activity command.

Go to the main directory of your adapter and execute the following command (adjust the path, activity name, operation type and point-of-interest name accordingly):

 cwm-nsox generate-activity \
 -src ../path/to/source/file.yang \
 -feature services \
 -activity NsoActivity \
 -oper PUT \
 -poi your-nsoservice:your-nsoservice-list=%s/example-leaf

This will generate a new adapter activity with a predefined rpc and I/O messages in the .proto files (see example in the section above), as well as a ready-to-execute implementation in the .go files.

Here's an example of the output generated by the cwm-nsox and inserted in the activities.go file:

package services

import (
    "context"

    "www.cisco.com/cwm/adapters/cisco/nsox/common"
    "www.cisco.com/cwm/sdk/adapters/logger"
    "www.cisco.com/cwm/sdk/adapters/nso"
)


func (adp *Adapter) NsoActivity(ctx context.Context, 
    req *NsoActivityRequest, cfg *common.Config) (*nso.Response, error) {
    logger.GetLogger(ctx).Info("Activity cisco.nsox.services.NsoActivity called...")
    return nso.SendCustomRequest(ctx, req, cfg)
}

Create activity (optional)

Optionally, you can create a new activity for a selected feature but without indicating the source file. This will create an activity implementation in the .go files and a stub for you to fill in the logic inside the .proto file:

cwm-nsox create-activity \
-feature device \
-activity TestActivity \
-oper GET \

Here's an example of the activity stub generated by the cwm-nsox inserted in the .proto file:

service Activities {

...

    /*
     * Description for activity Testactivity
     */
    rpc Testactivity (TestactivityRequest) returns (TestactivityResponse);

}
...

/*
 * Description for TestactivityRequest
 */
message TestactivityRequest {
    // NOTE: Developer needs to set vars
}

message TestactivityResponse {
    // NOTE: Developer needs to set vars
}

Step 4: Test your adapter

To test your adapter, generate an installable file and install the adapter in CWM.

Generate installable

Go to the main directory of your adapter and run the following command:

cwm-sdk create-installable

Test adapter activity

This will create a .tar file that can be then uploaded into CWM. Follow the detailed instructions in the Install NSO adapter section to install and deploy the adapter, then run a workflow that uses the newly added adapter activity.

CWM XDK for OpenAPI

Use CWM XDK for OpenAPI (cwm-oasx) to automatically build interfaces and message logic for custom adapters that require communicating with OpenAPI-based systems. With the cwm-oasx tool, you point to an OpenAPI operation defined in JSON, which cwm-oasx will then use to generate a new adapter activity with a predefined rpc and I/O messages in the .proto files, as well as a ready-to-execute implementation in the adapter .go files.

Prerequisites

  • Installed CWM SDK and dependencies.
  • A JSON or YAML schema file of an OpenAPI or Swagger-enabled API.

Get cwm-oasx

The cwm-oasx is a binary that comes with the Crosswork Workflow Manager Software Package.

Go to Cisco Software Download page to download the .tar file with the CWM Software Package, where the cwm-oasx resides. Unpack the .tar and move the contents of the adapters folder to a desired location.

tip.gif

Tipblank.gifIt's recommended that you put the binary in a common folder, with the cwm-sdk and other extension binaries like cwm-nsox.


Remember to include the location of the cwm-oasx binary by setting the environment variable path:

export PATH=/path/to/adapter-dev-binaries:$PATH

Use cwm-oasx for implementing adapter activities

The cwm-oasx works with OpenAPI JSON/YAML schemas to identify endpoint paths and methods that you'd like to call using the adapter. Follow this instruction to create a single adapter activity based on a single API path and method.

note.gif

Noteblank.gifAs an example, we'll use the NetBox REST API schema in YAML format downloaded from the NetBox Swagger API. Using a JSON schema is also supported.


Step 1: Create an adapter stub with CWM SDK

Run the following command to create a new adapter using SDK:

cwm-sdk create-adapter \
-vendor cisco \
-product oasx \
-feature services \
-ignore-template
tip.gif

Tipblank.gifThe ignore-template option eliminates tips and descriptions from the generated .proto files.


Step 2: Display paths and adapter code

display-paths

Use the cwm-oasx display-paths to extract paths and methods for activities from a source JSON/YAML file. Use the -src option to point to the desired JSON/YAML API schema file:

cwm-oasx display-paths -src ../path/to/source/NetBox_REST_API.yaml

A list of paths will be displayed. In the example, we're interested in first of the four that define operations on ipam/prefixes:

/api/ipam/prefixes/ : [GET POST PUT PATCH DELETE]
/api/ipam/prefixes/{id}/ : [GET PUT PATCH DELETE]
/api/ipam/prefixes/{id}/available-ips/ : [GET POST]
/api/ipam/prefixes/{id}/available-prefixes/ : [GET POST]

display-proto

Optionally, use the display-proto command with the -oper, -path, and -src options to display the output for the activity based on your chosen point of interest:

cwm-oasx display-proto \
-oper POST \
-path /api/ipam/prefixes/ \
-src ../path/to/source/NetBox_rest.yaml

The output will look similar to this:

Proto messages for activity:
    message ProtoRequest {
        message Data {
            optional string comments = 1;
            optional string customFields = 2;
            optional string description = 3;
            optional bool isPool = 4; // All IP addresses within this prefix are considered usable
            optional bool markUtilized = 5; // Treat as 100% utilized
            string prefix = 6;
            optional int32 role = 7; // The primary function of this prefix
            optional int32 site = 8;
            optional string status = 9; // Operational status of this prefix\n\n* `container` - Container\n* `active` - Active\n* `reserved` - Reserved\n* `deprecated` - Deprecated
            message Tags {
                optional string color = 1;
                string name = 2;
                string slug = 3;
            }
            repeated Tags tags = 10;
            optional int32 tenant = 11;
            optional int32 vlan = 12;
            optional int32 vrf = 13;
        }
        Data data = 3;
    }

    message ProtoResponse {
        int32 status = 1;
        google.protobuf.Value data = 2;
    }

Note that three of four available options are required:

Option Data type Description Status
-oper string Point to specific operation: GET, POST, PUT, PATCH or DELETE. required
-path string Point to specific API path. required
-src string Point to desired JSON API schema file. required
-verbose string Show command progress info. Options are: off, on, or very. optional

display-json

Optionally, use the display-json command with the required -oper, -path, and -src options to display the data payload for the activity based on your chosen point of interest (path):

cwm-oasx display-json \
-oper POST \
-path /api/ipam/prefixes/ \
-src ../path/to/source/NetBox_rest.yaml

The output will look similar to this:

Data payload for activity:
{
    "comments": "%s",
    "custom_fields": "{{'{'}}%s{{'}'}}",
    "description": "%s",
    "is_pool": %t,
    "mark_utilized": %t,
    "prefix": "%s",
    "role": %d,
    "site": %d,
    "status": "%s",
    "tags": [
        "color": "%s",
        "name": "%s",
        "slug": "%s"
    ],
    "tenant": %d,
    "vlan": %d,
    "vrf": %d
}

Note that three of four available options are required:

Option Data type Description Status
-oper string Point to specific operation: GET, POST, PUT, PATCH or DELETE. required
-path string Point to specific API path. required
-src string Point to desired JSON API schema file. required
-verbose string Show command progress info. Options are: off, on, or very. optional

Step 3: Generate activity

Using the path defined in the previous section, you can now run the generate-activity command.

Go to the main directory of your adapter and execute the following command (adjust the feature and activity name, operation, path, and source accordingly):

cwm-oasx generate-activity \
-feature services \
-activity PostPrefix \
-oper POST \
-poi /api/ipam/prefixes/ \
-src ../path/to/source/NetBox_rest.yaml

This will generate a new adapter activity with a predefined rpc and I/O messages in the .proto files (see example in the display-proto section above), as well as a ready-to-execute implementation in the .go files. Here's an example of the function generated by the cwm-oasx and inserted in the activities.go file:

func (adp *Adapter) PostPrefix(ctx context.Context, req *PostPrefixRequest, cfg *common.Config) (*PostPrefixResponse, error) {
    return oas.SendRequest[*PostPrefixResponse](ctx, req, cfg.GetResource(), cfg.GetSecret())
}

Create activity (optional)

Optionally, you can create a new activity for a selected feature but without indicating the source json/yaml file. This will create an activity implementation in the .go files and a stub for you to fill in the logic inside the .proto file:

cwm-oasx create-activity \
-feature services \
-activity TestActivity \
-oper POST \

Here's an example of the activity stub generated by the cwm-oasx inserted in the .proto file:

service Activities {

...

    /*
     * Description for activity Testactivity
     */
    rpc Testactivity (TestactivityRequest) returns (TestactivityResponse);

}
...

/*
 * Description for TestactivityRequest
 */
message TestactivityRequest {
    // NOTE: Developer needs to set vars
}

message TestactivityResponse {
    // NOTE: Developer needs to set vars
}

Step 4: Generate feature (optional)

Use this command to bulk create activities for new or existing features. If you point to a path, generate-feature will pick all the endpoints existing down this path and generate activity code based on each, for all available methods. Set verbose to on or very to see details of command execution.

For example, let's use the CWM JSON API specification and pass /secret as the path parameter for feature services.

cwm-oasx generate-feature \
-src ../path/to/source/cwm.json \
-feature services \
-poi /secret \
-verbose on 

Expand the sample to see what the generated output will look like in the activities.go file:

??? sample ```go package services

import (
    "context"

    "cisco.com/cwm/lib/xdk/oas"
    "cisco.com/cwm/adapters/cisco/oasx/common"
)

func (adp *Adapter) GetType(ctx context.Context, req *GetTypeRequest, cfg *common.Config) (*GetTypeResponse, error) {
    return oas.SendRequest[*GetTypeResponse](ctx, req, cfg.GetResource(), cfg.GetSecret())
}

func (adp *Adapter) Get(ctx context.Context, req *GetRequest, cfg *common.Config) (*GetResponse, error) {
    return oas.SendRequest[*GetResponse](ctx, req, cfg.GetResource(), cfg.GetSecret())
}

func (adp *Adapter) Post(ctx context.Context, req *PostRequest, cfg *common.Config) (*PostResponse, error) {
    return oas.SendRequest[*PostResponse](ctx, req, cfg.GetResource(), cfg.GetSecret())
}

func (adp *Adapter) GetWithSecretId(ctx context.Context, req *GetWithSecretIdRequest, cfg *common.Config) (*GetWithSecretIdResponse, error) {
    return oas.SendRequest[*GetWithSecretIdResponse](ctx, req, cfg.GetResource(), cfg.GetSecret())
}

func (adp *Adapter) PatchWithSecretId(ctx context.Context, req *PatchWithSecretIdRequest, cfg *common.Config) (*PatchWithSecretIdResponse, error) {
    return oas.SendRequest[*PatchWithSecretIdResponse](ctx, req, cfg.GetResource(), cfg.GetSecret())
}

func (adp *Adapter) DeleteWithSecretId(ctx context.Context, req *DeleteWithSecretIdRequest, cfg *common.Config) (*DeleteWithSecretIdResponse, error) {
    return oas.SendRequest[*DeleteWithSecretIdResponse](ctx, req, cfg.GetResource(), cfg.GetSecret())
}

func (adp *Adapter) GetTypeWithSecretTypeId(ctx context.Context, req *GetTypeWithSecretTypeIdRequest, cfg *common.Config) (*GetTypeWithSecretTypeIdResponse, error) {
    return oas.SendRequest[*GetTypeWithSecretTypeIdResponse](ctx, req, cfg.GetResource(), cfg.GetSecret())
}
```

The generate-feature command comes with the following options:

Option Data type Description Status
-src string Point to desired JSON/YAML API schema file. required
-feature string Give name of adapter feature to be updated. required
-poi string Point to specific API path. required
-verbose string Show command progress info. Options are: off, on, or very. optional

Export XDK module to local directory

The cwm-oasx uses the XDK go module for performing tasks, and some of them can share some of the resources with the NSOX extension. While the XDK module is exported to the directory of your adapter upon executing the generate-activity command, in certain cases you might want to have the XDK go module created in the adapter directory beforehand. For this purpose, use the export-lib command.

The export-lib command comes with the following options:

Option Data type Description Status
-location string Provide location where XDK lib should be created. (default: current directory) optional
-verbose string Show command progress info. Options are: off, on, or very. optional

Generate installable

Go to the main directory of your adapter and run the following command:

cwm-sdk create-installable

Test adapter activity

The command will produce a .tar file that can be then installed in CWM and tested for proper functioning.