The xosapi
library is a python library that may be used to interact with the XOS core. The library connects to the core, automatically downloads and compiles protobufs, and then provides high-level ORM abstractions of the models to the caller.
This library is used internally by the synchronizer framework. If you are writing a synchronizer, then it's advised that you work with the synchronizer framework rather than working with this library. This library may be useful for people who are developing python components that are not synchronizers.
The following pip packages must be installed
sudo pip install python-consul twisted simplejson xosapi
Next we need to create the necessary certificates. The gRPC API used between the client and the core uses SSL and the certificate authority must be specified. Below is an example:
Note: This file may be dependent on the particular xos-core installation. You can find the correct file at
helm-charts/xos-core/pki/xos-CA.pem
.
cat > local_certs.crt <<EOF -----BEGIN CERTIFICATE----- MIID1jCCAr6gAwIBAgIJAIWmwLL7nulVMA0GCSqGSIb3DQEBCwUAMHgxCzAJBgNV BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRMwEQYDVQQHDApNZW5sbyBQYXJr MQwwCgYDVQQKDANPTkYxFTATBgNVBAsMDFRlc3RpbmcgT25seTEaMBgGA1UEAwwR Q09SRCBUZXN0IFJvb3QgQ0EwHhcNMTgxMjE0MTgyNTE5WhcNMTkxMjE1MTgyNTE5 WjB4MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTETMBEGA1UEBwwK TWVubG8gUGFyazEMMAoGA1UECgwDT05GMRUwEwYDVQQLDAxUZXN0aW5nIE9ubHkx GjAYBgNVBAMMEUNPUkQgVGVzdCBSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOC AQ8AMIIBCgKCAQEAokxdd5vyy83NPQYQK/wsz6VLrunv/3FNSbUv9dC4MC5zZyMd oxrYCfM38rypbrB5PIVlFdndfDzoYORmlC9gxJnFUmAztyU2JIZrcxk1sQ+lBWj+ Bytwh1TKT0OSfEWjB/LV1FGLAuspJGBn2T0E35bGhhzOL8Cgm0e8akeAfs2s9akO Xcj+4osnAkXynKl+HhCTBkcrmg1YsTB3+0ug0vM5xuHMU5tVVKpn9DinZ3enuHle ICyiMF8JyEibjGl0cjnGhw1lPzT7lsjxuoZhr3NaIlI/zUXBDTJbJ6T6gUa1Npa/ lurbEn/9pUMQcUIOnIfzbmzVjPmd0AL9fEcAlQIDAQABo2MwYTAdBgNVHQ4EFgQU xYhJSu6N6DF7C39G1hAvF7JOC54wHwYDVR0jBBgwFoAUxYhJSu6N6DF7C39G1hAv F7JOC54wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcN AQELBQADggEBAJc7J+ZVhp7ti+YN2Smv/jtz79NyF1J6Eb3M/BC/A5Eo8Cp2hklC NI00+con2Dvvbmj6lOgKXPL6C8LgxiZ5gVDtSvK8zuoIzkIDod4IovxcwLrvlIH4 BpG6Sm1d7EbwAHKFGc0qvVdRN48P884KnzW27eLtsdqrkUPuqz9Ph1JJmAzy3v5p pKtL6zfn706pcad5NuAcoz0782T+wszHmBv0SBboLdo9NyUciJBQCjIDaSEOpqze upzRp50aDMq3nxd7yZ3VGA52ECNQ4gWgWAHomDS22RdCHsedbUofnrl6TW88j+Aa +4AJR9CmhoP1CnKHb5wVCBScw9T8gu3aLe0= -----END CERTIFICATE----- EOF
Create a configuration file that at a minimum configures logging:
cat > logging_config.yaml <<EOF logging: version: 1 handlers: console: class: logging.StreamHandler EOF
The DNS name xos-core
must map to an IP address. If you're working inside a container, then the name may already map correctly. If you're not working in a container then you may have to ensure this name maps yourself. One way to do that is to do so is by adding an entry to /etc/hosts/
:
echo "<my-core-ip-address> xos-core" | sudo tee -a /etc/hosts
The following directories must be writable:
sudo mkdir -p /var/run/xosapi sudo chmod a+rwx /var/run/xosapi
Now that everything is prepared, we can launch python and try to initialize and connect the API.
import sys import functools from xosconfig import Config from twisted.internet import reactor Config.init("logging_config.yaml") from xosapi.xos_grpc_client import SecureClient def connected(client): print "Connected!" print "Stopping!" reactor.stop() client = SecureClient(endpoint="xos-core:30010", username="admin@opencord.org", password="letmein", cacert="local_certs.crt") client.set_reconnect_callback(functools.partial(connected, client)) client.start() reactor.run()
If all works as it should, the above should print:
Connected! Stopping!
The connected client and generated ORM are available inside of the connected()
callback. Let's perform a few operations between the Connected!
and Stopping!
lines. Replace the connected()
function above with the following:
def connected(client): print "Connected!" orm = client.xos_orm # List current sites print "Current Sites:", orm.Site.objects.all() # Create a new site newSite = orm.Site(name="newsite", login_base="newsite", abbreviated_name="newsite") newSite.save() print "Created newsite with id:", newSite.id # Filter site someSites = orm.Site.objects.filter(name="newsite") print "Filtered sites with name=newsite and found:", someSites # Delete a site newSite.delete() print "Stopping!" reactor.stop()
This output of the above should be the following:
Connected! Current Sites: [<Site: mysite>] 2019-07-23T15:17:33.646318Z [debug ] save(): is new classname=Site syncstep=None Created newsite with id: 2 Filtered sites with name=newsite and found: [<Site: newsite>] Stopping!
In the above example, we have done everything from inside the connected()
callback, though this is not necessarily a requirement. You could for example save the client
argument to connected()
to a global, then call reactor.stop()
to terminate reactor. The reactor.run()
statement will complete and python will execute and subsequent statements. You may continue to use the client that you saved to the global. reactor
is only required during the initial setup of the client. This particular pattern of saving data to globals and then exiting reactor is how the xossynchronizer
library is implemented, as synchronizers do not use reactor
.