From 602e531197981607e659ec8eb8763e54e8902c55 Mon Sep 17 00:00:00 2001 From: Nirmal Ranganathan Date: Wed, 8 Oct 2014 19:25:36 -0500 Subject: [PATCH] [LIBCLOUD-622] Support for config_drive in the Openstack driver Adds a 'ex_config_drive' option to create_node and ex_rebuild_node for the Openstack driver. --- docs/compute/drivers/openstack.rst | 14 ++++++++++ docs/examples/compute/openstack/cloud_init.py | 28 +++++++++++++++++++ libcloud/compute/drivers/openstack.py | 17 +++++++++++ ..._26f7fbee_8ce1_4c28_887a_bfe8e4bb10fe.json | 2 +- libcloud/test/compute/test_openstack.py | 22 +++++++++++++++ 5 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 docs/examples/compute/openstack/cloud_init.py diff --git a/docs/compute/drivers/openstack.rst b/docs/compute/drivers/openstack.rst index ecf57d8c63..6975c3753c 100644 --- a/docs/compute/drivers/openstack.rst +++ b/docs/compute/drivers/openstack.rst @@ -122,6 +122,20 @@ Connecting to HP Cloud US West and US East (OpenStack Havana). .. literalinclude:: /examples/compute/openstack/hpcloud.py :language: python +7. Using Cloud-Init with Openstack +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This example shows how to use cloud-init using the ``ex_config_drive`` and +``ex_userdata`` arguments to ``create_node``. This example just installs +nginx and starts it. More `Cloud-Init examples`_. + +Note: You will need to use a cloud-init enabled image. Most Openstack based +public cloud providers support it. + +.. literalinclude:: /examples/compute/openstack/cloud_init.py + :language: python +.. _`Cloud-Init examples`: http://cloudinit.readthedocs.org/en/latest/topics/examples.html + Non-standard functionality and extension methods ------------------------------------------------ diff --git a/docs/examples/compute/openstack/cloud_init.py b/docs/examples/compute/openstack/cloud_init.py new file mode 100644 index 0000000000..5aafb92768 --- /dev/null +++ b/docs/examples/compute/openstack/cloud_init.py @@ -0,0 +1,28 @@ +from libcloud.compute.types import Provider +from libcloud.compute.providers import get_driver + + +cloud_init_config = """ +#cloud-config + +packages: + + - nginx + +runcmd: + + - service nginx start + +""" + + +OpenStack = get_driver(Provider.OPENSTACK) +driver = OpenStack('your_auth_username', 'your_auth_password', + ex_force_auth_url='http://192.168.1.101:5000', + ex_force_auth_version='2.0_password') + +image = driver.get_image('image_id') +size = driver.list_sizes()[0] + +node = driver.create_node(name='cloud_init', image=image, size=size, + ex_userdata=cloud_init_config, ex_config_drive=True) diff --git a/libcloud/compute/drivers/openstack.py b/libcloud/compute/drivers/openstack.py index 1d3b5ff9c3..750891d375 100644 --- a/libcloud/compute/drivers/openstack.py +++ b/libcloud/compute/drivers/openstack.py @@ -1175,6 +1175,10 @@ def create_node(self, **kwargs): Can be either ``AUTO`` or ``MANUAL``. :type ex_disk_config: ``str`` + :keyword ex_config_drive: If True enables metadata injection in a + server through a configuration drive. + :type ex_config_drive: ``bool`` + :keyword ex_admin_pass: The root password for the node :type ex_admin_pass: ``str`` @@ -1264,6 +1268,9 @@ def _create_args_to_params(self, node, **kwargs): if 'ex_disk_config' in kwargs: server_params['OS-DCF:diskConfig'] = kwargs['ex_disk_config'] + if 'ex_config_drive' in kwargs: + server_params['config_drive'] = str(kwargs['ex_config_drive']) + if 'ex_admin_pass' in kwargs: server_params['adminPass'] = kwargs['ex_admin_pass'] @@ -1358,6 +1365,10 @@ def ex_rebuild(self, node, image, **kwargs): Can be either ``AUTO`` or ``MANUAL``. :type ex_disk_config: ``str`` + :keyword ex_config_drive: If True enables metadata injection in a + server through a configuration drive. + :type ex_config_drive: ``bool`` + :rtype: ``bool`` """ server_params = self._create_args_to_params(node, image=image, @@ -1979,6 +1990,11 @@ def _to_node(self, api_node): image = api_node.get('image', None) image_id = image.get('id', None) if image else None + if api_node.get("config_drive", False).lower() == "true": + config_drive = True + else: + config_drive = False + return Node( id=api_node['id'], name=api_node['name'], @@ -2003,6 +2019,7 @@ def _to_node(self, api_node): updated=api_node['updated'], key_name=api_node.get('key_name', None), disk_config=api_node.get('OS-DCF:diskConfig', None), + config_drive=config_drive, availability_zone=api_node.get('OS-EXT-AZ:availability_zone', None), ), diff --git a/libcloud/test/compute/fixtures/openstack_v1.1/_servers_26f7fbee_8ce1_4c28_887a_bfe8e4bb10fe.json b/libcloud/test/compute/fixtures/openstack_v1.1/_servers_26f7fbee_8ce1_4c28_887a_bfe8e4bb10fe.json index d972cfd66c..7180b9167b 100644 --- a/libcloud/test/compute/fixtures/openstack_v1.1/_servers_26f7fbee_8ce1_4c28_887a_bfe8e4bb10fe.json +++ b/libcloud/test/compute/fixtures/openstack_v1.1/_servers_26f7fbee_8ce1_4c28_887a_bfe8e4bb10fe.json @@ -40,7 +40,7 @@ } ] }, - "config_drive": "", + "config_drive": "True", "id": "26f7fbee-8ce1-4c28-887a-bfe8e4bb10fe", "metadata": { "My Server Name" : "Apache1" diff --git a/libcloud/test/compute/test_openstack.py b/libcloud/test/compute/test_openstack.py index 930fff9bf0..19f0eb811e 100644 --- a/libcloud/test/compute/test_openstack.py +++ b/libcloud/test/compute/test_openstack.py @@ -916,6 +916,18 @@ def test_create_node_with_ex_disk_config(self): self.assertEqual(node.name, 'racktest') self.assertEqual(node.extra['disk_config'], 'AUTO') + def test_create_node_with_ex_config_drive(self): + OpenStack_1_1_MockHttp.type = 'EX_CONFIG_DRIVE' + image = NodeImage( + id=11, name='Ubuntu 8.10 (intrepid)', driver=self.driver) + size = NodeSize( + 1, '256 slice', None, None, None, None, driver=self.driver) + node = self.driver.create_node(name='racktest', image=image, size=size, + ex_config_drive=True) + self.assertEqual(node.id, '26f7fbee-8ce1-4c28-887a-bfe8e4bb10fe') + self.assertEqual(node.name, 'racktest') + self.assertEqual(node.extra['config_drive'], True) + def test_destroy_node(self): self.assertTrue(self.node.destroy()) @@ -965,6 +977,16 @@ def test_ex_rebuild_with_ex_disk_config(self): ex_disk_config='MANUAL') self.assertTrue(success) + def test_ex_rebuild_with_ex_config_drive(self): + image = NodeImage(id=58, name='Ubuntu 10.10 (intrepid)', + driver=self.driver) + node = Node(id=12066, name=None, state=None, public_ips=None, + private_ips=None, driver=self.driver) + success = self.driver.ex_rebuild(node, image=image, + ex_disk_config='MANUAL', + ex_config_drive=True) + self.assertTrue(success) + def test_ex_resize(self): size = NodeSize(1, '256 slice', None, None, None, None, driver=self.driver)