Skip to content
/ cliapi Public

cliapi ( pronounced calliope ): A Python framework for creating Unix, "getopt()" style CLI scripts composed from an arbitrary set of APIs.

License

Notifications You must be signed in to change notification settings

edlane/cliapi

Repository files navigation

Guide for CLIAPI Plugin Developers:

cliapi ( pronounced calliope ): A Python framework for creating Unix, "getopt()" style CLI scripts composed from an arbitrary set of APIs.

...at its core, cliapi is a data driven, state machine for dynamically generating CLIs.

cliapi features:

  • entire CLI is generated by applying python decorators to API calls together with a dictionary which specifies a backing-API-store. This decorator is applied to each API that is supported by a "plugin provider". For each cloud provider (eg. Azure or GCE) a supporting "plugin" module is added to the cliapi/providers directory (see cliapi directory layout below) Presumably the plugin developer will rarely need to change the cliapi framework itself which involves a little python meta-programming (1 decorator + 1 dictionary overriding class).

  • consistent command line behavior is enforced by the cliapi framework across all plugin providers. Several common commands are automatically inherited by all plugin providers: (this allows a level of "discoverablility" to the CLI across all plugin providers)

    • "--list-providers" Lists all the available plugin providers.
    • "--provider=" specify a particular provider plugin for all CLI commands.
    • "--all" Lists all data returned by all APIs supported by a single provider.
    • "--list-apis" Lists all the APIs available by a particular plugin provider.
    • "--query=" extracts specified API data using a python-dictionary-restricted syntax.
  • other behaviors enforced by the cliapi framework:

    • error handling and help is also consistent across all plugin providers.
    • multiple queries in same command will return a JSON list in "option order" by default
    • single query will return a single JSON element.
  • multiple data queries within the same CLI will result in "at most" a single API call.

Key cliapi plugin developer concepts:

An example cliapi plugin provider for Azuremeta API + SUSE extensions can be found here: https://github.com/edlane/cliapi/blob/master/cliapi/providers/azure.py

  • provider: an associated set of APIs accessed from the CLI in a particular context or cloud environment e.g. "azure", "gce", "ec2", ... but can essentially be any mix of apis

  • api: an API for interfacing to remote or local services. If the interface can be implemented as a python function with an (*args, **kwargs) style calling convention AND it returns a JSON serializable object, THEN it can easily become a configurable CLI query. With the cliapi decorator, both required and optional parameters are expressible through the CLI. Help is also handled by the cliapi framework.

  • scoops: a dictionary which maps a CLI query name to a particular API data scoop. "scoops" are really just "sandboxed python eval()" statements. This allows predefined scoops to be expressed as CLI options. It also allows for restricted ad-hoc queries to be provided on the command line when a return value is not currently supported as an option in the CLI. The query uses Python's dictionary lookup syntax for slice slices (See examples using --query= below). Python's eval() function allows limiting access to a single data structure and "no builtins" through this facility:

  • fetchers: a dictionary which maps from a particular API name to the actual python function which provides the backing store for the contents of the top-level API dictionary.

cliapi directory layout:

├── cliapi                      root of cliapi package
│   ├── __init__.py
│   ├── cliapi_lib.py           framework meta classes and decorators
│   ├── cliapi.py               main() and the CLI generation code
│   └── what_cloud.py           module (useful for detecting which cloud plugins are valid)
│   ├── providers               directory for plugin providers
│   │   ├── __init__.py
│   │   ├── azure.py            plugin for Azure/SUSE APIs
│   │   ├── <your plugin here>  ...your plugin goes here
│   │   ├── ...                 ...additional plugins are automatically discovered by cliapi
│   │   └── test.py             ..."because it's not a framework without at least 2 plugins"
├── design.md                   design considerations for cliapi
├── LICENSE                     provisional license (Apache2 is mutable into any other license)
├── README.md                   this document
└── setup.py                    Python installation script

Examples:

example #1 - Common help AND plugin provider help (default provider = azure)

ed-sle12sp3byos:/home/lane/cliapi # cliapi --help
usage: /usr/bin/cliapi [display option#1]... [API option#1]... [CLI option]

***[ azure ]*** provider Display options:
  --internal-ip                     
  --location         region location
  --cloud-service    what           
  --instance-name    name of instance
  --mac              the MAC address for this interface
  --external-ip                     

***[ azure ]*** provider API config options:
  --api_version=     default='2017-08-01', azure metadata api version

Common CLI options:
  --help             help for this CLI command
  --provider=        specify name of provider module
  --list-providers   list all available providers
  --list-apis        list all available APIs for specified provider
  --query=           specify a python dictionary style query command
  --all              output all API results for specified API options or defaults

example #2 - a predefined query option (default provider = azure)

ed-sle12sp3byos:/home/lane/cliapi # cliapi --internal-ip
"172.16.3.8"

example #3 - all values returned by all APIs (default provider = azure)

ed-sle12sp3byos:/home/lane/cliapi # cliapi --all
{
  "meta_data": {
    "compute": {
      "location": "westus",
      "vmSize": "Standard_B1ms",
      "osType": "Linux",
      "platformUpdateDomain": "0",
      "sku": "12-SP3",
      "name": "ed-sle12sp3byos",
      "placementGroupId": "",
      "resourceGroupName": "ed_lane",
      "offer": "SLES-BYOS",
      "vmId": "ce01dc32-6d0a-40bd-9534-a3509f768a53",
      "tags": "",
      "subscriptionId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
      "version": "2018.02.21",
      "publisher": "SUSE",
      "platformFaultDomain": "0"
    },
    "network": {
      "interface": [
        {
          "ipv6": {
            "ipAddress": []
          },
          "ipv4": {
            "ipAddress": [
              {
                "publicIpAddress": "40.112.253.198",
                "privateIpAddress": "172.16.3.8"
              }
            ],
            "subnet": [
              {
                "prefix": "24",
                "address": "172.16.3.0"
              }
            ]
          },
          "macAddress": "000D3A3AE8A5"
        }
      ]
    }
  },
  "cloud-service": "__ed-sle12sp3byosService.cloudapp.net",
  "tag": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
}

example #4 - list of valid plugin providers

ed-sle12sp3byos:/home/lane/cliapi # cliapi --list-providers
[
  "test",
  "azure"
]

example #5 - list of APIs supported by plugin provider (default provider = azure)

ed-sle12sp3byos:/home/lane/cliapi # cliapi --list-apis
[
  "tag",
  "cloud-service",
  "meta_data"
]

example #6 - an ad-hoc restricted python dictionary syntax query (provider='test')

lane@suse-laptop:~/develop/garage/cliapi> cliapi --query="['meta_data']['compute']['offer']" --provider=test 
"SLES-BYOS"

example #7 - mixed multiple queries with a single CLI call (provider='test')

lane@suse-laptop:~/develop/garage/cliapi> cliapi --location --query="['meta_data']['compute']['offer']" --provider=test 
[
  "westus",
  "SLES-BYOS"
]

About

cliapi ( pronounced calliope ): A Python framework for creating Unix, "getopt()" style CLI scripts composed from an arbitrary set of APIs.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages