Merge "Add extra data to Stack table for Convergence."
This commit is contained in:
commit
7f0ff06247
@ -416,14 +416,21 @@ def stack_create(context, values):
|
||||
def stack_update(context, stack_id, values):
|
||||
stack = stack_get(context, stack_id)
|
||||
|
||||
if not stack:
|
||||
if stack is None:
|
||||
raise exception.NotFound(_('Attempt to update a stack with id: '
|
||||
'%(id)s %(msg)s') % {
|
||||
'id': stack_id,
|
||||
'msg': 'that does not exist'})
|
||||
|
||||
stack.update(values)
|
||||
stack.save(_session(context))
|
||||
session = _session(context)
|
||||
rows_updated = (session.query(models.Stack)
|
||||
.filter(models.Stack.id == stack.id)
|
||||
.filter(models.Stack.current_traversal
|
||||
== stack.current_traversal)
|
||||
.update(values, synchronize_session=False))
|
||||
session.expire_all()
|
||||
|
||||
return (rows_updated is not None and rows_updated > 0)
|
||||
|
||||
|
||||
def stack_delete(context, stack_id):
|
||||
|
140
heat/db/sqlalchemy/migrate_repo/versions/055_stack_convg_data.py
Normal file
140
heat/db/sqlalchemy/migrate_repo/versions/055_stack_convg_data.py
Normal file
@ -0,0 +1,140 @@
|
||||
#
|
||||
# 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.
|
||||
|
||||
import sqlalchemy
|
||||
|
||||
from heat.db.sqlalchemy import types as heat_db_types
|
||||
from heat.db.sqlalchemy import utils as migrate_utils
|
||||
|
||||
from migrate import ForeignKeyConstraint
|
||||
|
||||
|
||||
def upgrade(migrate_engine):
|
||||
if migrate_engine.name == 'sqlite':
|
||||
_upgrade_sqlite(migrate_engine)
|
||||
return
|
||||
|
||||
meta = sqlalchemy.MetaData(bind=migrate_engine)
|
||||
|
||||
stack = sqlalchemy.Table('stack', meta, autoload=True)
|
||||
|
||||
prev_raw_template_id = sqlalchemy.Column('prev_raw_template_id',
|
||||
sqlalchemy.Integer)
|
||||
current_traversal = sqlalchemy.Column('current_traversal',
|
||||
sqlalchemy.String(36))
|
||||
current_deps = sqlalchemy.Column('current_deps', heat_db_types.Json)
|
||||
prev_raw_template_id.create(stack)
|
||||
current_traversal.create(stack)
|
||||
current_deps.create(stack)
|
||||
|
||||
raw_template = sqlalchemy.Table('raw_template', meta, autoload=True)
|
||||
fkey = ForeignKeyConstraint(columns=[stack.c.prev_raw_template_id],
|
||||
refcolumns=[raw_template.c.id],
|
||||
name='prev_raw_template_ref')
|
||||
fkey.create()
|
||||
|
||||
|
||||
def _upgrade_sqlite(migrate_engine):
|
||||
meta = sqlalchemy.MetaData(bind=migrate_engine)
|
||||
stack = sqlalchemy.Table('stack', meta, autoload=True)
|
||||
table_name = stack.name
|
||||
|
||||
newcols = [
|
||||
sqlalchemy.Column('prev_raw_template_id', sqlalchemy.Integer,
|
||||
sqlalchemy.ForeignKey('raw_template.id',
|
||||
name='prev_raw_template_ref')),
|
||||
sqlalchemy.Column('current_traversal', sqlalchemy.String(36)),
|
||||
sqlalchemy.Column('current_deps', heat_db_types.Json),
|
||||
]
|
||||
|
||||
new_stack = migrate_utils.clone_table(table_name + '__tmp__', stack,
|
||||
meta, newcols=newcols)
|
||||
|
||||
# migrate stacks into new table
|
||||
stacks = list(stack.select().order_by(
|
||||
sqlalchemy.sql.expression.asc(stack.c.created_at))
|
||||
.execute())
|
||||
colnames = [c.name for c in stack.columns]
|
||||
for s in stacks:
|
||||
values = dict(zip(colnames,
|
||||
map(lambda colname: getattr(s, colname),
|
||||
colnames)))
|
||||
migrate_engine.execute(new_stack.insert(values))
|
||||
|
||||
# Drop old tables and rename new ones
|
||||
stack.drop()
|
||||
new_stack.rename('stack')
|
||||
|
||||
# add the indexes back
|
||||
_add_indexes(migrate_engine, new_stack)
|
||||
|
||||
|
||||
def downgrade(migrate_engine):
|
||||
meta = sqlalchemy.MetaData(bind=migrate_engine)
|
||||
|
||||
stack = sqlalchemy.Table('stack', meta, autoload=True)
|
||||
|
||||
if migrate_engine.name == 'sqlite':
|
||||
_downgrade_sqlite(migrate_engine)
|
||||
else:
|
||||
raw_template = sqlalchemy.Table('raw_template', meta, autoload=True)
|
||||
fkey = ForeignKeyConstraint(columns=[stack.c.prev_raw_template_id],
|
||||
refcolumns=[raw_template.c.id],
|
||||
name='prev_raw_template_ref')
|
||||
fkey.drop()
|
||||
stack.c.prev_raw_template_id.drop()
|
||||
stack.c.current_traversal.drop()
|
||||
stack.c.current_deps.drop()
|
||||
|
||||
|
||||
def _downgrade_sqlite(migrate_engine):
|
||||
meta = sqlalchemy.MetaData(bind=migrate_engine)
|
||||
stack = sqlalchemy.Table('stack', meta, autoload=True)
|
||||
table_name = stack.name
|
||||
# ignore CheckConstraints and FK Constraint on prev_raw_template_id.
|
||||
ignorecols = [
|
||||
stack.c.prev_raw_template_id.name,
|
||||
stack.c.current_traversal.name,
|
||||
stack.c.current_deps.name,
|
||||
]
|
||||
ignorecons = [
|
||||
'prev_raw_template_ref',
|
||||
]
|
||||
new_stack = migrate_utils.clone_table(table_name + '__tmp__', stack, meta,
|
||||
ignorecols=ignorecols,
|
||||
ignorecons=ignorecons)
|
||||
|
||||
migrate_data = """
|
||||
INSERT INTO %s
|
||||
SELECT id, created_at, updated_at, name, raw_template_id,
|
||||
user_creds_id, username, owner_id, status, status_reason,
|
||||
parameters, timeout, tenant, disable_rollback, action,
|
||||
deleted_at, stack_user_project_id, backup, nested_depth,
|
||||
convergence
|
||||
FROM stack;""" % new_stack.name
|
||||
migrate_engine.execute(migrate_data)
|
||||
stack.drop()
|
||||
new_stack.rename(table_name)
|
||||
# add the indexes back to new table
|
||||
_add_indexes(migrate_engine, new_stack)
|
||||
|
||||
|
||||
def _add_indexes(migrate_engine, stack):
|
||||
name_index = sqlalchemy.Index('ix_stack_name',
|
||||
stack.c.name,
|
||||
mysql_length=255)
|
||||
tenant_index = sqlalchemy.Index('ix_stack_tenant',
|
||||
stack.c.tenant,
|
||||
mysql_length=255)
|
||||
name_index.create(migrate_engine)
|
||||
tenant_index.create(migrate_engine)
|
@ -141,7 +141,14 @@ class Stack(BASE, HeatBase, SoftDelete, StateAware):
|
||||
sqlalchemy.Integer,
|
||||
sqlalchemy.ForeignKey('raw_template.id'),
|
||||
nullable=False)
|
||||
raw_template = relationship(RawTemplate, backref=backref('stack'))
|
||||
raw_template = relationship(RawTemplate, backref=backref('stack'),
|
||||
foreign_keys=[raw_template_id])
|
||||
prev_raw_template_id = sqlalchemy.Column(
|
||||
'prev_raw_template_id',
|
||||
sqlalchemy.Integer,
|
||||
sqlalchemy.ForeignKey('raw_template.id'))
|
||||
prev_raw_template = relationship(RawTemplate,
|
||||
foreign_keys=[prev_raw_template_id])
|
||||
username = sqlalchemy.Column(sqlalchemy.String(256))
|
||||
tenant = sqlalchemy.Column(sqlalchemy.String(256))
|
||||
parameters = sqlalchemy.Column('parameters', types.Json)
|
||||
@ -158,6 +165,9 @@ class Stack(BASE, HeatBase, SoftDelete, StateAware):
|
||||
convergence = sqlalchemy.Column('convergence', sqlalchemy.Boolean)
|
||||
tags = relationship(StackTag, cascade="all,delete",
|
||||
backref=backref('stack'))
|
||||
current_traversal = sqlalchemy.Column('current_traversal',
|
||||
sqlalchemy.String(36))
|
||||
current_deps = sqlalchemy.Column('current_deps', types.Json)
|
||||
|
||||
# Override timestamp column to store the correct value: it should be the
|
||||
# time the create/update call was issued, not the time the DB entry is
|
||||
|
@ -79,7 +79,8 @@ class Stack(collections.Mapping):
|
||||
created_time=None, updated_time=None,
|
||||
user_creds_id=None, tenant_id=None,
|
||||
use_stored_context=False, username=None,
|
||||
nested_depth=0, strict_validate=True, convergence=False):
|
||||
nested_depth=0, strict_validate=True, convergence=False,
|
||||
current_traversal=None):
|
||||
'''
|
||||
Initialise from a context, name, Template object and (optionally)
|
||||
Environment object. The database ID may also be initialised, if the
|
||||
@ -121,6 +122,7 @@ class Stack(collections.Mapping):
|
||||
self.nested_depth = nested_depth
|
||||
self.strict_validate = strict_validate
|
||||
self.convergence = convergence
|
||||
self.current_traversal = current_traversal
|
||||
|
||||
if use_stored_context:
|
||||
self.context = self.stored_context()
|
||||
@ -322,13 +324,14 @@ class Stack(collections.Mapping):
|
||||
updated_time=stack.updated_at,
|
||||
user_creds_id=stack.user_creds_id, tenant_id=stack.tenant,
|
||||
use_stored_context=use_stored_context,
|
||||
username=stack.username, convergence=stack.convergence)
|
||||
username=stack.username, convergence=stack.convergence,
|
||||
current_traversal=stack.current_traversal)
|
||||
|
||||
@profiler.trace('Stack.store', hide_args=False)
|
||||
def store(self, backup=False):
|
||||
'''
|
||||
Store the stack in the database and return its ID
|
||||
If self.id is set, we update the existing stack
|
||||
If self.id is set, we update the existing stack.
|
||||
'''
|
||||
s = {
|
||||
'name': self._backup_name() if backup else self.name,
|
||||
@ -347,7 +350,8 @@ class Stack(collections.Mapping):
|
||||
'user_creds_id': self.user_creds_id,
|
||||
'backup': backup,
|
||||
'nested_depth': self.nested_depth,
|
||||
'convergence': self.convergence
|
||||
'convergence': self.convergence,
|
||||
'current_traversal': self.current_traversal,
|
||||
}
|
||||
if self.id:
|
||||
db_api.stack_update(self.context, self.id, s)
|
||||
|
@ -403,6 +403,11 @@ class HeatMigrationsCheckers(test_migrations.WalkVersionsMixin,
|
||||
def _check_052(self, engine, data):
|
||||
self.assertColumnExists(engine, 'stack', 'convergence')
|
||||
|
||||
def _check_055(self, engine, data):
|
||||
self.assertColumnExists(engine, 'stack', 'prev_raw_template_id')
|
||||
self.assertColumnExists(engine, 'stack', 'current_traversal')
|
||||
self.assertColumnExists(engine, 'stack', 'current_deps')
|
||||
|
||||
|
||||
class TestHeatMigrationsMySQL(HeatMigrationsCheckers,
|
||||
test_base.MySQLOpportunisticTestCase):
|
||||
|
@ -1153,7 +1153,8 @@ class StackTest(common.HeatTestCase):
|
||||
tenant_id='test_tenant_id',
|
||||
use_stored_context=False,
|
||||
username=mox.IgnoreArg(),
|
||||
convergence=False)
|
||||
convergence=False,
|
||||
current_traversal=None)
|
||||
|
||||
self.m.ReplayAll()
|
||||
parser.Stack.load(self.ctx, stack_id=self.stack.id,
|
||||
|
@ -1366,6 +1366,7 @@ class DBAPIStackTest(common.HeatTestCase):
|
||||
'status': 'failed',
|
||||
'status_reason': "update_failed",
|
||||
'timeout': '90',
|
||||
'current_traversal': 'dummy-uuid',
|
||||
}
|
||||
db_api.stack_update(self.ctx, stack.id, values)
|
||||
stack = db_api.stack_get(self.ctx, stack.id)
|
||||
@ -1373,7 +1374,8 @@ class DBAPIStackTest(common.HeatTestCase):
|
||||
self.assertEqual('update', stack.action)
|
||||
self.assertEqual('failed', stack.status)
|
||||
self.assertEqual('update_failed', stack.status_reason)
|
||||
self.assertEqual('90', stack.timeout)
|
||||
self.assertEqual(90, stack.timeout)
|
||||
self.assertEqual('dummy-uuid', stack.current_traversal)
|
||||
|
||||
self.assertRaises(exception.NotFound, db_api.stack_update, self.ctx,
|
||||
UUID2, values)
|
||||
|
Loading…
Reference in New Issue
Block a user