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
sudowith many of the commands in this tutorial, for examplesudo helm initinstead 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-liteprofile, then you may wish to uninstall those, as there's no guarantee that thebase-kubernetesanddemo-simpleexampleservicehelm-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 podsto explore the state of the system during deployment. In particular, note the presence oftosca-loadercontainers. These containers are responsible for running TOSCA that configures services in the stack. Thetosca-loadersmay error and retry several times as they wait for services to be dynamically loaded. This is normal, and eventually thetosca-loadercontainers will enter theCompletedstate.
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 kafka import KafkaProducer producer = KafkaProducer(bootstrap_servers="cord-kafka") producer.send("SimpleExampleEvent", json.dumps({"service_instance": "My Simple Example Service Instance", "tenant_message": "Earth"})) 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.