SimpleExampleService

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.

Limitations

This service does not yet demonstrate dataplane connectivity to subscribers.

Implementation

Inside the SimpleExampleService repository's xos/synchronizer directory, there are three key parts to the service.

  1. 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.

  2. 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.

  3. 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.

Demonstration

The following subsections work through a quick demonstration of SimpleExampleService.

Prerequisites

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 example sudo helm init instead of helm init.

Deploy the necessary profiles

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 the base-kubernetes and demo-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 of tosca-loader containers. These containers are responsible for running TOSCA that configures services in the stack. The tosca-loaders may error and retry several times as they wait for services to be dynamically loaded. This is normal, and eventually the tosca-loader containers will enter the Completed 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.

Create a SimpleExampleServiceInstance using TOSCA

This 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.

  • Check out the SimpleExampleService repository

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
  • Set your username and password.
# Customize as necessary for your deployment.
USERNAME=admin@opencord.org
PASSWORD=letmein
  • Run the TOSCA recipe to create a 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.

  • View the web page

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.

Use the Event Bus to modify a SimpleExampleServiceInstace

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.

  • Launch the Kafka Helm Chart, if you have not already done so:
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.