#!/usr/bin/python # Copyright (C) 2013 Codethink Limited # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; version 2 of the License. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License along # with this program; if not, write to the Free Software Foundation, Inc., # 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. '''A Morph deployment write extension for deploying to OpenStack.''' import cliapp import os import tempfile import urlparse import morphlib.writeexts class OpenStackWriteExtension(morphlib.writeexts.WriteExtension): '''Configure a raw disk image into an OpenStack host. The raw disk image is created during Morph's deployment and the image is deployed in OpenStack using python-glanceclient. The location command line argument is the authentification url of the OpenStack server using the following syntax: http://HOST:PORT/VERSION where * HOST is the host running OpenStack * PORT is the port which is using OpenStack for authentifications. * VERSION is the authentification version of OpenStack (Only v2.0 supported) This extension needs in the environment the following variables: * OPENSTACK_USER is the username to use in the deployment. * OPENSTACK_TENANT is the project name to use in the deployment. * OPENSTACK_IMAGENAME is the name of the image to create. * OPENSTACK_PASSWORD is the password of the user. The extension will connect to OpenStack using python-glanceclient to configure a raw image. ''' def process_args(self, args): if len(args) != 2: raise cliapp.AppException('Wrong number of command line args') temp_root, location = args self.check_location(location) os_params = self.get_openstack_parameters() fd, raw_disk = tempfile.mkstemp() os.close(fd) self.create_local_system(temp_root, raw_disk) self.status(msg='Temporary disk image has been created at %s' % raw_disk) self.set_extlinux_root_to_virtio(raw_disk) self.configure_openstack_image(raw_disk, location, os_params) def set_extlinux_root_to_virtio(self, raw_disk): '''Re-configures extlinux to use virtio disks''' self.status(msg='Updating extlinux.conf') mp = self.mount(raw_disk) try: path = os.path.join(mp, 'extlinux.conf') with open(path) as f: extlinux_conf = f.read() extlinux_conf = extlinux_conf.replace('root=/dev/sda', 'root=/dev/vda') with open(path, "w") as f: f.write(extlinux_conf) finally: self.unmount(mp) def get_openstack_parameters(self): '''Check the environment variables needed and returns all. The environment variables are described in the class documentation. ''' keys = ('OPENSTACK_USER', 'OPENSTACK_TENANT', 'OPENSTACK_IMAGENAME', 'OPENSTACK_PASSWORD') for key in keys: if key not in os.environ: raise cliapp.AppException(key + ' was not given') return (os.environ[key] for key in keys) def check_location(self, location): x = urlparse.urlparse(location) if x.scheme != 'http': raise cliapp.AppException('URL schema must be http in %s' \ % location) if (x.path != '/v2.0' and x.path != '/v2.0/'): raise cliapp.AppException('API version must be v2.0 in %s'\ % location) def configure_openstack_image(self, raw_disk, auth_url, os_params): '''Configure the image in OpenStack using glance-client''' self.status(msg='Configuring OpenStack image...') username, tenant_name, image_name, password = os_params cmdline = ['glance', '--os-username', username, '--os-tenant-name', tenant_name, '--os-password', password, '--os-auth-url', auth_url, 'image-create', '--name=%s' % image_name, '--disk-format=raw', '--container-format', 'bare', '--file', raw_disk] cliapp.runcmd(cmdline) self.status(msg='Image configured.') OpenStackWriteExtension().run()