Merge "Inherit base image properties on instance creation"
This commit is contained in:
commit
4ff98af610
@ -129,8 +129,6 @@ MAX_USERDATA_SIZE = 65535
|
||||
QUOTAS = quota.QUOTAS
|
||||
RO_SECURITY_GROUPS = ['default']
|
||||
|
||||
SM_IMAGE_PROP_PREFIX = "image_"
|
||||
|
||||
|
||||
def check_instance_state(vm_state=None, task_state=(None,),
|
||||
must_have_launched=True):
|
||||
@ -1071,9 +1069,8 @@ class API(base.Base):
|
||||
return "Server %s" % instance_uuid
|
||||
|
||||
def _populate_instance_for_create(self, instance, image,
|
||||
index, security_groups):
|
||||
index, security_groups, instance_type):
|
||||
"""Build the beginning of a new instance."""
|
||||
image_properties = image.get('properties', {})
|
||||
|
||||
if not instance.obj_attr_is_set('uuid'):
|
||||
# Generate the instance_uuid here so we can use it
|
||||
@ -1092,20 +1089,17 @@ class API(base.Base):
|
||||
# (for notifications, etc). Only store what we can.
|
||||
if not instance.obj_attr_is_set('system_metadata'):
|
||||
instance.system_metadata = {}
|
||||
prefix_format = SM_IMAGE_PROP_PREFIX + '%s'
|
||||
for key, value in image_properties.iteritems():
|
||||
new_value = unicode(value)[:255]
|
||||
instance['system_metadata'][prefix_format % key] = new_value
|
||||
# Make sure we have the dict form that we need for instance_update.
|
||||
instance['system_metadata'] = utils.instance_sys_meta(instance)
|
||||
|
||||
# Keep a record of the original base image that this
|
||||
# image's instance is derived from:
|
||||
base_image_ref = image_properties.get('base_image_ref')
|
||||
if not base_image_ref:
|
||||
# base image ref property not previously set through a snapshot.
|
||||
# default to using the image ref as the base:
|
||||
base_image_ref = instance.image_ref
|
||||
system_meta = utils.get_system_metadata_from_image(
|
||||
image, instance_type)
|
||||
|
||||
# In case we couldn't find any suitable base_image
|
||||
system_meta.setdefault('image_base_image_ref', instance['image_ref'])
|
||||
|
||||
instance['system_metadata'].update(system_meta)
|
||||
|
||||
instance.system_metadata['image_base_image_ref'] = base_image_ref
|
||||
self.security_group_api.populate_security_groups(instance,
|
||||
security_groups)
|
||||
return instance
|
||||
@ -1123,7 +1117,7 @@ class API(base.Base):
|
||||
instance has been determined.
|
||||
"""
|
||||
self._populate_instance_for_create(instance, image, index,
|
||||
security_group)
|
||||
security_group, instance_type)
|
||||
|
||||
self._populate_instance_names(instance, num_instances)
|
||||
|
||||
@ -1860,8 +1854,8 @@ class API(base.Base):
|
||||
# Now inherit image properties from the base image
|
||||
for key, value in system_meta.items():
|
||||
# Trim off the image_ prefix
|
||||
if key.startswith(SM_IMAGE_PROP_PREFIX):
|
||||
key = key[len(SM_IMAGE_PROP_PREFIX):]
|
||||
if key.startswith(utils.SM_IMAGE_PROP_PREFIX):
|
||||
key = key[len(utils.SM_IMAGE_PROP_PREFIX):]
|
||||
|
||||
# Skip properties that are non-inheritable
|
||||
if key in CONF.non_inheritable_image_properties:
|
||||
@ -2037,12 +2031,14 @@ class API(base.Base):
|
||||
orig_sys_metadata = dict(sys_metadata)
|
||||
# Remove the old keys
|
||||
for key in sys_metadata.keys():
|
||||
if key.startswith(SM_IMAGE_PROP_PREFIX):
|
||||
if key.startswith(utils.SM_IMAGE_PROP_PREFIX):
|
||||
del sys_metadata[key]
|
||||
|
||||
# Add the new ones
|
||||
for key, value in image.get('properties', {}).iteritems():
|
||||
new_value = unicode(value)[:255]
|
||||
sys_metadata[(SM_IMAGE_PROP_PREFIX + '%s') % key] = new_value
|
||||
new_sys_metadata = utils.get_system_metadata_from_image(
|
||||
image, instance_type)
|
||||
|
||||
sys_metadata.update(new_sys_metadata)
|
||||
self.db.instance_system_metadata_update(context,
|
||||
instance['uuid'], sys_metadata, True)
|
||||
return orig_sys_metadata
|
||||
|
@ -5729,11 +5729,13 @@ class ComputeAPITestCase(BaseTestCase):
|
||||
{'fake': 'value'})}
|
||||
instance = instance_obj.Instance()
|
||||
instance.update(base_options)
|
||||
inst_type = flavors.get_flavor_by_name("m1.tiny")
|
||||
instance = self.compute_api._populate_instance_for_create(
|
||||
instance,
|
||||
self.fake_image,
|
||||
1,
|
||||
security_groups=None)
|
||||
security_groups=None,
|
||||
instance_type=inst_type)
|
||||
self.assertEquals(str(base_options['image_ref']),
|
||||
instance['system_metadata']['image_base_image_ref'])
|
||||
self.assertEquals(vm_states.BUILDING, instance['vm_state'])
|
||||
@ -5879,6 +5881,7 @@ class ComputeAPITestCase(BaseTestCase):
|
||||
instance_uuid)
|
||||
self.assertEqual(sys_metadata,
|
||||
{'image_kernel_id': 'fake_kernel_id',
|
||||
'image_min_disk': '1',
|
||||
'image_ramdisk_id': 'fake_ramdisk_id',
|
||||
'image_something_else': 'meow',
|
||||
'preserved': 'preserve this!'})
|
||||
|
@ -957,3 +957,74 @@ class AutoDiskConfigUtilTestCase(test.TestCase):
|
||||
|
||||
def test_is_auto_disk_config_disabled_false(self):
|
||||
self.assertFalse(utils.is_auto_disk_config_disabled("false"))
|
||||
|
||||
|
||||
class GetSystemMetadataFromImageTestCase(test.TestCase):
|
||||
def get_image(self):
|
||||
image_meta = {
|
||||
"id": "fake-image",
|
||||
"name": "fake-name",
|
||||
"min_ram": 1,
|
||||
"min_disk": 1,
|
||||
"disk_format": "raw",
|
||||
"container_format": "bare",
|
||||
}
|
||||
|
||||
return image_meta
|
||||
|
||||
def get_instance_type(self):
|
||||
instance_type = {
|
||||
"id": "fake.flavor",
|
||||
"root_gb": 10,
|
||||
}
|
||||
|
||||
return instance_type
|
||||
|
||||
def test_base_image_properties(self):
|
||||
image = self.get_image()
|
||||
|
||||
# Verify that we inherit all the needed keys
|
||||
sys_meta = utils.get_system_metadata_from_image(image)
|
||||
for key in utils.SM_INHERITABLE_KEYS:
|
||||
sys_key = "%s%s" % (utils.SM_IMAGE_PROP_PREFIX, key)
|
||||
self.assertEqual(image[key], sys_meta.get(sys_key))
|
||||
|
||||
# Verify that everything else is ignored
|
||||
self.assertEqual(len(sys_meta), len(utils.SM_INHERITABLE_KEYS))
|
||||
|
||||
def test_inherit_image_properties(self):
|
||||
image = self.get_image()
|
||||
image["properties"] = {"foo1": "bar", "foo2": "baz"}
|
||||
|
||||
sys_meta = utils.get_system_metadata_from_image(image)
|
||||
|
||||
# Verify that we inherit all the image properties
|
||||
for key, expected in image["properties"].iteritems():
|
||||
sys_key = "%s%s" % (utils.SM_IMAGE_PROP_PREFIX, key)
|
||||
self.assertEqual(sys_meta[sys_key], expected)
|
||||
|
||||
def test_vhd_min_disk_image(self):
|
||||
image = self.get_image()
|
||||
instance_type = self.get_instance_type()
|
||||
|
||||
image["disk_format"] = "vhd"
|
||||
|
||||
sys_meta = utils.get_system_metadata_from_image(image, instance_type)
|
||||
|
||||
# Verify that the min_disk property is taken from
|
||||
# instance_type's root_gb when using vhd disk format
|
||||
sys_key = "%s%s" % (utils.SM_IMAGE_PROP_PREFIX, "min_disk")
|
||||
self.assertEqual(sys_meta[sys_key], instance_type["root_gb"])
|
||||
|
||||
def test_dont_inherit_empty_values(self):
|
||||
image = self.get_image()
|
||||
|
||||
for key in utils.SM_INHERITABLE_KEYS:
|
||||
image[key] = None
|
||||
|
||||
sys_meta = utils.get_system_metadata_from_image(image)
|
||||
|
||||
# Verify that the empty properties have not been inherited
|
||||
for key in utils.SM_INHERITABLE_KEYS:
|
||||
sys_key = "%s%s" % (utils.SM_IMAGE_PROP_PREFIX, key)
|
||||
self.assertTrue(sys_key not in sys_meta)
|
||||
|
@ -110,6 +110,11 @@ _IS_NEUTRON = False
|
||||
|
||||
synchronized = lockutils.synchronized_with_prefix('nova-')
|
||||
|
||||
SM_IMAGE_PROP_PREFIX = "image_"
|
||||
SM_INHERITABLE_KEYS = (
|
||||
'min_ram', 'min_disk', 'disk_format', 'container_format',
|
||||
)
|
||||
|
||||
|
||||
def vpn_ping(address, port, timeout=0.05, session_id=None):
|
||||
"""Sends a vpn negotiation packet and returns the server session.
|
||||
@ -1050,6 +1055,8 @@ def instance_meta(instance):
|
||||
|
||||
|
||||
def instance_sys_meta(instance):
|
||||
if not instance.get('system_metadata'):
|
||||
return {}
|
||||
if isinstance(instance['system_metadata'], dict):
|
||||
return instance['system_metadata']
|
||||
else:
|
||||
@ -1216,3 +1223,28 @@ def get_auto_disk_config_from_instance(instance=None, sys_meta=None):
|
||||
|
||||
def get_auto_disk_config_from_image_props(image_properties):
|
||||
return image_properties.get("auto_disk_config")
|
||||
|
||||
|
||||
def get_system_metadata_from_image(image_meta, instance_type=None):
|
||||
system_meta = {}
|
||||
prefix_format = SM_IMAGE_PROP_PREFIX + '%s'
|
||||
|
||||
for key, value in image_meta.get('properties', {}).iteritems():
|
||||
new_value = unicode(value)[:255]
|
||||
system_meta[prefix_format % key] = new_value
|
||||
|
||||
for key in SM_INHERITABLE_KEYS:
|
||||
value = image_meta.get(key)
|
||||
|
||||
if key == 'min_disk' and instance_type:
|
||||
if image_meta.get('disk_format') == 'vhd':
|
||||
value = instance_type['root_gb']
|
||||
else:
|
||||
value = max(value, instance_type['root_gb'])
|
||||
|
||||
if value is None:
|
||||
continue
|
||||
|
||||
system_meta[prefix_format % key] = value
|
||||
|
||||
return system_meta
|
||||
|
@ -24,7 +24,6 @@ import uuid
|
||||
from oslo.config import cfg
|
||||
|
||||
from nova.api.metadata import password
|
||||
from nova.compute import api as compute_api
|
||||
from nova import context
|
||||
from nova import crypto
|
||||
from nova import exception
|
||||
@ -36,11 +35,11 @@ from nova import utils
|
||||
|
||||
|
||||
USE_AGENT_KEY = "xenapi_use_agent"
|
||||
USE_AGENT_SM_KEY = compute_api.SM_IMAGE_PROP_PREFIX + USE_AGENT_KEY
|
||||
USE_AGENT_SM_KEY = utils.SM_IMAGE_PROP_PREFIX + USE_AGENT_KEY
|
||||
SKIP_SSH_KEY = "xenapi_skip_agent_inject_ssh"
|
||||
SKIP_SSH_SM_KEY = compute_api.SM_IMAGE_PROP_PREFIX + SKIP_SSH_KEY
|
||||
SKIP_SSH_SM_KEY = utils.SM_IMAGE_PROP_PREFIX + SKIP_SSH_KEY
|
||||
SKIP_FILES_AT_BOOT_KEY = "xenapi_skip_agent_inject_files_at_boot"
|
||||
SKIP_FILES_AT_BOOT_SM_KEY = compute_api.SM_IMAGE_PROP_PREFIX \
|
||||
SKIP_FILES_AT_BOOT_SM_KEY = utils.SM_IMAGE_PROP_PREFIX \
|
||||
+ SKIP_FILES_AT_BOOT_KEY
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
Loading…
x
Reference in New Issue
Block a user