Introducing Murano plugins: Extending OpenStack catalog capabilities
Murano, the Application Catalog for Openstack, is more than app storage. Murano enables the easy building of compound environments that include multiple interconnected applications. But what if you want your application to integrate with an external service directly? In previous versions of Murano, you would have had to modify the code directly. The introduction of Murano plugins has simplified the process. Let’s have a look at where Murano plugins can be useful, and how to use your own plugins.
Murano plugins can be used for:
Providing interaction with external services
Suppose you want to interact with the OpenStack Glance service to get information about images suitable for deployment. A plugin may request image data from Glance during deployment, performing any necessary checks. (In the second half of this article, we'll show you how to do that.)
Enabling connections between Murano applications and external hardware
Suppose you have an external load balancer located on a powerful hardware, and you want your applications launched in OpenStack to use that load balancer. You can write a plugin that interacts with the load balancer API. Once you've done that, you can add new apps to the pool of your load balancer or make any other configurations from within your application definition.
Extending core-library class functionality, which is responsible for creating networks, interaction with murano-agent and so on
Suppose you want to create networks with special parameters for all of your applications. You can just copy the class that is responsible for network management from the Murano core library, make the desired modification, and load the new class as a plugin. Both classes will be available, and it’s up to you to decide which way to create your networks.
Optimization of frequently used operations. (Plugin classes are written in Python, so opportunity for improvement is significant.)
Depending on what you need to improve, Murano provides plenty of opportunities for optimization. For example, classes in the murano-core library, can be rewritten in C and used from python code to improved their performance in particular use cases.
Creating a Murano plugin
Let’s consider the use case of adding additional validation before using a chosen image to spawn an image as part of the application deployment process.. The plugin that implements this use case connects to the OpenStack Glance service using glanceclient.
The full code of the plugin is available at Murano repository adn https://github.com/openstack/murano/tree/master/contrib/plugins/murano_exampleplugin.
To implement this plugin, perform the following steps:
Create a simple Python class for image validation, and use it to send http requests to the Glance API server.
class GlanceClient(object):
def initialize(self, _context):
client_manager = helpers.get_environment(_context).clients
self.client = client_manager.get_client(_context, "glance", True,
self.create_glance_client)
def list(self):
images = self.client.images.list()
while True:
try:
image = images.next()
yield GlanceClient._format(image)
except StopIteration:
break
...
def getById(self, imageId):
image = self.client.images.get(imageId)
return GlanceClient._format(image)
@classmethod
def init_plugin(cls):
cls.CONF = cfg.init_config(config.CONF)
class AmbiguousNameException(Exception):
def __init__(self, name):
super(AmbiguousNameException, self).__init__("Image name '%s'"
" is ambiguous" % name)
Create a setuptools-compliant python package with setup.py and all other nessesary files. It exports the created class as plugin entry-point at ‘io.murano.extensions’ namespace. This makes the plugin compatible with stevedore, a common way to dynamically load code in OpenStack. (You can find more information about defining stevedore plugins in the stevedore documentation at https://wiki.openstack.org/wiki/Oslo#stevedore.)
Install the created python package into the Murano environment by either executing its setup script or by using a package deployment tool such as pip. Make sure to restart the Murano engine after installation.
$ user@host:~/murano_exampleplugin python setup.py install
Zip and upload an app which uses this plugin to test it.
$ user@host:~/murano_exampleplugin pushd example-app/io.murano.apps.demo.DemoApp; zip -r ../../murano-app.zip *; popd;
$ user@host:~/murano_exampleplugin murano package-import murano-app.zip
And that's it. In just 4 easy steps you have the limitless possibilities of improving, customizing and upgrading the application deployment process.
What kinds of deployment use-cases are you working on? Please share in the comments; we really want to know how you're using Murano, and we'll be happy to provide advice on how to implement them!