Merge "Inherit base image properties on instance creation"

This commit is contained in:
Jenkins 2013-09-04 16:49:52 +00:00 committed by Gerrit Code Review
commit 4ff98af610
5 changed files with 129 additions and 28 deletions

View File

@ -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

View File

@ -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!'})

View File

@ -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)

View File

@ -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

View File

@ -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__)