SimpleExampleService
is a service intended to demonstrate integration with the XOS kubernetes
service. SimpleExampleService
provides a SimpleExampleServiceInstance
model that generates and hosts a web page, displaying two text strings on the web page: a service_message
and a tenant_message
. Each time a SimpleExampleServiceInstance
is created, a corresponding KubernetesServiceInstance
will also be created which will in turn cause a Kubernetes pod to be created that runs an apache web server hosting the web page.
Destroying the SimpleExampleServiceInstance
will cause the linked KubernetesServiceInstance
to also be destroyed, which will in turn cause the Kubernetes pod to be cleaned up.
This service does not yet demonstrate dataplane connectivity to subscribers.
Inside the SimpleExampleService
repository's xos/synchronizer
directory, there are three key parts to the service.
The models
directory. This directory contains the models that comprise SimpleExampleService
. The full text of the models are specified in a file, simpleexampleservice.xproto
. A summary of the models is below:
SimpleExampleService
holds global service-wide settings, including a service_message
, which appears in all web pages generated by SimpleExampleService
, and a service_secret
that is installed into all container that run the web servers.
ServiceInstanceWithCompute
is an intermediate model, inheriting from ServiceInstance
and being inherited by SimpleExampleServiceInstance
. It augments ServiceInstance
with a compute_instance
field that may be used to link a ServiceInstance
to the ComputeServiceInstance
that will hold the compute resources necessary to implement the ServiceInstance
. This model will likely be migrated to the XOS core at some point as more containerized VNFs are developed. For those familiar with CORD-5.0
, ServiceInstanceWithCompute
serves the same purpose that TenantWithContainer
and/or ServiceInstanceWithContainer
served in CORD-5.0
and prior releases.
SimpleExampleServiceInstance
holds per-tenant settings, including a tenant_message
. Each SimpleExampleServiceInstance
corresponds to one web server serving one web page. This model has relations for foreground_color
and background_color
that allow some additional customization of the served page. tenant_secret
is a secret that is installed into the container running the web server
ColorNew
implements the color model used by the foreground_color
and background_color
fields of SimpleExampleServiceInstance
.
EmbeddedImageNew
allows embedded images to be attached to web pages. As the foreign key relation is from the embedded image to the service instance, this forms a many-to-one relation that allows many images to be attached to a single web page.
The model_policies
directory contains a model policy. This model_policy executes code every time a SimpleExampleServiceInstance
is created, updated, or deleted.
Rather than reproducing the full text of the code here, the actions are summarized below, and it's suggested the reader consult model_policy_simpleexampleserviceinstance.py
for reference.
When a new SimpleExampleServiceInstance
is created, the model policy creates a KubernetesConfigMap
, KubernetesSecret
, KubernetesServiceInstance
and the necessary objects to mount the configmap and secret into the service instance. The SimpleExampleServiceInstance
is updated with a relation to the KubernetesServiceInstance
, to make it easy to handle updates and deletions later.
When a SimpleExampleServiceInstance
is updated, the config map is modified to contain the new data, and the related KubernetesServiceInstance
is resaved, to cause it to be resynchronized by the Kubernetes synchronizer.
When a SimpleExampleServiceInstance
is deleted, the related KubernetesServiceInstance
is deleted.
The event_steps
directory contains an event step. This event step listens for Kafka events on the Kafka topic SimpleExampleEvent
. It assumes each event is a json-encoded dictionary containing a service_instance_name
and tenant_message
. The SimpleExampleServiceInstance
is looked up by name, the tenant_message
is updated, and the object is re-saved. Saving the object will then trigger the update model policy to run.
The following subsections work through a quick demonstration of SimpleExampleService
.
This document assumes that you have already installed Kubernetes in your development environment. If you haven't done so already, see QuickStart.
Note: Depending on the method that was used to deploy your Kubernetes installation, your installation may require root privilege to interact with Kubernetes. If so, then you may need to use
sudo
with many of the commands in this tutorial, for examplesudo helm init
instead ofhelm init
.
It's necessary for us to deploy three helm charts, xos-core
, base-kubernetes
. and demo-simpleexampleservice
.
If you followed the quickstart, then you should already have the proper helm charts installed and you may skip this subsection. If you're joining this guide after using an alternative method of installing Kubernetes, then you'll want to proceed with installing the following helm charts:
Note: If you've already installed a different set of XOS profile helm charts, such as the
rcord-lite
profile, then you may wish to uninstall those, as there's no guarantee that thebase-kubernetes
anddemo-simpleexampleservice
helm-charts can be layered on top of an existing XOS profile.
# Go into the helm-charts repository cd ~/cord/helm-charts # Initialize helm helm init # Install the xos-core helm chart helm dep update xos-core helm install xos-core -n xos-core # Install the base-kubernetes helm chart helm dep update xos-profiles/base-kubernetes helm install xos-profiles/base-kubernetes -n base-kubernetes # Install the demo-simpleexampleservice helm chart helm dep update xos-profiles/demo-simpleexampleservice helm install xos-profiles/demo-simpleexampleservice -n demo-simpleexampleservice
The helm charts above install successive layers of CORD. The first chart, xos-core
installs core components such as the XOS core, database, TOSCA engine, etc. The second chart, base-kubernetes
installs the XOS Kubernetes Service, which provides modeling and synchronizers for instantiating Kubernetes resources using the XOS data model. The final helm chart, demo-simpleexampleservice
installs the synchronizer for SimpleExampleService
, including registering models with the core.
Note: It will take some time for the various helm charts to deploy and the containers to come online. We recommend using
kubectl get pods
to explore the state of the system during deployment. In particular, note the presence oftosca-loader
containers. These containers are responsible for running TOSCA that configures services in the stack. Thetosca-loaders
may error and retry several times as they wait for services to be dynamically loaded. This is normal, and eventually thetosca-loader
containers will enter theCompleted
state.
Use kubectl get pods
to verify that all containers in the profile are successful and none are in error state. At this point, we've installed all of the necessary infrastructure to support SimpleExampleService
, such as registering its models and starting its synchronizer, but we haven't actually provisioned a SimpleExampleServiceInstance
yet. We will do that step next.
SimpleExampleServiceInstance
using TOSCAThis step will provision a SimpleExampleServiceInstance
. This ServiceInstance will be responsible for generating a web page and hosting that we page using resoucres of the Kubernetes service. SimpleExampleService
is a multi-tenant service, and the operator may provision man SimpleExampleServiceInstance
, each one an individual tenant of the service and each one generating a custom web page. This demo will take you through creating one ServiceInstance, and leave creating further ServiceInstances as an exercise.
We will demonstrate using TOSCA to create the SimpleExampleServiceInstance
, but this is not the only mechanism available. The steps here could alternatively be done in the XOS GUI, by using the XOS REST or gRPC APIs, or implemented as part of the model policies of some other service.
If you've already checked out the CORD code, for example using repo, then make note the path to the simpleexampleservice
code as we'll be using it in a few minutes:
SIMPLEEXAMPLESERVICE_PATH=~/cord/orchestration/xos-services/simpleexampleservice
Otherwise, check out the simpleexampleservice repository now:
cd ~ git clone https://github.com/opencord/simpleexampleservice SIMPLEEXAMPLESERVICE_PATH=~/simpleexampleservice
# Customize as necessary for your deployment. USERNAME=admin@opencord.org PASSWORD=letmein
SimpleExampleServiceInstance
.TOSCA_URL=http://$( hostname ):30007 TOSCA_FN=$SIMPLEEXAMPLESERVICE_PATH/xos/examples/SimpleExampleServiceInstance.yaml curl -H "xos-username: $USERNAME" -H "xos-password: $PASSWORD" -X POST --data-binary @$TOSCA_FN $TOSCA_URL/run
Please wait a few seconds for model policies to run, the Kubernetes synchronizer to instantiate containers, etc.
View the status.
CHAMELEON_URL=http://$( hostname ):30006 python $SIMPLEEXAMPLESERVICE_PATH/xos/examples/show-instances.py $CHAMELEON_URL $USERNAME $PASSWORD
Note: You may have to re-execute the above a few times while waiting for the objects to be created. If all is successful, eventually you will see an IP address assigned to the service instance.
Enter one of the other Kubernetes containers, where kubectl get pods
can be used to retrieve a list. Any of the containers will do (e.g., one of the synchronizer containers).
kubectl exec -it <pod-name> bash
From the shell prompt, perform a curl on the IP address obtained in the previous step.
The event bus is an optional mechanism that may be used to interact with services. SimpleExampleService
implements a single EventStep
, which listens on a Kafka topic and allows the tenant_message
to be updated.
helm repo add incubator http://storage.googleapis.com/kubernetes-charts-incubator helm install --name cord-kafka --set replicas=1 incubator/kafka
Wait for Kafka to be ready. Use kubectl get pods
to make sure the Kafka containers are in Running state.
Send an Event to update a web page
Enter one of the other Kubernetes containers, install the kafka library (pip install kafka
) and execute the follow python:
import json from confluent_kafka import Producer producer_config = {"bootstrap.servers": "cord-kafka"} producer = Producer(**producer_config) event = {"service_instance": "My Simple Example Service Instance", "tenant_message": "Earth"} producer.produce("SimpleExampleEvent", json.dumps(event), key=event["service_instance"]) producer.flush()
View the web page
Enter one of the other Kubernetes containers, any container such as one of the synchronizer containers will do, and perform a curl on the same IP address obtained in previous section. It may take up to a few minutes for the container to be updated with the new state from the event.