Merge lp:~rackspace-titan/nova/postgres-instance-type-id into lp:~hudson-openstack/nova/trunk

Proposed by Mark Washenberger
Status: Merged
Approved by: Dan Prince
Approved revision: 1045
Merged at revision: 1080
Proposed branch: lp:~rackspace-titan/nova/postgres-instance-type-id
Merge into: lp:~hudson-openstack/nova/trunk
Diff against target: 84 lines (+69/-1)
2 files modified
nova/db/sqlalchemy/migrate_repo/versions/017_make_instance_type_id_an_integer.py (+68/-0)
nova/db/sqlalchemy/models.py (+1/-1)
To merge this branch: bzr merge lp:~rackspace-titan/nova/postgres-instance-type-id
Reviewer Review Type Date Requested Status
Dan Prince (community) Approve
Rick Harris (community) Approve
Review via email: mp+60859@code.launchpad.net

Description of the change

Convert instance_type_ids in the instances table from strings to integers to enable joins with instance_types. This in particular fixes a problem when using postgresql.

To post a comment you must log in.
Revision history for this message
Rick Harris (rconradharris) wrote :

Looks great.

Tested upgrade and downgrade paths with good and bad data. All worked as expected.

Just a thought:

Would it be useful to log at the error-level any instances that weren't properly converted over, e.g.

  LOG.error("Instance %s did not have instance_type_id converted to an int because its value is" % (instance.id, instance.instance_type_id))

review: Approve
Revision history for this message
Dan Prince (dan-prince) wrote :

So hey Mark. Kind of unfortunate Postgres doesn't cast this automatically within the alter table command. I just tinkered with a simple Postgres table and I have to do something like this to get it to work:

  ALTER TABLE instances ALTER COLUMN instance_type_id TYPE integer USING instance_type_id::int;

Initially I just tried a simple:

  ALTER TABLE instances ALTER COLUMN instance_type_id TYPE integer;

The second command gives a casting error.

In any case it looks like what you have done is the best we can do in terms of converting data in a database agnostic fashion.

Looks good.

review: Approve
Revision history for this message
Dan Prince (dan-prince) wrote :

Hey Mark,

Heads up. Your quote limit branch just went in so you need to bump the migration version from 016 to 017.

review: Needs Fixing
Revision history for this message
Mark Washenberger (markwash) wrote :

Bumped the version and added some error logging. Should be good to go now, although if any of the other db migrations go in before this I suppose I will have to change filenames again.

Revision history for this message
Dan Prince (dan-prince) wrote :

Hey Mark.

Looks good now.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'nova/db/sqlalchemy/migrate_repo/versions/017_make_instance_type_id_an_integer.py'
2--- nova/db/sqlalchemy/migrate_repo/versions/017_make_instance_type_id_an_integer.py 1970-01-01 00:00:00 +0000
3+++ nova/db/sqlalchemy/migrate_repo/versions/017_make_instance_type_id_an_integer.py 2011-05-17 16:37:31 +0000
4@@ -0,0 +1,68 @@
5+from sqlalchemy import Column, Integer, MetaData, String, Table
6+from nova import log as logging
7+
8+meta = MetaData()
9+
10+
11+def upgrade(migrate_engine):
12+ meta.bind = migrate_engine
13+ instances = Table('instances', meta, autoload=True,
14+ autoload_with=migrate_engine)
15+
16+ types = {}
17+ for instance in migrate_engine.execute(instances.select()):
18+ if instance.instance_type_id is None:
19+ types[instance.id] = None
20+ continue
21+ try:
22+ types[instance.id] = int(instance.instance_type_id)
23+ except ValueError:
24+ logging.warn("Instance %s did not have instance_type_id "
25+ "converted to an integer because its value is %s" %
26+ (instance.id, instance.instance_type_id))
27+ types[instance.id] = None
28+
29+ integer_column = Column('instance_type_id_int', Integer(), nullable=True)
30+ string_column = instances.c.instance_type_id
31+
32+ integer_column.create(instances)
33+ for instance_id, instance_type_id in types.iteritems():
34+ update = instances.update().\
35+ where(instances.c.id == instance_id).\
36+ values(instance_type_id_int=instance_type_id)
37+ migrate_engine.execute(update)
38+
39+ string_column.alter(name='instance_type_id_str')
40+ integer_column.alter(name='instance_type_id')
41+ string_column.drop()
42+
43+
44+def downgrade(migrate_engine):
45+ meta.bind = migrate_engine
46+ instances = Table('instances', meta, autoload=True,
47+ autoload_with=migrate_engine)
48+
49+ integer_column = instances.c.instance_type_id
50+ string_column = Column('instance_type_id_str',
51+ String(length=255, convert_unicode=False,
52+ assert_unicode=None, unicode_error=None,
53+ _warn_on_bytestring=False),
54+ nullable=True)
55+
56+ types = {}
57+ for instance in migrate_engine.execute(instances.select()):
58+ if instance.instance_type_id is None:
59+ types[instance.id] = None
60+ else:
61+ types[instance.id] = str(instance.instance_type_id)
62+
63+ string_column.create(instances)
64+ for instance_id, instance_type_id in types.iteritems():
65+ update = instances.update().\
66+ where(instances.c.id == instance_id).\
67+ values(instance_type_id_str=instance_type_id)
68+ migrate_engine.execute(update)
69+
70+ integer_column.alter(name='instance_type_id_int')
71+ string_column.alter(name='instance_type_id')
72+ integer_column.drop()
73
74=== modified file 'nova/db/sqlalchemy/models.py'
75--- nova/db/sqlalchemy/models.py 2011-05-12 06:27:47 +0000
76+++ nova/db/sqlalchemy/models.py 2011-05-17 16:37:31 +0000
77@@ -209,7 +209,7 @@
78 hostname = Column(String(255))
79 host = Column(String(255)) # , ForeignKey('hosts.id'))
80
81- instance_type_id = Column(String(255))
82+ instance_type_id = Column(Integer)
83
84 user_data = Column(Text)
85