Aerie-CLI provides a command-line interface and user-extendable Python API for interacting with an instance of Aerie.
Note: this project is an informal CLI and is not maintained by the MPSA Aerie team.
This short procedure will get you up and running with the basics of the CLI.
-
Install/update to Python >= 3.6
-
Install Aerie-CLI from Github:
python3 -m pip install git+https://github.com/NASA-AMMOS/aerie-cli.git@main
-
Configure access to an Aerie host
-
If you've been provided a Configuration JSON, reference that file
-
If you don't have already have a Configuration JSON, copy the following to a JSON file for a local Aerie deployment (replacing the username with your own):
[ { "name": "localhost", "graphql_url": "http://localhost:8080/v1/graphql", "gateway_url": "http://localhost:9000", "username": "my_username" } ]
-
Load either your given configuration(s) or the configuration above into Aerie-CLI:
aerie-cli configurations load -i JSON_FILE
-
-
Activate a configuration to start a session with an Aerie host:
➜ aerie-cli activate 1) localhost Select an option: 1
-
Try out a command to list the plans in Aerie:
aerie-cli plans list
-
Use the
--help
flag on any command to see available subcommands and parameters. For example:aerie-cli --help ... aerie-cli plans --help ... aerie-cli plans download --help
Aerie-CLI uses configurations to define different Aerie hosts. Define configurations by either loading JSON configurations or manually via the CLI. Configurations persist on a per-user basis and may be shared between installations.
If you have a file of configurations to load, you can use the configurations load
command:
aerie-cli configurations load -i JSON_FILE
You can view the configurations you've loaded with the configurations list
command:
➜ aerie-cli configurations list
Configuration file location: /Users/<username>/Library/Application Support/aerie_cli/config.json
Aerie Host Configurations
┏━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━┓
┃ Host Name ┃ GraphQL API URL ┃ Aerie Gateway URL ┃ Username ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━┩
│ localhost │ http://localhost:8080/v1/graphql │ http://localhost:9000 │ │
└───────────┴──────────────────────────────────┴───────────────────────┴──────────┘
If you haven't been provided a JSON configuration for a host, you can create a configuration by running aerie-cli configurations create
and follow the prompts.
Each configuration is stored as JSON object list entry in the configuration file provided with the configurations list
command. The full contents of a host configuration are:
Field | Description | Required |
---|---|---|
name |
User-facing name of the host | Yes |
graphql_url |
URL of the Aerie instance's Hasura GraphQL API | Yes |
gateway_url |
URL of the Aerie instance's Gateway | Yes |
username |
Username for authentication with Aerie | No |
external_auth |
Specification for external authentication required to reach an Aerie instance. See Configuring for External Authentication for details | No |
Aerie-CLI maintains a persistent "session" with an Aerie instance so multiple commands can run without needing to re-authenticate. To start a session, use the activate
command:
➜ aerie-cli activate
1) localhost
...
Select an option: 1
Aerie uses "roles" to adjust what a client is permitted to do. To view the active configuration name and current role, use the status
command:
➜ aerie-cli status
Active configuration: localhost
Active role: viewer
The default role is configured by Aerie. To change the selected role for the active Aerie-CLI session, use the role
command:
➜ aerie-cli role
Active Role: viewer
1) aerie_admin
2) user
3) viewer
Select an option: 1
Changed role to: aerie_admin
At any time, the active session can be closed with the deactivate
command.
Commands are the main functions available via the CLI and are broken down into several levels. For example, the top-level plans
command has sub-commands for list
, upload
, simulate
, and more. From any command or sub-command, use the --help
flag to learn about what commands are available or what arguments are required.
Help at script level:
aerie-cli --help
Help at command level:
aerie-cli plans --help
Help at sub-command level:
aerie-cli plans download --help
If a command is invoked without the necessary arugments, interactive prompts are provided:
➜ aerie-cli plans download
Id: 42
Output: sample-output.json
Alternatively, arguments can be provided using flags:
➜ aerie-cli plans download --id 42 --output sample-output.json
Aerie-CLI configurations include a mechanism to authenticate against an external authentication service which may require additional credentials as cookies for accessing Aerie. Aerie-CLI will issue a post request with given JSON data to a provided authentication endpoint and persist any returned cookies in a browser-like manner for the remainder of the Aerie-CLI session.
An external authentication service is configured using the key external_auth
in the JSON configuration file as follows:
{
"name": "my_host",
"graphql_url": "https://hostname/v1/graphql",
"gateway_url": "https://hostname/gateway",
"username": "my_username",
"external_auth": {
"auth_url": "https://auth_service/route",
"static_post_vars": {
"username": "my_username"
},
"secret_post_vars": [
"password"
]
}
}
Here, static_post_vars
is an object containing fixed values to include in the post request payload such as usernames and other persistent, non-sensitive fields. secret_post_vars
is a list of keys for credentials which may be sensitive or time-varying. The user will be prompted to provide the "secret" values using hidden entry in the terminal when activating a session with external authentication.
In this example, the user would be prompted to enter a value for "password" and, assuming they enter "my_password", the post request JSON would include the following:
{
"username": "my_username",
"password": "my_password"
}
In some cases, an admin secret may be used to permit otherwise prohibited requests through Hasura (the software behind the Aerie API). When running a command, the user may add the --hasura-admin-secret
flag after the aerie-cli
command to use these elevated privileges for the following command.
Instead of using the CLI for interactive use cases, the underlying classes and methods behind Aerie-CLI can be invoked directly in Python scripts.
The key constructs are:
aerie_cli.aerie_host.AerieHost
: An abstraction for an Aerie Host, including methods for authentication and issuing requests to the Aerie API.aerie_cli.aerie_client.AerieClient
: A class containing common requests and reusable logic to interact with data in Aerie.
The following example defines an AerieHost
using the necessary URLs, authenticates with a command-line prompt for the user's password, and issues a simple request using one of the built-in requests.
from aerie_cli.aerie_client import AerieClient
from aerie_cli.aerie_host import AerieHost
from getpass import getpass
# These URLs define the Aerie host
GRAPHQL_URL = "http://myhostname:8080/v1/graphql"
GATEWAY_URL = "http://myhostname:9000"
# User credentials. The password may be omitted on Aerie instances with authentication disabled
USERNAME = "myusername"
PASSWORD = getpass(prompt='Password: ')
# Define the Aerie host and provide user credentials
aerie_host = AerieHost(GRAPHQL_URL, GATEWAY_URL)
aerie_host.authenticate(USERNAME, PASSWORD)
# AerieClient takes in a host and returns an object to issue requests to that host
client = AerieClient(aerie_host)
# Simple example of a request to get an activity plan using the plan ID
plan = client.get_activity_plan_by_id(42)
print(plan.name)
Look through the available methods in the provided AerieClient
class to find ones that suit your needs.
If you need to write a custom query, you can extend the AerieClient
class and add your own method. Access the Aerie host using the aerie_host
property. For example:
# ...
class MyCustomAerieClient(AerieClient):
def get_plan_id_by_name(self, plan_name: str) -> int:
my_query = """
query GetPlanIdByName($plan_name: String!) {
plan(where: { name: { _eq: $plan_name } }) {
id
}
}
"""
# Pass variables for the query as keyword arguments
resp = self.aerie_host.post_to_graphql(
my_query,
plan_name=plan_name
)
return resp[0]["id"]
Now, you can use your custom method like any other:
# ...
client = MyCustomAerieClient(aerie_host)
plan_id = client.get_plan_id_by_name("my-plan-name")
print(plan_id)
If your application will be run by a user who may also be using the CLI, you may reduce the amount of code required to configure an Aerie host and instead just use the active session. Aerie-CLI provides a utility to retrieve an AerieClient
instance from the active CLI session:
from aerie_cli.utils.sessions import get_active_session_client
# client is an instance of `AerieClient`
client = get_active_session_client()
# Issue requests like normal
plan = client.get_activity_plan_by_id(...)
If you have needs for authentication (e.g., a custom token system) that aren't provided by Aerie-CLI, you can use any features supported by the Python requests
module's Session
class. Instantiate a session object, manipulate/add headers/cookies/SSL certificates/etc. as necessary, and use to instantiate an AerieHostSession
:
# ...
from requests import Session
my_custom_requests_session = Session()
# Manipulate as necessary
# ...
aerie_host = AerieHost(
GRAPHQL_URL,
GATEWAY_URL,
session=my_custom_requests_session
)
aerie_host.authenticate(...)
client = AerieClient(aerie_host)
# Use client as normal
The recommended develper installation method is in a virutual environment with an editatable install via Pip.
See this primer or virtual environments to get set up. A quick and easy method is using Python's native venv
package from the root of the Aerie-CLI repo:
python3 -m venv venv
source venv/bin/activate
Then, install Aerie-CLI in editable mode via Pip:
python3 -m pip install -e .
Now, your installation of Aerie-CLI will update as you make changes to the source code.
Dependencies are currently managed via Poetry. For more information on dependency and project management, see the poetry
docs.
Aerie-CLI has unit tests and integration tests built with the pytest library.
Unit tests can be run anytime and reference local test files. test_aerie_client.py
is where unit tests are added to exercise particular methods of the AerieClient
class using mocked Aerie API responses.
Run the unit tests using pytest
from the tests/unit_tests
directory:
cd tests
python3 -m pytest .
A separate suite of tests is designed to validate CLI functionality against a local instance of Aerie. See the integration testing documentation for details.
The integration tests are based on Typer
testing documentation found here.
Aerie-CLI generally follows the gitflow workflow model for managing releases:
- Features are merged to the
develop
branch. - Release branches are made from develop and merge in
main
for testing. - Releases are made from the tip of the
main
branch. - Hotfix branches can be made from
main
to resolve bugs without needing to incorporate new features.
Version numbers are managed using semantic versioning in pyproject.toml
:
- The version tag on
develop
is fixed at0.0.0-dev0
- Release versions are incremented on release branches before being merged to main.
The full workflow for releasing a new version of Aerie-CLI:
- Make a release branch from
develop
- Merge
main
into the release branch - Commit a version increment in
pyproject.toml
- Open a PR to merge the release branch into
main
and verify CI passes - Merge the PR and tag a release on
main