SEBA-800 Document usage of xosapi library

Change-Id: Id6dbd7fb1b6f068ea537a16ba7f53e12f1ad6e3d
diff --git a/docs/SUMMARY.md b/docs/SUMMARY.md
index 98f3ecf..83caec0 100644
--- a/docs/SUMMARY.md
+++ b/docs/SUMMARY.md
@@ -14,6 +14,7 @@
         * [Synchronizer Design](dev/sync_arch.md)
         * [Synchronizer Implementation](dev/sync_impl.md)
         * [Synchronizer Reference](dev/sync_reference.md)
+    * [xosapi library](dev/xos-api.md)
     * [Core Models](core_models.md)
     * [Migrating XOS Models](dev/xosmigrate.md)
     * [Backup and Restore](dev/backup.md)
diff --git a/docs/dev/xos-api.md b/docs/dev/xos-api.md
new file mode 100644
index 0000000..4c0a78c
--- /dev/null
+++ b/docs/dev/xos-api.md
@@ -0,0 +1,173 @@
+# The xosapi Library
+
+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.
+
+## Prerequisites
+
+The following pip packages must be installed
+
+```bash
+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`.
+
+```bash
+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:
+
+```bash
+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/`:
+
+```bash
+echo "<my-core-ip-address> xos-core" | sudo tee -a /etc/hosts
+```
+
+The following directories must be writable:
+
+```bash
+sudo mkdir -p /var/run/xosapi
+sudo chmod a+rwx /var/run/xosapi
+```
+
+## Starting the API
+
+Now that everything is prepared, we can launch python and try to
+initialize and connect the API.
+
+```python
+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:
+
+```test
+Connected!
+Stopping!
+```
+
+## Using the API
+
+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:
+
+```python
+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:
+
+```text
+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`.