rerobots Python client library¶
This is a command-line interface and Python client library for the rerobots API. The corresponding source code repository is hosted at https://github.com/rerobots/py
Introduction¶
Summary¶
command-line interface and Python client library for the rerobots API
Releases are available at PyPI.
Documentation of the current release is at https://rerobots-py.readthedocs.io/ or can be built from sources as described below.
Getting started¶
To install the current release, try
pip install rerobots
Besides installing the rerobots
Python package, this will add the command
rerobots
to your shell. To get a brief help message, try
rerobots help
Most interesting interactions with rerobots require an API token, which can be
provided through the environment variable REROBOTS_API_TOKEN
or via the
command-line switch -t
.
For additional features, such as getting images from cameras as NumPy arrays,
pip install rerobots[extra]
Testing and development¶
All tests are in the directory tests/
. If you have the rerobots
package
installed, then you can
make check
to run static analysis and tests that do not require a rerobots API token. Recent results on Travis CI are available at https://travis-ci.org/rerobots/py
Several other commands are available to run subsets of tests or create coverage reports. For example, to run tests that do not touch production servers:
make checklocal
and to measure code coverage: make checklocalcover
. To view the coverage
report, direct your Web browser at tests/cover/index.html
To build the User’s Guide:
make doc
and direct your Web browser at doc/build/index.html
There are extra tests (not run during make check
) that interact with
production servers in a way that requires an API token and that may cause
billing against the associated user account. These tests are only of interest if
you plan to contribute internal changes to this Python package.
Participating¶
All participation must follow our code of conduct, elaborated in the file CODE_OF_CONDUCT.md in the same directory as this README.
Reporting errors, requesting features¶
Please first check for prior reports that are similar or related in the issue tracker at https://github.com/rerobots/py/issues If your observations are indeed new, please open a new issue
Reports of security flaws are given the highest priority and should be sent to <security@rerobots.net>, optionally encrypted with the public key available at https://rerobots.net/contact Please do so before opening a public issue to allow us an opportunity to find a fix.
Contributing changes or new code¶
Contributions are welcome! There is no formal declaration of code style. Just try to follow the style and structure currently in the repository.
Contributors, who are not rerobots employees, must agree to the Developer
Certificate of Origin. Your agreement is
indicated explicitly in commits by adding a Signed-off-by line with your real
name. (This can be done automatically using git commit --signoff
.)
License¶
This is free software, released under the Apache License, Version 2.0. You may obtain a copy of the License at https://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.
Tutorial¶
This tutorial demonstrates how to work with client code. For the Command-line interface, there is a different tutorial.
Begin by getting an API token (from
the Web UI). There are several ways to make it
available to the client code. In this example, we assume that it is saved to a
file named jwt.txt
. Instantiate APIClient
with this token:
import rerobots.api
with open('jwt.txt') as fp:
apic = rerobots.api.APIClient(api_token=fp.read())
Get a list of all workspace deployments that involve “misty” (i.e., robots by Misty Robotics):
apic.get_wdeployments(query='misty')
yielding a list like
[{'id': '2c0873b5-1da1-46e6-9658-c40379774edf', 'type': 'fixed_misty2'},
{'id': '3a65acd4-4aef-4ffc-b7f9-d50e48fc5541', 'type': 'basic_misty2fieldtrial'}]
The list you receive might be different, depending on availability of workspace
deployments. To get more information about one of them, call
get_wdeployment_info()
, for example:
apic.get_wdeployment_info('3a65acd4-4aef-4ffc-b7f9-d50e48fc5541')
which will return a Python dict
like
{'id': '3a65acd4-4aef-4ffc-b7f9-d50e48fc5541',
'type': 'basic_misty2fieldtrial',
'type_version': 1,
'supported_addons': ['cam', 'mistyproxy', 'drive'],
'desc': '',
'region': 'us:cali',
'icounter': 886,
'created': '2019-07-28 23:26:16.983048',
'queuelen': 0}
Notice that the field supported_addons
includes cam
. Later in this
tutorial, the cam
add-on is used to get images from cameras in the
workspace.
The Instance class can be used to instantiate from this workspace deployment:
rri = rerobots.Instance(wdeployment_id='3a65acd4-4aef-4ffc-b7f9-d50e48fc5541', apic=apic)
Then, methods on rri
will affect the instance just created. For example, to
get the status of the instance, call rri.get_status()
, which usually begins
with 'INIT'
(i.e., initializing). The instance is ready for action when
rri.get_status() == 'READY'
. For more information about it, call
rri.get_details()
to get a Python dict
like
{'type': 'basic_misty2fieldtrial',
'region': 'us:cali',
'starttime': '2020-05-23 02:12:16.984534',
'status': 'READY',
'conn': {
'type': 'sshtun',
'ipv4': '147.75.70.51',
'port': 2210,
'hostkeys': ['ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBOBfAaj/HSSl7oJZ+CXnzxFsXnGQZjBh1Djdm8s7V1fdgdiyJn0JrBxzt0pSdcy50JZW+9qc1Msl34YXUjn0mwU= root@newc247']}}
Notice that the connection type is sshtun
and that the above host keys
should be expected from hosts in the instance.
Recall from earlier in this tutorial that the cam
add-on is supported by the
workspace. Activate it by calling
rri.activate_addon_cam()
and waiting until rri.status_addon_cam()
indicates that it is ready. In
practice, activation is completed within several seconds. Then, use
get_snapshot_cam() to get an image and save it
in a NumPy ndarray, and display it with Matplotlib:
import matplotlib.pyplot as plt
import numpy as np
res = rri.get_snapshot_cam(dformat='ndarray')
plt.imshow(res['data'])
plt.show()
The resulting figure should open in a separate window.
Though not as powerful as dedicated ssh
command-line programs, the
Instance class provides methods for basic
operations over SSH. To begin, start an ssh client:
rri.start_sshclient()
Then, arbitrary commands can be executed on the host in the instance via
exec_ssh
. For example,
rri.exec_ssh('pwd')
will return the default path from which commands are executed. Files can be
uploaded and downloaded using put_file
,
and get_file
, respectively. For
example, to download the file /etc/hosts
from the remote host:
rri.get_file('/etc/hosts', 'hosts')
Finally, to stop using the instance and delete your data from it,
rri.terminate()
Command-line interface¶
Summary¶
The command-line interface (CLI) is self-documenting. To begin, try:
rerobots help
which will result in a message similar to the following
usage: rerobots [-h] [-V] [-t FILE]
{info,isready,addon-cam,addon-mistyproxy,addon-drive,list,search,wdinfo,launch,terminate,version,help}
...
rerobots API command-line client
positional arguments:
{info,isready,addon-cam,addon-mistyproxy,addon-drive,list,search,wdinfo,launch,terminate,version,help}
info print summary about instance.
isready indicate whether instance is ready with exit code.
addon-cam get image via add-on `cam`
addon-mistyproxy get proxy URL via add-on `mistyproxy`
addon-drive send motion commands via add-on `drive`
list list all instances owned by this user.
search search for matching deployments. empty query implies
show all existing workspace deployments.
wdinfo print summary about workspace deployment.
launch launch instance from specified workspace deployment or
type. if none is specified, then randomly select from
those available.
terminate terminate instance.
version print version number and exit.
help print this help message and exit
optional arguments:
-h, --help print this help message and exit
-V, --version print version number and exit.
-t FILE, --jwt FILE plaintext file containing API token; with this flag,
the REROBOTS_API_TOKEN environment variable is
ignored.
Call help
to learn more about commands, e.g., rerobots help info
to
learn usage of rerobots info
.
To use an API token, assign it to the
environment variable REROBOTS_API_TOKEN
, or give it through a file named in
the command-line switch -t
.
Example¶
The following video demonstrates how to search for types of workspaces, request an instance, and finally terminate it. The same example is also presented below in text.
Before beginning, get an API token (from
the Web UI). In this example, we assume that it
is saved to a file named jwt.txt
.
Search for workspace deployments:
$ rerobots search misty
2c0873b5-1da1-46e6-9658-c40379774edf fixed_misty2
Get more information about one of them:
$ rerobots wdinfo 2c0873b5-1da1-46e6-9658-c40379774edf
{
"id": "2c0873b5-1da1-46e6-9658-c40379774edf",
"type": "fixed_misty2",
"type_version": 1,
"supported_addons": [
"cam",
"mistyproxy"
],
"desc": "",
"region": "us:cali",
"icounter": 641,
"created": "2019-11-18 22:23:57.433893",
"queuelen": 0
}
Notice that queuelen = 0
, i.e., this workspace deployment is available, and
requests to instantiate from it now are likely to succeed. To do so,
$ rerobots launch 2c0873b5-1da1-46e6-9658-c40379774edf
f7856ad4-a9d7-43f5-8420-7073d10bceec
which will result in a secret key being written locally to the file key.pem
.
This key should be used for ssh connections, e.g., with commands of the form
ssh -i key.pem
. Get information about the new instance:
$ rerobots info f7856ad4-a9d7-43f5-8420-7073d10bceec
{
"id": "f7856ad4-a9d7-43f5-8420-7073d10bceec",
"deployment": "2c0873b5-1da1-46e6-9658-c40379774edf",
"type": "fixed_misty2",
"region": "us:cali",
"starttime": "2020-05-23 02:05:20.311535",
"rootuser": "scott",
"fwd": {
"ipv4": "147.75.70.51",
"port": 2210
},
"hostkeys": [
"ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBPd5tTJLAksiu3uTbGwkBKXFb00XyTPeef6tn/0AMFiRpomU5bArpJnT3SZKhN3kkdT3HvTQiN5/dexOCFWNGUE= root@newc59"
],
"status": "READY"
}
Finally, terminate the instance:
$ rerobots terminate f7856ad4-a9d7-43f5-8420-7073d10bceec
API client objects¶
API client objects provide direct access to the rerobots API with several useful features like mapping returned data into other types.
Example¶
import rerobots.api
apic = rerobots.api.APIClient()
wdeployments = apic.get_wdeployments()
print(apic.get_wdeployment_info(wdeployments[0]['id']))
Create a new client object¶
-
class
rerobots.api.
APIClient
(api_token=None, headers=None, ignore_env=False, base_uri=None, verify=True)¶ Instantiate API client.
api_token is some auth token obtained from https://rerobots.net/tokens In general this token has limited scope and might not be sufficient for some actions that this API client will try to do, leading to the exception WrongAuthToken.
headers is a dictionary of headers to add to every request made by this client object. This is only of interest in special use-cases.
ignore_env determines whether configuration data should be obtained from the process environment variable REROBOTS_API_TOKEN. Default (ignore_env=False) behavior is to try REROBOTS_API_TOKEN if api_token is not given.
base_uri is the string prefix used to create API requests. In general the default value works, but special cases might motivate changing this, e.g., to use an unofficial proxy.
verify determines whether the TLS certificates of the server are checked. Except possibly during testing, this should not be False.
Workspace deployments¶
-
APIClient.
get_wdeployments
(query=None, maxlen=None, types=None, page=None, max_per_page=None)¶ Get list of workspace deployments.
types, if given, should be a list of workspace types (str). The significance of parameters is described in the HTTP-based API documentation.
The parameters page and max_per_page can be used for pagination, which restricts the maximum number of items in the list of instances returned in any one response. Cf. documentation of the HTTP API.
-
APIClient.
get_wdeployment_info
(wdeployment_id)¶ Get details about a workspace deployment.
Instance creation and management¶
APIClient
objects provide methods for working with instances. All operations
are associated with an API token.
Note that classes presented in Workspace instances abstract some of the methods of
APIClient
and provide combined operations, e.g., copying a file to an
instance via ssh.
-
APIClient.
get_instances
(include_terminated=False, page=None, max_per_page=None)¶ Get list of your instances.
The parameters page and max_per_page can be used for pagination, which restricts the maximum number of items in the list of instances returned in any one response. Cf. documentation of the HTTP API.
-
APIClient.
get_instance_info
(instance_id)¶ Get details about a workspace instance.
This operation requires sufficient permissions by the requesting user.
-
APIClient.
request_instance
(type_or_wdeployment_id, sshkey=None, vpn=False, reserve=False, event_url=None, duration=None)¶ Request new workspace instance.
If given, sshkey is the public key of the key pair with which the user can sign-in to the instance. Otherwise (default), a key pair is automatically generated.
If reserve=True, then create a reservation if the workspace deployment is not available at the time of this request.
-
APIClient.
get_vpn_newclient
(instance_id)¶ Create new OpenVPN client.
-
APIClient.
terminate_instance
(instance_id)¶ Terminate a workspace instance.
add-on: cam¶
The cam
add-on provides access to cameras in the workspace through the
rerobots API.
-
APIClient.
get_snapshot_cam
(instance_id, camera_id=0, coding=None, dformat=None)¶ Get image from camera via cam add-on.
If coding=None (default), then returned data are not encoded. The only coding supported is base64, which can be obtained with coding=’base64’.
If dformat=None (default), then the image format is whatever the rerobots API provided. Currently, this can be ‘jpeg’ or ‘ndarray’ (i.e., ndarray type of NumPy).
Note that some coding and format combinations are not compatible. In particular, if dformat=’ndarray’, then coding must be None.
add-on: mistyproxy¶
The mistyproxy
add-on provides proxies for the HTTP REST and WebSocket APIs
of Misty robots.
-
APIClient.
activate_addon_mistyproxy
(instance_id)¶ Activate mistyproxy add-on.
Note that this add-on is unique to workspaces that involve Misty robots, e.g., https://help.rerobots.net/workspaces/fixed_misty2fieldtrial.html
When it is ready, proxy URLs can be obtained via status_addon_mistyproxy().
-
APIClient.
status_addon_mistyproxy
(instance_id)¶ Get status of mistyproxy add-on for this instance.
The response includes proxy URLs if any are defined.
-
APIClient.
deactivate_addon_mistyproxy
(instance_id)¶ Deactivate mistyproxy add-on.
Note that a cycle of deactivate-activate of the mistyproxy add-on will create new proxy URLs.
Note that calling this is not required if the workspace instance will be terminated.
Workspace instances¶
Classes presented in this section have methods for working with instances. They
are built on the rerobots API, but some methods do not correspond directly to
rerobots API calls. In practice, Instance
will provide everything needed for
working with a single workspace instance, without need for raw calls from
API client objects.
Example¶
import rerobots
inst = rerobots.Instance(['fixed_misty2'])
print(inst.get_status())
Instance class¶
-
class
rerobots.
Instance
(workspace_types=None, wdeployment_id=None, instance_id=None, api_token=None, headers=None, apic=None)¶ client for a workspace instance
At least one of workspace_types or wdeployment_id must be given. If both are provided (not None), consistency is checked: the type of the workspace deployment of the given identifier is compared with the given type. If they differ, no instance is created, and ValueError is raised.
If instance_id is given, then attempt to attach this class to an existing instance. In this case, neither workspace_types or wdeployment_id is required. If they are provided, then consistency is checked.
The optional parameter apic is an instance of APIClient. If it is not given, then an APIClient object is instantiated internally from the parameters api_token etc., corresponding to parameters APIClient of the same name.
-
exec_ssh
(command, timeout=None, get_files=False)¶ Execute command via SSH.
https://docs.paramiko.org/en/2.4/api/client.html#paramiko.client.SSHClient.exec_command
If get_files=True, then return files of stdin, stdout, and stderr.
-
get_file
(remotepath, localpath)¶ Get file from remote host.
For the general case, the underlying Paramiko SFTP object is available from sftp_client().
-
put_file
(localpath, remotepath)¶ Put local file onto remote host.
For the general case, the underlying Paramiko SFTP object is available from sftp_client().
-
sftp_client
()¶ Get Paramiko SFTP client.
Note that methods put_file() and get_file() are small wrappers to put() and get() of this Paramiko class.
Read about it at https://docs.paramiko.org/en/2.4/api/sftp.html
-
start_sshclient
()¶ Create SSH client to instance.
This method is a prerequisite to exec_ssh(), which executes remote terminal commands.
-