This is an automated email from the ASF dual-hosted git repository.
tomaz pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/libcloud.git
The following commit(s) were added to refs/heads/trunk by this push:
new 114f09f openstack driver can create node from bootable vol
new 9e3296d Merge pull request #1362 from
vdloo/openstack-driver-can-create-node-from-bootable-vol
114f09f is described below
commit 114f09f11abeb353ee1d19bd8e203f4daf1bdfec
Author: Rick van de Loo <[email protected]>
AuthorDate: Wed Oct 30 12:46:22 2019 +0100
openstack driver can create node from bootable vol
Currently it is not possible to use the create_node method without
specifying an image. This is because in the OpenStack_1_1_NodeDriver
create_node converts the server_params like:
```
server_params = self._create_args_to_params(None, **kwargs)
```
but in case when there is no image to boot from like when you are
booting from an already existing bootable volume (which could have been
created from an image earlier), then _create_args_to_params will try to
access node.extra in order to get the imageRef, and node is None:
```
if 'image' in kwargs:
server_params['imageRef'] = kwargs.get('image').id
else:
server_params['imageRef'] = node.extra.get('imageId')
```
Booting an instance from a previously existing bootable volume like this
would fail:
```
In [36]: conn.create_node(ex_availability_zone='R123',
port='8487d948-0840-4205-8b31-7f705a19e7f4', name='r123apitestnode', ex_keyname
...: ='rick', size='e55a2688-ef74-44cf-b302-9a6f960c3d74',
ex_blockdevicemappings=[{'boot_index': 0, 'uuid': 'be7ee330-b454-4414-8
...: e9f-c70c558dd3af', 'source_type': 'volume', 'destination_type':
'volume', 'delete_on_termination': False}])
```
with:
```
/usr/local/venv/hypernode-control/src/apache-libcloud/libcloud/compute/drivers/openstack.pyc
in _create_args_to_params(self, node, **kwargs)
1495 server_params['imageRef'] = kwargs.get('image').id
1496 else:
-> 1497 server_params['imageRef'] = node.extra.get('imageId')
1498
1499 if 'size' in kwargs:
AttributeError: 'NoneType' object has no attribute 'extra'
```
This could be circumvented by specifying `image=''`:
```
In [39]: conn.create_node(ex_availability_zone='R123',
port='8487d948-0840-4205-8b31-7f705a19e7f4', image='', name='r123apitestnode',
...: ex_keyname='rick', size='e55a2688-ef74-44cf-b302-9a6f960c3d74',
ex_blockdevicemappings=[{'boot_index': 0, 'uuid': 'be7ee330-b
...: 454-4414-8e9f-c70c558dd3af', 'source_type': 'volume',
'destination_type': 'volume', 'delete_on_termination': False}])
```
This PR also changes the default imageRef to empty string '' instead of
None to prevent the API from responding with an error like this when the .get
would default to None so that `image=''` will now no longer have to be
specified.
```
BaseHTTPError: 400 Bad Request Invalid input for field/attribute imageRef.
Value: None. u'None' is not valid under any of the given schemas
```
---
libcloud/compute/drivers/openstack.py | 4 +++-
libcloud/test/compute/test_openstack.py | 20 ++++++++++++++++++++
2 files changed, 23 insertions(+), 1 deletion(-)
diff --git a/libcloud/compute/drivers/openstack.py
b/libcloud/compute/drivers/openstack.py
index 6be9157..2b1039d 100644
--- a/libcloud/compute/drivers/openstack.py
+++ b/libcloud/compute/drivers/openstack.py
@@ -1515,7 +1515,9 @@ class OpenStack_1_1_NodeDriver(OpenStackNodeDriver):
if 'image' in kwargs:
server_params['imageRef'] = kwargs.get('image').id
else:
- server_params['imageRef'] = node.extra.get('imageId')
+ server_params['imageRef'] = node.extra.get(
+ 'imageId', ''
+ ) if node else ''
if 'size' in kwargs:
server_params['flavorRef'] = kwargs.get('size').id
diff --git a/libcloud/test/compute/test_openstack.py
b/libcloud/test/compute/test_openstack.py
index e3604e9..d172771 100644
--- a/libcloud/test/compute/test_openstack.py
+++ b/libcloud/test/compute/test_openstack.py
@@ -981,6 +981,26 @@ class OpenStack_1_1_Tests(unittest.TestCase,
TestCaseMixin):
self.assertEqual(node.name, 'racktest')
self.assertTrue(node.extra['config_drive'])
+ def test_create_node_from_bootable_volume(self):
+ size = NodeSize(
+ 1, '256 slice', None, None, None, None, driver=self.driver)
+
+ node = self.driver.create_node(
+ name='racktest', size=size,
+ ex_blockdevicemappings=[
+ {
+ 'boot_index': 0,
+ 'uuid': 'ee7ee330-b454-4414-8e9f-c70c558dd3af',
+ 'source_type': 'volume',
+ 'destination_type': 'volume',
+ 'delete_on_termination': False
+ }])
+
+ self.assertEqual(node.id, '26f7fbee-8ce1-4c28-887a-bfe8e4bb10fe')
+ self.assertEqual(node.name, 'racktest')
+ self.assertEqual(node.extra['password'], 'racktestvJq7d3')
+ self.assertEqual(node.extra['metadata']['My Server Name'], 'Apache1')
+
def test_destroy_node(self):
self.assertTrue(self.node.destroy())