Skip to main content

Command-line Interface (CLI)

Installation

Installation and configuration instructions are available here.

Usage

Use the help command to see a list of all available "root" commands and global flags:

signadot help

Each command may have command-specific flags and nested sub-commands, which you can see by running:

signadot help <command>

Examples

Note

The examples here work with v0.2+ of the Signadot CLI. If you're upgrading from v0.1, please note that the sandbox file format and the names of some commands have changed.

Clusters

You can use the cluster add command to begin the process of connecting a Kubernetes cluster to Signadot:

signadot cluster add --name my-cluster

The --name that you specify is only used within Signadot. It's the value you'll pass back in other commands to tell Signadot which Kubernetes cluster you want to work with.

The cluster add command will generate the first auth token for that cluster and provide an example kubectl command to install the cluster token as a Secret.

You can use signadot cluster list to see the names of clusters already registered with Signadot.

You can also create a new auth token for an existing cluster with:

signadot cluster token create --cluster my-cluster

Sandboxes

To create a sandbox, first write a YAML or JSON file containing the name and spec for the sandbox. The available fields within spec are documented in the Sandbox spec reference

For example:

name: my-sandbox
spec:
cluster: my-cluster
description: Testing sandboxes
forks:
- forkOf:
kind: Deployment
namespace: example
name: my-app
customizations:
images:
- image: example.com/my-app:dev-abcdef
env:
- name: EXTRA_ENV
value: foo
defaultRouteGroup: # CLI v0.3.7+ required (see sandbox specification for details)
endpoints:
- name: my-endpoint
target: http://my-app.example.svc:8080

Then submit this sandbox by passing the filename to the sandbox apply command:

signadot sandbox apply -f my-sandbox.yaml

You can use signadot sandbox list to see all existing sandboxes, and signadot sandbox get to see details about a single sandbox.

# List all sandboxes
signadot sandbox list

# Get one sandbox by name
signadot sandbox get my-sandbox

Each of the above commands can also produce meachine-readable output (JSON or YAML). For example:

# List all sandboxes in machine-readable format
signadot sandbox list -o json

# Get one sandbox in machine-readable format
signadot sandbox get my-sandbox -o yaml

You can delete a sandbox either by name, or by pointing at the same file that was used to create it:

# Delete sandbox by name
signadot sandbox delete my-sandbox

# Delete sandbox specified in a file
signadot sandbox delete -f my-sandbox.yaml

Also, the sandbox spec supports automatic deletion with time to live.

Local Workloads

signadot local {connect,disconnect}

Note

The examples here work with v0.5.0+ of the Signadot CLI.

To run Local Workloads within sandboxes, one first connects to the cluster:

% signadot local connect
signadot local connect needs root privileges for:
- updating /etc/hosts with cluster service names
- configuring networking to direct local traffic to the cluster
Password:

signadot local connect has been started ✓
* runtime config: cluster demo, running with root-daemon
✓ Local connection healthy!
* operator version 0.16.0
* port-forward listening at ":59933"
* localnet has been configured
* 45 hosts accessible via /etc/hosts
* sandboxes watcher is running
* Connected Sandboxes:
- No active sandbox

In the event several connections are specified, you will be asked to provide the signadot cluster name of the cluster to which you want to connect:

% signadot local connect
Error: must specify --cluster=... (one of [air signadot-staging])

% signadot local connect --cluster=air
signadot local connect needs root privileges for:
- updating /etc/hosts with cluster service names
- configuring networking to direct local traffic to the cluster
Password:

signadot local connect has been started ✓
...

Once connected, you can run workloads locally which will receive requests from the cluster and, if that workload communicates with other services in the cluster, all of its outbound requests will be directed to the cluster. This is accomplished simply by running signadot sandbox apply using sandbox specs with a local section.

Starting with Signadot CLI v0.6.0, all the applied sandboxes having a local section will be registered along with a machine ID, a hashed unique identifier of the workstation from where the CLI is being run. Once connected, the CLI will continuously run a sandbox discovery service (sandboxes watcher), automatically establishing all the required tunnels for the configured local workloads. Note that this new feature requires the Signadot Operator >= v0.14.1 to be functional, otherwise you will find the following message in the status:

% signadot local status
* runtime config: cluster test, running with root-daemon
✓ Local connection healthy!
* port-forward listening at ":36337"
* localnet has been configured
* 25 hosts accessible via /etc/hosts
* sandboxes watcher is not running ("this feature requires operator >= 0.14.1")
* Connected Sandboxes:
- No active sandbox

With older operator versions, you can still apply sandboxes with local references, but they won't be automatically re-established after disconnecting and connecting back.

To disconnect, run:

% signadot local disconnect

In case you want to remove all the connected sandboxes when disconnecting, run:

% signadot local disconnect --clean-local-sandboxes

signadot local proxy

Note

The examples here work with v0.7.0+ of the Signadot CLI.

signadot local proxy provides the ability to run arbitrary cluster services locally via proxy, similar to Kubernetes port forwarding. In order to run it, one must specify one of:

  • --sandbox <sandbox-name>
  • --routegroup <route-group-name>
  • --cluster <cluster-name>

In the event a Sandbox or RouteGroup is specified, the proxy goes to the associated cluster and will inject the associated routing keys (unless already present in a given request). In the event a cluster is specified, no headers are injected.

With this in hand, signadot local proxy then will proxy remote services to local servers, each specified as

--map <scheme>://<host>:<port>@<host>:<port>

On the right side of the @, we have the local bind address. To the left of the @, we have a URL which is resolved in the remote cluster.

The scheme may be one of http, grpc, or tcp. However, no header injection is performed with tcp.

As an example, consider the case where one would like to run a test against a sandbox called feature-x by hitting the endpoint http://backend.staging.svc:8000. Suppose also the test accepts an environment variable $BACKEND_SERVICE_ADDR.

export BACKEND_SERVICE_ADDR=localhost:8001
signadot local proxy --sandbox feature-x --map http://backend.staging.svc:8000@$BACKEND_SERVICE_ADDR &
pid=$!
# run the test
newman run -env-var backend=$BACKEND_SERVICE_ADDR
kill $pid

RouteGroups

Note

The examples here work with v0.3.7+ of the Signadot CLI.

To create a RouteGroup, first write a YAML or JSON file containing the name and spec. The available fields within spec are documented in the RouteGroup spec reference

For example:

name: my-routegroup
spec:
cluster: my-cluster
description: "route group for testing multiple sandboxes together"
match:
any:
- label:
key: feature
value: new-feature-x-*
endpoints:
- name: frontend-endpoint
target: http://frontend.hotrod.svc:8080

Then submit this routegroup by passing the filename to the routegroup apply command:

signadot routegroup apply -f my-routegroup.yaml

You can use signadot routegroup list to see all existing routegroups, and signadot routegroup get to see details about a single routegroup.

# List all routegroups
signadot routegroup list

# Get one routegroup by name
signadot routegroup get my-routegroup

You can delete a routegroup either by name, or by pointing at the same file that was used to create it:

# Delete routegroup by name
signadot routegroup delete my-routegroup

# Delete routegroup specified in a file
signadot routegroup delete -f my-routegroup.yaml

ResourcePlugins

Note

The examples here work with v0.4.0+ of the Signadot CLI.

To create a ResourcePlugin, first write a YAML or JSON file containing the name and spec. The available fields within spec are documented in the ResourcePlugin spec reference

For example:

name: my-plugin
spec:
runner:
image: ubuntu
create:
- name: say-hello
script: |
#!/usr/bin/env bash
echo hello
delete:
- name: say-goodbye
script: |
#!/usr/bin/env bash
echo good-bye

Then submit this plugin by passing the filename to the resourceplugin apply command:

signadot resourceplugin apply -f my-resourceplugin.yaml

You can use signadot resourceplugin list to see all existing resourceplugins, and signadot resourceplugin get to see details about a single resourceplugin.

# List all resourceplugins
signadot resourceplugin list

# Get one resource plugin by name
signadot resourceplugin get my-plugin

You can delete a resourceplugin either by name, or by pointing at the same file that was used to create it:

# Delete resourceplugin by name
signadot resourceplugin delete my-resourceplugin

# Delete resourceplugin specified in a file
signadot resourceplugin delete -f my-resourceplugin.yaml

Job Runner Groups

Note

The examples here work with v0.8.0+ of the Signadot CLI.

To create a Job Runner Group, first write a YAML or JSON file containing the name and spec. The available fields within spec are documented in the JobRunnerGroup spec reference

For example:

name: my-jrg
spec:
cluster: your-cluster-name
labels:
my-custom-label: foo
env: bar
namespace: signadot
jobTimeout: 1h
image: ubuntu:latest
podTemplate:
metadata:
creationTimestamp: null
spec:
containers:
- image: ubuntu:latest
name: main
resources: {}
scaling:
manual:
desiredPods: 1

Then submit this job runner group by passing the filename to the jrg apply or jobrunnergroup apply command:

signadot jobrunnergroup apply -f my-jobrunnergroup.yaml

You can use signadot jobrunnergroup list to see all existing jobrunnergroups, and signadot jobrunnergroup get to see details about a single jobrunnergroup.

# List all job runner groups
signadot jobrunnergroup list

# Get one job runner group by name
signadot jobrunnergroup get my-jrg

You can delete a jobrunnergroup either by name, or by pointing at the same file that was used to create it:

# Delete job runner group by name
signadot jobrunnergroup delete my-jrg

# Delete job runner group specified in a file
signadot jobrunnergroup delete -f my-jobrunnergroup.yaml

Jobs

Note

The examples here work with v0.8.0+ of the Signadot CLI.

To submit a Job, first write a YAML or JSON file containing the spec. The available fields within spec are documented in the Job spec reference

For example:

spec:
namePrefix: my-job
runnerGroup: my-jrg
script: |
#!/bin/bash

x=1
while [ $x -le 30 ]
do
echo "Welcome $x times (env TEST=$TEST)"
x=$(( $x + 1 ))
sleep 1
done
echo "This is an artifact" > /tmp/my-artifact.txt
echo "We are done!"
uploadArtifact:
- path: /tmp/my-artifact.txt
meta:
format: text
kind: demo

Note

Notice that runnerGroup is set to the name of the JRG in the previous example. A Job runs in the context of its associated JRG.

Then submit this job by passing the filename to the job submit command:

signadot job submit -f my-job.yaml

You can use signadot job list to see all jobs, and signadot job get to see details about a single job.

# List all jobs with only running or queued state
signadot job list

# List all jobs including completed, cancelled states
signadot job list --all

# Get one job runner group by name
signadot job get my-job-[generated_id]

You can cancel a job either by the generated name.

# Delete job by name
signadot job delete my-job-[generated_id]

Artifacts

Note

The examples here work with v0.8.0+ of the Signadot CLI.

To download an artifact linked to a job, first list the available artifacts with job get [NAME], once you know the artifact you would like to download apply the following command.

# Download the stdout of job logs
signadot artifact download --job my-job-[generated_id] @stdout

# Download the stderr of job logs with a custom name (it will not create any unresolved directory)
signadot artifact download --job my-job-[generated_id] @stderr --output job_errors

# Download user/custom artifacts. The output will be the basename only (my-artifact.txt)
signadot artifact download --job my-job-[generated_id] /tmp/my-artifact.txt

Logs

Note

The examples here work with v0.8.0+ of the Signadot CLI.

To see jobs logs we can use logs, for example:

# See stdout logs of job
signadot log --job my-job-[generated_id]

# By default is stdout, but we can see stderr too
signadot log --job my-job-[generated_id] --stream stderr

YAML/JSON Templates

Note

The examples here work with v0.4.0+ of the Signadot CLI.

Sandboxes, RouteGroups, and ResourcePlugins support yaml and json templating which allows substituting values provided in the spec files with values specified on the command line or in other files.

Templating helps with CI automation where some values come from the environment and it also helps with spec organisation, such as allowing a script to be edited in a file with extension .sh while having it automatically embedded into the spec.

A template file is a yaml file with template directives in strings. A template directive takes the form @{<value-spec>}.

A value spec specifies something to put in place of the template directive, which may be a variable reference or an embedding:

<value-spec> ::= <variable-ref> | <embedding>

Variables

A variable in a template directive takes the form @{<variable>} and can occur in any string literal. For example

name: "@{dev}-@{team}-feature"
city: "@{city}"

A variable must match the regular expression ^[a-zA-Z][a-zA-Z0-9._-]*$.

Variable values are then supplied on the command line in the form --set <variable>=<value>. For example

signadot sandbox apply -f SANDBOX_FILE --set dev=jane --set team=plumbers

If a variable reference occurs in a sandbox file and no value for that variable is provided, then an error is flagged and the operation is aborted.

Embeddings

An embedding takes the form @{embed: <file>}. <file> is a path to another file. Relative paths are interpreted relative to the directory in which the template file lives, or relative to the current working directory if the template file is stdin.

The contents of <file> are then placed in the string in the resulting document. For example, with template

name: "@{embed: name.txt}"

and if name.txt contains

Jane
Plumb

Then the expanded file would be

name: "Jane\nPlumb"

Perhaps rendered to yaml as

name: |
Jane
Plumb

Expansion Encodings

Both variable references and embeddings can be expanded in a few different ways.

By default, the value of a variable or the contents of a file are simply placed in the string in which the directive occurs. This replacement occurs by means of operations on the yaml/json string in which the directive occurs, rather than by means of operations on the containing document, so there is no problem with quoting or indentation. This expansion encoding is called a raw expansion encoding and it is the default.

Alternative expansion encodings can be specified for variables or embeddings by appending [<encoding>] to the variable name or the operation. raw, yaml, and binary expansion encodings are supported.

Expansion encodings other than raw cannot occur properly within a string, nor can one have multiple template directives in one string when one of them is a non-raw expansion encoding.

Below are examples of the input and output of raw, yaml, and binary expansion encodings.

For example:

# illegal template
name: " @{embed[yaml]: file.yaml}"
# ^ (contains a space outside the directive)
---
# ok embedding, nothing outside the directive
name: "@{embed[yaml]: file.yaml}"

raw expansion encoding

# both dev and team are expanded with the raw expansion encoding,
# which is just string interpolation.
name: "@{dev[raw]}-@{team}"
---
# output
name: "jane-plumbers"

yaml expansion encoding

# the value of the field 'podTemplate' will be the full yaml (not a string)
# defined by the contents of pod-template.yaml
podTemplate: "@{embed[yaml]: pod-template.yaml}"
---
# output
podTemplate:
spec:
containers:

raw expansion encoding of yaml

# the value of the field 'podTemplateString' will be a string containing
# yaml defined by the contents of pod-template.yaml
podTemplateString: "@{embed[raw]: pod-template.yaml}"
---
# output
podTemplateString: |
spec:
containers:

yaml expansion encoding of a port number

# with --set port=123, port will be a yaml number
port: "@{port[yaml]}"
---
# output
port: 123

binary expansion encoding

# with --set data="$(dd if=/dev/urandom count=1)"
data: "@{data[binary]}"
---
# output
data: "mj3cLyX8B5yiL0S9jOm2WKapDD8a56WyJW0nyg7ufiL8w8KZ4mEM0z7eCnBAlqBuDpJPjIwy7Am3X5yQSv7MHZK0Ui+QRCL0D53blHAcFS8WV9bZSRkTBtBAyaeF0tH0HLRKPyXuJPDoZC1NmQIPdsW/el5gmf9nXjtYegjd8oNiN4bayDULXEOjeYkKNyVGGCvCn6TAQ3UeCmfckIcad7Ek1Vvm4EETDF4OFAL6hsYBujeZXdjn/vIquWtMWCq8iVPlLJQ0sMyzCCsNJvx170RSNF6/xh7zeI+RsfFBD/b71Kg0GdFz8zSOSSxsRZqAZBZGdUmYmJvQOyhYOq5Z9sumwSnqgBHjP3gnUaVS4jyaQuhcJJoLlTwHTd6X0WLPknctDGZWCLMd10XVLvKJoPEL99GDhWKyDpXwB2PNNWtZBa8UGrr6YYRsrttlgFkKd/tcSc/zYc8rjsdWARBPSvntSAzKPy459niet+OtpW8SpBuykmT60OZdRUYkntdEvmn7YP88e4aQxT3hZJx+qQGaJUT00w/MdtPL9JUZ63LVKvyDzCf3FGEtDipZZemveNQmyzTg/3mAIBHljS7QZdzeZtZ4ITh+Nxjm30I/Hedkd1qrPBZtoTqMgyVtXYCU+HVLMbiDLUj/9Jc0XL8VHwQoaCJ9M/V+ORZYSOdlDYY="

CLI Config

The CLI reads configuration from a file stored at $HOME/.signadot/config.yaml. This location can be overridden with the --config flag. This file contains information for using the CLI as an interface to Signadot API and also for running Local Sandboxes. Some parameters in this file can also be set via environment variables. See the config file reference.