Creating your own VNF charm (Release FIVE): Difference between revisions
No edit summary |
No edit summary |
||
Line 10: | Line 10: | ||
===Types of charm=== | ===Types of charm=== | ||
There are | There are two types of charms supported in Release 5: proxy and machine. Proxy charms are appropriate when working with physical devices, such as a switch, or virtualized appliances, running in a VM. Machine charms work best with software that can be installed and run on top of a traditional operating system, such as Ubuntu Linux. | ||
The primary difference between them is that a proxy charm operates remotely against a VNF, typically using SSH, while a machine charm runs on the same machine as the VNF and interacts with it directly. | |||
====Proxy Charm==== | ====Proxy Charm==== | ||
OSM | The diagram below illustrates the OSM proxy charm workflow: | ||
<nowiki> | |||
+---------------------+ +---------------------+ | |||
| <----+ | | |||
| Resource | | Lightweight | | |||
| Orchestrator (RO) +----> Management (LCM) | | |||
| | | | | |||
+------------------+--+ +-------+----^--------+ | |||
| | | | |||
| | | | |||
| | | | |||
+-----v-----+ +-v----+--+ | |||
| <-------+ | | |||
| Virtual | | Proxy | | |||
| Machine | | Charm | | |||
| +-------> | | |||
+-----------+ +---------+ | |||
</nowiki> | |||
The SO directs the RO to create a virtual machine using the selected VNF image. When that has successfully completed, the SO will instantiate a LXD container, managed by Juju, with the proxy charm. The proxy charm will then communicate with the VNF virtual machine to do Day 1 configuration. | |||
====Machine Charm==== | |||
Machine (or Native) charms are written to run on the same machine as the application. They handle the complete lifecycle of an application, from installation to removal. | |||
Here is the OSM machine charm workflow: | |||
<nowiki> | <nowiki> | ||
+---------------------+ +---------------------+ | +---------------------+ +---------------------+ | ||
| <----+ | | | <----+ | | ||
| Resource | | | | Resource | | Lightweight | | ||
| Orchestrator (RO) +----> | | Orchestrator (RO) +----> Management (LCM) | | ||
| | | | | | | | | | ||
+------------------+--+ +-------+----^--------+ | +------------------+--+ +-------+----^--------+ | ||
Line 28: | Line 54: | ||
| | | | | | | | ||
| | | | | | | | ||
+-----v-----+ | +-----v-----+ | | | ||
| | | | | | | ||
| Virtual | | | Virtual | | | | ||
| Machine | | | Machine | | | | ||
| +------- | | | | | | ||
+-----------+ | | | | | | ||
| +-------+ <---------+ | | |||
| | Charm | | | | |||
| +-------+ +--------------+ | |||
+-----------+ | |||
</nowiki> | </nowiki> | ||
=== | ===Layers=== | ||
Layers are pieces of code that encapsulate operational logic. Each layer provides specific functionality that can be utilized by other layers. | |||
The diagram below illustrates the layers used by our ''simple'' charm, followed by a walkthrough of how it is built. The layer is available in the devops [https://osm.etsi.org/gitweb/?p=osm/devops.git;a=tree;f=charms;h=40e509e61920da3bb6f42b2ea403c923fc5fdbdf;hb=HEAD charms] repository. | |||
<nowiki> | <nowiki> | ||
+------------------+ | +------------------+ | ||
| | | | | | ||
| Layers | | | Layers | | ||
| | | | | | ||
| +------------+ | | | +------------+ | | ||
| | | | | | | | | | ||
| | | | | simple | | | ||
| | | | | | | | | | ||
| +------+-----+ | | | +------+-----+ | | ||
| | | | | | | | ||
| +------v-----+ | | | +------v-----+ | | ||
| | | | | | | | | | ||
| | sshproxy | | +-----------------+ | | | sshproxy | | +-----------------+ | ||
| | | | | | | | | | | | | | ||
| +------+-----+ | | | | +------+-----+ | | simple | | ||
| | +------------> | | | | +------------> | | ||
| +------v-----+ | | charm | | | +------v-----+ | | charm | | ||
| | | | | | | | | | | | | | ||
| | vnfproxy | | +-----------------+ | | | vnfproxy | | +-----------------+ | ||
| | | | | | | | | | ||
| +------+-----+ | | | +------+-----+ | | ||
| | | | | | | | ||
| +------v-----+ | | | +------v-----+ | | ||
| | | | | | | | | | ||
| | | | | Base | | | ||
| | | | | | | | | | ||
| +------------+ | | | +------------+ | | ||
| | | | | | ||
+------------------+ | +------------------+ | ||
</nowiki> | </nowiki> | ||
When we are ready, we will use the ''charm build'' command to flatten these layers into a charm, which can then be onboarded into OSM. | |||
===Interfaces=== | ===Interfaces=== | ||
Interfaces are layers that facilitate communication between two applications. Examples of using interfaces are forthcoming. | |||
===Actions=== | ===Actions=== | ||
[https://jujucharms.com/docs/stable/actions Actions], also referred to as Service Primitives, enable the operator to execute Day 1 and Day 2 configuration. | |||
==Getting Started== | ==Getting Started== | ||
We recommend that you are running Ubuntu 16.04 or newer, using the Juju and LXD packages installed via Snap. | We recommend that you are running Ubuntu 16.04 or newer, using the Juju and LXD packages installed via Snap, and the latest release of OSM. | ||
By default, the OSM installer will install and configure [[LXD_configuration_for_OSM_Release_FIVE|LXD]] and Juju for you, | |||
===Charm Tools=== | ===Charm Tools=== | ||
Line 113: | Line 126: | ||
<nowiki> | <nowiki> | ||
snap install charm | snap install charm --classic | ||
</nowiki> | </nowiki> | ||
Line 124: | Line 137: | ||
cd $LAYER_PATH | cd $LAYER_PATH | ||
</nowiki> | </nowiki> | ||
==Creating a charm== | ==Creating a charm== | ||
Line 132: | Line 146: | ||
<nowiki> | <nowiki> | ||
charm create | cd ~/charms/layers | ||
cd | charm create simple | ||
cd simple | |||
</nowiki> | </nowiki> | ||
Line 144: | Line 159: | ||
├── metadata.yaml | ├── metadata.yaml | ||
├── reactive | ├── reactive | ||
│ └── | │ └── simple.py | ||
├── README.ex | ├── README.ex | ||
└── tests | └── tests | ||
Line 152: | Line 167: | ||
===config.yaml=== | ===config.yaml=== | ||
Application-level configuration can be defined in [https://docs.jujucharms.com/2.4/en/charms-config config.yaml]. For our simple charm, extra configuration is required so you may ignore or delete this file. | |||
===layers.yaml=== | ===layers.yaml=== | ||
We define the layers required for our charm in ''layers.yaml''. Modify the file as shown below. This will include the ''vnfproxy'' layer, which adds standard primitives that OSM can execute. We'll also set the use_venv option of layer:basic. | |||
Note: We don't need to explicitly include the sshproxy layer, because it is included by the vnfproxy layer. | |||
<nowiki> | <nowiki> | ||
Line 163: | Line 180: | ||
- layer:basic | - layer:basic | ||
- layer:vnfproxy | - layer:vnfproxy | ||
options: | |||
basic: | |||
use_venv: false | |||
</nowiki> | </nowiki> | ||
You can find more layers in the [https://github.com/juju/layer-index Charm Layers Index]. | |||
===metadata.yaml=== | ===metadata.yaml=== | ||
Line 170: | Line 193: | ||
<nowiki> | <nowiki> | ||
name: | name: simple | ||
summary: A | summary: A simple charm example. | ||
maintainer: Adam Israel <adam.israel@canonical.com> | maintainer: Adam Israel <adam.israel@canonical.com> | ||
description: | | description: | | ||
A simple charm to use with Open Source Mano. | |||
subordinate: false | subordinate: false | ||
series: | series: | ||
- trusty | - trusty | ||
- xenial | - xenial | ||
- bionic | |||
</nowiki> | </nowiki> | ||
The metadata provides OSM and Juju with basic details about your charm. The ''series'' key informs Juju of what series of Ubuntu the charm can be deployed to. | |||
===actions.yaml=== | ===actions.yaml=== | ||
There are three pieces that make up an action: ''actions.yaml'', which define an action, the ''actions/'' directory where we'll place a small script that invokes the reactive framework, and the python code in ''reactive/ | There are three pieces that make up an action: ''actions.yaml'', which define an action, the ''actions/'' directory where we'll place a small script that invokes the reactive framework, and the python code in ''reactive/simple.py'' that executes the action. | ||
In ''actions.yaml'', we define the actions we wish to support: | In ''actions.yaml'', we define the actions we wish to support: | ||
<nowiki> | <nowiki> | ||
touch: | |||
description: " | description: "Touch a file." | ||
params: | params: | ||
filename: | |||
description: " | description: "The filename to touch." | ||
type: string | type: string | ||
default: "" | default: "" | ||
required: | required: | ||
- | - filename | ||
</nowiki> | </nowiki> | ||
<nowiki> | <nowiki> | ||
Line 232: | Line 233: | ||
<nowiki> | <nowiki> | ||
cat <<'EOF' >> actions/ | cat <<'EOF' >> actions/touch | ||
#!/usr/bin/env python3 | #!/usr/bin/env python3 | ||
import sys | import sys | ||
Line 257: | Line 258: | ||
<nowiki> | <nowiki> | ||
chmod +x actions/ | chmod +x actions/touch | ||
</nowiki> | </nowiki> | ||
The last step is to map the action to the command(s) to be run. To do this, open up reactive/ | The last step is to map the action to the command(s) to be run. To do this, open up reactive/simple.py and add this code. | ||
<nowiki> | <nowiki> | ||
@when('actions. | @when('actions.touch') | ||
def | def touch(): | ||
err = '' | err = '' | ||
try: | try: | ||
cmd = | filename = action_get('filename') | ||
cmd = ['touch {}'.format(filename)] | |||
result, err = charms.sshproxy._run(cmd) | result, err = charms.sshproxy._run(cmd) | ||
except: | except: | ||
Line 282: | Line 275: | ||
action_set({'outout': result}) | action_set({'outout': result}) | ||
finally: | finally: | ||
remove_flag('actions. | remove_flag('actions.touch') | ||
</nowiki> | </nowiki> | ||
When the touch primitive is invoked, it will execute the ''actions/touch'' script, which will run the code in ''reactive/simple.py'' that uses the matching ''@when'' decorator. | |||
===Building=== | ===Building=== | ||
Line 294: | Line 287: | ||
$ charm build | $ charm build | ||
build: Composing into /home/stone/charms | build: Composing into /home/stone/charms | ||
build: Destination charm directory: /home/stone/charms/builds/ | build: Destination charm directory: /home/stone/charms/builds/simple | ||
build: Please add a `repo` key to your layer.yaml, with a url from which your layer can be cloned. | build: Please add a `repo` key to your layer.yaml, with a url from which your layer can be cloned. | ||
build: Processing layer: layer:basic | build: Processing layer: layer:basic | ||
build: Processing layer: layer:sshproxy | build: Processing layer: layer:sshproxy | ||
build: Processing layer: layer:vnfproxy | build: Processing layer: layer:vnfproxy | ||
build: Processing layer: | build: Processing layer: simple | ||
</nowiki> | </nowiki> | ||
This combines all layers that you included, and those that they include, into a charm called '' | This combines all layers that you included, and those that they include, into a charm called ''simple'', located in the ''~/charms/builds'' directory. | ||
Now, you can copy the simple charm from your builds directory into the charms folder inside your VNF package: | |||
<nowiki> | |||
hackfest_simplecharm_vnf | |||
├── charms/ | |||
│ └── simple/ | |||
├── checksums.txt | |||
├── icons/ | |||
├── images/ | |||
├── scripts/ | |||
├── hackfest_simplecharm_vnfd.yaml | |||
└── README | |||
</nowiki> | |||
===Debugging=== | ===Debugging=== | ||
==VNF | When developing a charm, there are several useful tools available to use to aid in debugging. | ||
====juju debug-log==== | |||
The [https://docs.jujucharms.com/2.4/en/developer-debugging#the-'debug-log'-command juju debug-log] command allows you to view the Juju log stream in real time. This will show you the inner workings of Juju and any logs sent from the charm, including unhandled errors. | |||
====juju debug-hooks==== | |||
The [https://docs.jujucharms.com/2.4/en/developer-debugging#the-'debug-hooks'-command juju debug-hooks] command allows you to intercept lifecycle events and actions before or during their execution by opening a tmux session in the container running the charm. | |||
The initial tmux window does nothing but keep the session alive. When an event is queued, Juju will open a new window in the tmux session in a ''hook'' context. | |||
From here, you can manually execute the hook or action. | |||
You can also make to make changes to the deployed charm, such as adding ''import pdb; pdb.set_trace()'' to set a break point where you would like to use the Python debugger to examine the code at runtime. | |||
'''Note''': Changes made to a charm during a debug-hooks session are ephemeral, so be sure to replicate any fixes to your charm layer, rebuild the charm, and update the VNF package. | |||
===Source=== | |||
====Simple charm==== | |||
The source code for the simple charm layer can be found in the [https://osm.etsi.org/gitweb/?p=osm/devops.git;a=tree devops] git repository, under [https://osm.etsi.org/gitweb/?p=osm/devops.git;a=tree;f=charms/layers;h=d87b76d8b7169776ed59d6bc094b9a6eca5f2279;hb=HEAD charms/layers], along with other example charms. | |||
===VNF Descriptor=== | |||
Also in the devops repo, you will find many [https://osm.etsi.org/gitweb/?p=osm/devops.git;a=tree;f=descriptor-packages;h=17294792b83cdfc3d00caea2989125bedd05edbe;hb=HEAD examples of descriptors], including the [https://osm.etsi.org/gitweb/?p=osm/devops.git;a=tree;f=descriptor-packages/nsd/hackfest_simplecharm_ns;h=3ce3d0c1c427440c8980456614c0f540d2014c6f;hb=HEAD simplecharm ns] and [https://osm.etsi.org/gitweb/?p=osm/devops.git;a=tree;f=descriptor-packages/vnfd/hackfest_simplecharm_vnf;h=680b919586f9f94d89502932939280c7d02e1b26;hb=HEAD simplecharm_vnf]. | |||
Latest revision as of 20:08, 5 December 2018
DISCLAIMER: This page is being updated to reflect changes required for Release FIVE.
What is a VNF charm
A charm is a collection of scripts and metadata that encapsulate the distilled DevOps knowledge of experts in a particular product. These charms make it easy to reliably and repeatedly deploy applications, then scale them as required with minimal effort.
Driven by Juju, these charms manage the complete lifecycle of the application, including installation, configuration, clustering, and scaling.
Types of charm
There are two types of charms supported in Release 5: proxy and machine. Proxy charms are appropriate when working with physical devices, such as a switch, or virtualized appliances, running in a VM. Machine charms work best with software that can be installed and run on top of a traditional operating system, such as Ubuntu Linux.
The primary difference between them is that a proxy charm operates remotely against a VNF, typically using SSH, while a machine charm runs on the same machine as the VNF and interacts with it directly.
Proxy Charm
The diagram below illustrates the OSM proxy charm workflow:
+---------------------+ +---------------------+ | <----+ | | Resource | | Lightweight | | Orchestrator (RO) +----> Management (LCM) | | | | | +------------------+--+ +-------+----^--------+ | | | | | | | | | +-----v-----+ +-v----+--+ | <-------+ | | Virtual | | Proxy | | Machine | | Charm | | +-------> | +-----------+ +---------+
The SO directs the RO to create a virtual machine using the selected VNF image. When that has successfully completed, the SO will instantiate a LXD container, managed by Juju, with the proxy charm. The proxy charm will then communicate with the VNF virtual machine to do Day 1 configuration.
Machine Charm
Machine (or Native) charms are written to run on the same machine as the application. They handle the complete lifecycle of an application, from installation to removal.
Here is the OSM machine charm workflow:
+---------------------+ +---------------------+ | <----+ | | Resource | | Lightweight | | Orchestrator (RO) +----> Management (LCM) | | | | | +------------------+--+ +-------+----^--------+ | | | | | | | | | +-----v-----+ | | | | | | | Virtual | | | | Machine | | | | | | | | | | | | +-------+ <---------+ | | | Charm | | | | +-------+ +--------------+ +-----------+
Layers
Layers are pieces of code that encapsulate operational logic. Each layer provides specific functionality that can be utilized by other layers.
The diagram below illustrates the layers used by our simple charm, followed by a walkthrough of how it is built. The layer is available in the devops charms repository.
+------------------+ | | | Layers | | | | +------------+ | | | | | | | simple | | | | | | | +------+-----+ | | | | | +------v-----+ | | | | | | | sshproxy | | +-----------------+ | | | | | | | +------+-----+ | | simple | | | +------------> | | +------v-----+ | | charm | | | | | | | | | vnfproxy | | +-----------------+ | | | | | +------+-----+ | | | | | +------v-----+ | | | | | | | Base | | | | | | | +------------+ | | | +------------------+
When we are ready, we will use the charm build command to flatten these layers into a charm, which can then be onboarded into OSM.
Interfaces
Interfaces are layers that facilitate communication between two applications. Examples of using interfaces are forthcoming.
Actions
Actions, also referred to as Service Primitives, enable the operator to execute Day 1 and Day 2 configuration.
Getting Started
We recommend that you are running Ubuntu 16.04 or newer, using the Juju and LXD packages installed via Snap, and the latest release of OSM.
By default, the OSM installer will install and configure LXD and Juju for you,
Charm Tools
Install the charm snap, which provides the charm command and libraries necessary to compile your charm:
snap install charm --classic
Setup your workspace for writing layers and building charms:
mkdir -p ~/charms/layers export JUJU_REPOSITORY=~/charms export LAYER_PATH=$JUJU_REPOSITORY/layers cd $LAYER_PATH
Creating a charm
Create your charm layer
Create the layer for your proxy charm:
cd ~/charms/layers charm create simple cd simple
This will create a charm layer ready for customization:
. ├── config.yaml ├── icon.svg ├── layer.yaml ├── metadata.yaml ├── reactive │ └── simple.py ├── README.ex └── tests ├── 00-setup └── 10-deploy
config.yaml
Application-level configuration can be defined in config.yaml. For our simple charm, extra configuration is required so you may ignore or delete this file.
layers.yaml
We define the layers required for our charm in layers.yaml. Modify the file as shown below. This will include the vnfproxy layer, which adds standard primitives that OSM can execute. We'll also set the use_venv option of layer:basic.
Note: We don't need to explicitly include the sshproxy layer, because it is included by the vnfproxy layer.
includes: - layer:basic - layer:vnfproxy options: basic: use_venv: false
You can find more layers in the Charm Layers Index.
metadata.yaml
The metadata.yaml file describes what your charm is and sets certain properties used by Juju.
name: simple summary: A simple charm example. maintainer: Adam Israel <adam.israel@canonical.com> description: | A simple charm to use with Open Source Mano. subordinate: false series: - trusty - xenial - bionic
The metadata provides OSM and Juju with basic details about your charm. The series key informs Juju of what series of Ubuntu the charm can be deployed to.
actions.yaml
There are three pieces that make up an action: actions.yaml, which define an action, the actions/ directory where we'll place a small script that invokes the reactive framework, and the python code in reactive/simple.py that executes the action.
In actions.yaml, we define the actions we wish to support:
touch: description: "Touch a file." params: filename: description: "The filename to touch." type: string default: "" required: - filename
mkdir actions/
For each action, we need to create a script to invoke the reactive framework. This is a boilerplate script that will be used for every action. The first step is to create the first action script.
cat <<'EOF' >> actions/touch #!/usr/bin/env python3 import sys sys.path.append('lib') from charms.reactive import main from charms.reactive import set_state from charmhelpers.core.hookenv import action_fail, action_name """ `set_state` only works here because it's flushed to disk inside the `main()` loop. remove_state will need to be called inside the action method. """ set_state('actions.{}'.format(action_name())) try: main() except Exception as e: action_fail(repr(e)) EOF
After this, make the file executable.
chmod +x actions/touch
The last step is to map the action to the command(s) to be run. To do this, open up reactive/simple.py and add this code.
@when('actions.touch') def touch(): err = '' try: filename = action_get('filename') cmd = ['touch {}'.format(filename)] result, err = charms.sshproxy._run(cmd) except: action_fail('command failed:' + err) else: action_set({'outout': result}) finally: remove_flag('actions.touch')
When the touch primitive is invoked, it will execute the actions/touch script, which will run the code in reactive/simple.py that uses the matching @when decorator.
Building
When you're ready, you can create your charm via the charm build command:
$ charm build build: Composing into /home/stone/charms build: Destination charm directory: /home/stone/charms/builds/simple build: Please add a `repo` key to your layer.yaml, with a url from which your layer can be cloned. build: Processing layer: layer:basic build: Processing layer: layer:sshproxy build: Processing layer: layer:vnfproxy build: Processing layer: simple
This combines all layers that you included, and those that they include, into a charm called simple, located in the ~/charms/builds directory.
Now, you can copy the simple charm from your builds directory into the charms folder inside your VNF package:
hackfest_simplecharm_vnf ├── charms/ │ └── simple/ ├── checksums.txt ├── icons/ ├── images/ ├── scripts/ ├── hackfest_simplecharm_vnfd.yaml └── README
Debugging
When developing a charm, there are several useful tools available to use to aid in debugging.
juju debug-log
The juju debug-log command allows you to view the Juju log stream in real time. This will show you the inner workings of Juju and any logs sent from the charm, including unhandled errors.
juju debug-hooks
The juju debug-hooks command allows you to intercept lifecycle events and actions before or during their execution by opening a tmux session in the container running the charm.
The initial tmux window does nothing but keep the session alive. When an event is queued, Juju will open a new window in the tmux session in a hook context.
From here, you can manually execute the hook or action.
You can also make to make changes to the deployed charm, such as adding import pdb; pdb.set_trace() to set a break point where you would like to use the Python debugger to examine the code at runtime.
Note: Changes made to a charm during a debug-hooks session are ephemeral, so be sure to replicate any fixes to your charm layer, rebuild the charm, and update the VNF package.
Source
Simple charm
The source code for the simple charm layer can be found in the devops git repository, under charms/layers, along with other example charms.
VNF Descriptor
Also in the devops repo, you will find many examples of descriptors, including the simplecharm ns and simplecharm_vnf.