Keep flavor information in system_metadata

This patch copies the instance_type information into an
instance's system_metadata on creation. This provides a way
for us to recall the attributes used to create the instance
even after the type may have been deleted.

This adds db migration 153, which generates flavor information in
system_metadata for existing instances in the database, as well as
brings a test to make sure that works.

Change-Id: Iad9d640b44df5f3831de58f9e800bcf42bc0610e
This commit is contained in:
Dan Smith 2012-11-13 10:53:06 -08:00
parent 3c64e6ca4c
commit fed19822f8
4 changed files with 147 additions and 1 deletions

View File

@ -508,6 +508,13 @@ class API(base.Base):
availability_zone, forced_host = self._handle_availability_zone(
availability_zone)
system_metadata = {}
instance_type_props = ['id', 'name', 'memory_mb', 'vcpus',
'root_gb', 'ephemeral_gb', 'flavorid',
'swap', 'rxtx_factor', 'vcpu_weight']
for k in instance_type_props:
system_metadata["instance_type_%s" % k] = instance_type[k]
base_options = {
'reservation_id': reservation_id,
'image_ref': image_href,
@ -537,7 +544,8 @@ class API(base.Base):
'access_ip_v6': access_ip_v6,
'availability_zone': availability_zone,
'root_device_name': root_device_name,
'progress': 0}
'progress': 0,
'system_metadata': system_metadata}
options_from_image = self._inherit_properties_from_image(
image, auto_disk_config)

View File

@ -0,0 +1,49 @@
# Copyright 2013 IBM Corp.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from sqlalchemy import MetaData, select, Table
def upgrade(migrate_engine):
meta = MetaData()
meta.bind = migrate_engine
instances = Table('instances', meta, autoload=True)
instance_types = Table('instance_types', meta, autoload=True)
sys_meta = Table('instance_system_metadata', meta, autoload=True)
# Taken from nova/compute/api.py
instance_type_props = ['id', 'name', 'memory_mb', 'vcpus',
'root_gb', 'ephemeral_gb', 'flavorid',
'swap', 'rxtx_factor', 'vcpu_weight']
select_columns = [instances.c.uuid]
select_columns += [getattr(instance_types.c, name)
for name in instance_type_props]
q = select(select_columns, from_obj=instances.join(
instance_types,
instances.c.instance_type_id == instance_types.c.id))
i = sys_meta.insert()
for values in q.execute():
for index in range(0, len(instance_type_props)):
i.execute({"key": "instance_type_%s" % instance_type_props[index],
"value": str(values[index + 1]),
"instance_uuid": values[0]})
def downgrade(migration_engine):
# This migration only touches data, and only metadata at that. No need
# to go through and delete old metadata items.
pass

View File

@ -3780,6 +3780,28 @@ class ComputeAPITestCase(BaseTestCase):
finally:
db.instance_destroy(self.context, ref[0]['uuid'])
def test_create_saves_type_in_system_metadata(self):
instance_type = instance_types.get_default_instance_type()
(ref, resv_id) = self.compute_api.create(
self.context,
instance_type=instance_type,
image_href=None)
try:
sys_metadata = db.instance_system_metadata_get(self.context,
ref[0]['uuid'])
instance_type_props = ['name', 'memory_mb', 'vcpus', 'root_gb',
'ephemeral_gb', 'flavorid', 'swap',
'rxtx_factor', 'vcpu_weight']
for key in instance_type_props:
sys_meta_key = "instance_type_%s" % key
self.assertTrue(sys_meta_key in sys_metadata)
self.assertEqual(str(instance_type[key]),
str(sys_metadata[sys_meta_key]))
finally:
db.instance_destroy(self.context, ref[0]['uuid'])
def test_create_instance_associates_security_groups(self):
# Make sure create associates security groups.
group = self._create_group()

View File

@ -24,6 +24,7 @@ properly both upgrading and downgrading, and that no data loss occurs
if possible.
"""
import collections
import commands
import ConfigParser
import os
@ -452,3 +453,69 @@ class TestMigrations(test.TestCase):
self.assertEqual("", volume.deleted)
volume = volumes.select(volumes.c.id == "second").execute().first()
self.assertEqual(volume.id, volume.deleted)
# migration 153, copy flavor information into system_metadata
def _prerun_153(self, engine):
fake_types = [
dict(id=10, name='type1', memory_mb=128, vcpus=1,
root_gb=10, ephemeral_gb=0, flavorid="1", swap=0,
rxtx_factor=1.0, vcpu_weight=1, disabled=False,
is_public=True),
dict(id=11, name='type2', memory_mb=512, vcpus=1,
root_gb=10, ephemeral_gb=5, flavorid="2", swap=0,
rxtx_factor=1.5, vcpu_weight=2, disabled=False,
is_public=True),
dict(id=12, name='type3', memory_mb=128, vcpus=1,
root_gb=10, ephemeral_gb=0, flavorid="3", swap=0,
rxtx_factor=1.0, vcpu_weight=1, disabled=False,
is_public=False),
dict(id=13, name='type4', memory_mb=128, vcpus=1,
root_gb=10, ephemeral_gb=0, flavorid="4", swap=0,
rxtx_factor=1.0, vcpu_weight=1, disabled=True,
is_public=True),
dict(id=14, name='type5', memory_mb=128, vcpus=1,
root_gb=10, ephemeral_gb=0, flavorid="5", swap=0,
rxtx_factor=1.0, vcpu_weight=1, disabled=True,
is_public=False),
]
fake_instances = [
dict(uuid='m153-uuid1', instance_type_id=10),
dict(uuid='m153-uuid2', instance_type_id=11),
dict(uuid='m153-uuid3', instance_type_id=12),
dict(uuid='m153-uuid4', instance_type_id=13),
# NOTE(danms): no use of type5
]
instances = get_table(engine, 'instances')
instance_types = get_table(engine, 'instance_types')
engine.execute(instance_types.insert(), fake_types)
engine.execute(instances.insert(), fake_instances)
return fake_types, fake_instances
def _check_153(self, engine, data):
fake_types, fake_instances = data
# NOTE(danms): Fetch all the tables and data from scratch after change
instances = get_table(engine, 'instances')
instance_types = get_table(engine, 'instance_types')
sys_meta = get_table(engine, 'instance_system_metadata')
# Collect all system metadata, indexed by instance_uuid
metadata = collections.defaultdict(dict)
for values in sys_meta.select().execute():
metadata[values['instance_uuid']][values['key']] = values['value']
# Taken from nova/compute/api.py
instance_type_props = ['id', 'name', 'memory_mb', 'vcpus',
'root_gb', 'ephemeral_gb', 'flavorid',
'swap', 'rxtx_factor', 'vcpu_weight']
for instance in fake_instances:
inst_sys_meta = metadata[instance['uuid']]
inst_type = fake_types[instance['instance_type_id'] - 10]
for prop in instance_type_props:
prop_name = 'instance_type_%s' % prop
self.assertIn(prop_name, inst_sys_meta)
self.assertEqual(str(inst_sys_meta[prop_name]),
str(inst_type[prop]))