SEBA-329 Tutorial on Interacting with gRPC Northbound API

Change-Id: I2a16e44bcb7ad1ab4cbd9f0e055614fff6c4b331
diff --git a/VERSION b/VERSION
index a62db96..6156c34 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1 @@
-2.1.22
+2.1.23
diff --git a/containers/chameleon/Dockerfile.chameleon b/containers/chameleon/Dockerfile.chameleon
index 67dd70f..8fc542b 100644
--- a/containers/chameleon/Dockerfile.chameleon
+++ b/containers/chameleon/Dockerfile.chameleon
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 # xosproject/chameleon
-FROM xosproject/xos-base:2.1.22
+FROM xosproject/xos-base:2.1.23
 
 # xos-base already has protoc and dependencies installed
 
diff --git a/containers/xos/Dockerfile.client b/containers/xos/Dockerfile.client
index f2fd717..c7ae9dc 100644
--- a/containers/xos/Dockerfile.client
+++ b/containers/xos/Dockerfile.client
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 # xosproject/xos-client
-FROM xosproject/xos-libraries:2.1.22
+FROM xosproject/xos-libraries:2.1.23
 
 # Install XOS client
 COPY xos/xos_client /tmp/xos_client
diff --git a/containers/xos/Dockerfile.libraries b/containers/xos/Dockerfile.libraries
index 801c93e..a2ffe34 100644
--- a/containers/xos/Dockerfile.libraries
+++ b/containers/xos/Dockerfile.libraries
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 # xosproject/xos-libraries
-FROM xosproject/xos-base:2.1.22
+FROM xosproject/xos-base:2.1.23
 
 # Add libraries
 COPY lib /opt/xos/lib
diff --git a/containers/xos/Dockerfile.synchronizer-base b/containers/xos/Dockerfile.synchronizer-base
index 82cbd49..2d083de 100644
--- a/containers/xos/Dockerfile.synchronizer-base
+++ b/containers/xos/Dockerfile.synchronizer-base
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 # xosproject/xos-synchronizer-base
-FROM xosproject/xos-client:2.1.22
+FROM xosproject/xos-client:2.1.23
 
 COPY xos/synchronizers/new_base /opt/xos/synchronizers/new_base
 COPY xos/xos/logger.py /opt/xos/xos/logger.py
diff --git a/containers/xos/Dockerfile.xos-core b/containers/xos/Dockerfile.xos-core
index bd677ba..cdc36a7 100644
--- a/containers/xos/Dockerfile.xos-core
+++ b/containers/xos/Dockerfile.xos-core
@@ -13,7 +13,7 @@
 # limitations under the License.
 
 # xosproject/xos-core
-FROM xosproject/xos-libraries:2.1.22
+FROM xosproject/xos-libraries:2.1.23
 
 # Install XOS
 ADD xos /opt/xos
diff --git a/docs/dev/grpc_api.md b/docs/dev/grpc_api.md
new file mode 100644
index 0000000..93ce856
--- /dev/null
+++ b/docs/dev/grpc_api.md
@@ -0,0 +1,112 @@
+# gRPC API Usage Tutorial
+
+The XOS gRPC API may be used directly for operating on objects in the XOS data model as an alternative to REST or TOSCA. This short tutorial will walk the reader through the necessary steps to generate protobufs and to create a working gRPC API client.
+
+### Prerequisites
+
+Several python packages need to be installed into your development environment. You may use our supplied [virtualenv](./unittest.html#setting-up-a-unit-testing-environment), or you can install the necessary packages directly into your development environment:
+
+```shell
+# for running xosgenx
+sudo pip install plyxproto jinja2 pyyaml colorama
+
+# for building protobufs
+sudo pip install grpcio grpcio-tools
+
+# install the xos-genx library (not currently available on pypi)
+cd ~/cord/orchestration/xos/lib/xos-genx
+sudo python ./setup.py install
+```
+
+This guide assumes that you have checked out CORD using the repo tool into the directory `~/cord`. It is also assumed that you have a working SEBA installation that uses the `att-workflow` profile.
+
+### Build common protobufs
+
+There are a number of common protobufs that are referenced by the XOS API that need to be generated. This can be done as follows:
+
+```shell
+cd ~/cord/orchestration/xos/xos/coreapi/protos
+make
+```
+
+Note that you may want to clean these up (`make clean`) after you've completed this tutorial, particularly if you plan on building any XOS docker containers from your build environment.
+
+### Generating and build protobufs and gRPC from a subset of the XOS API
+
+The XOS API is relatively large, but if you want to only operate over a subset of it, there are options that can be used with xosgenx. Here's an example:
+
+```shell
+mkdir -p ~/cord/sample_client
+cd ~/cord/sample_client
+xosgenx --target protoapi.xtarget --include-apps volt --include-apps rcord --include-apps att-workflow-driver --include-apps fabric-crossconnect  ~/cord/orchestration/xos/xos/core/models/core.xproto ~/cord/orchestration/xos_services/olt-service/xos/synchronizer/models/volt.xproto ~/cord/orchestration/xos_services/att-workflow-driver/xos/synchronizer/models/att-workflow-driver.xproto ~/cord/orchestration/xos_services/fabric-crossconnect/xos/synchronizer/models/fabric-crossconnect.xproto ~/cord/orchestration/profiles/rcord/xos/synchronizer/models/rcord.xproto > ~/cord/sample_client/seba.proto
+```
+
+Note that it's necessary to supply the source xproto files that you're going to use. For this example, we've provided a list that includes popular SEBA services. We've also included the core xprotos, since they include necessary base classes for the services.
+
+The `--include-apps` directive is used to filter which apps are included in the output. In this example, we've included all apps present in the source files, *excluding* the core, as the core includes many models that we aren't directly interested in.
+
+It's also time to copy the common protobuf stubs into your working directory:
+
+```shell
+cp ~/cord/orchestration/xos/xos/coreapi/protos/*_pb2*.py ~/cord/sample_client/
+```
+
+Finally, we can build our custom protobufs:
+
+```shell
+cd ~/cord/sample-client
+COMMON_PROTO_DIR=`realpath ~/cord/orchestration/xos/xos/coreapi/protos`
+python -m grpc_tools.protoc -I. -I$COMMON_PROTO_DIR --python_out=. --grpc_python_out=. seba.proto
+```
+
+This will generate `seba_pb2.py` and `seba_pb2_grpc.py`, and they will be residing alongside the common protobuf stubs that we copied into our working directory earlier.
+
+### Get the ca-cert-chain
+
+In order to use the gRPC API, we need to have a certificate that we can use to talk to the core. That certificate chain is located in the file `xos-core/values.yaml` in the `helm-charts` repositry. You'll need to locate the value `ca_cert_chain` in `values.yaml`, extract that value into a text file called `xos_core_ca_cert.in`, and then run the following:
+
+```shell
+base64 --decode xos_core_ca_cert.in > xos_core_ca_cert.out
+```
+
+The reason we had to base64 decode it is because secrets in kubernetes are always base64 encoded when they're placed into helm charts.
+
+### Create and run the test client
+
+Below is a simple test client:
+
+```python
+import base64
+import grpc
+import seba_pb2, seba_pb2_grpc
+
+from grpc import metadata_call_credentials, ssl_channel_credentials, composite_channel_credentials
+from google.protobuf.empty_pb2 import Empty
+
+CACERT="xos_core_ca_cert.out"
+USERNAME="admin@opencord.org"
+PASSWORD="letmein"
+
+class UsernamePasswordCallCredentials(grpc.AuthMetadataPlugin):
+      """Metadata wrapper for raw access token credentials."""
+      def __init__(self, username, password):
+            self._username = username
+            self._password = password
+      def __call__(self, context, callback):
+            basic_auth = "Basic %s" % base64.b64encode("%s:%s" % (self._username, self._password))
+            metadata = (('authorization', basic_auth),)
+            callback(metadata, None)
+
+server_ca = open(CACERT,"r").read()
+call_creds = metadata_call_credentials(UsernamePasswordCallCredentials(USERNAME, PASSWORD))
+chan_creds = ssl_channel_credentials(server_ca)
+chan_creds = composite_channel_credentials(chan_creds, call_creds)
+
+with grpc.secure_channel('xos-core:30010', chan_creds) as channel:
+    stub = seba_pb2_grpc.xosStub(channel)
+    print stub.ListVOLTService(Empty())
+```
+
+Note that the name `xos-core` must resolve inside of the environment you will be using to run the client. The name `xos-core` is baked into the certificate, so it must be that named used, and no other name. When operating inside of a container, Kubernetes will usually have name resolution already provided, but if operating in a development environment outside of a container, it may be necessary to provide name resolution yourself, such as an entry in `/etc/hosts`.
+
+Paste the above to a file, such as `client.py` and then run it (`python client.py`). The output should be a list of VOLTService currently in the data model. If there are no VOLTServices, then it'll emit an empty list.
\ No newline at end of file