Add a config option to enable Convergence
This patch adds column 'convergence' to stack table and configuration option 'convergence_engine'. If 'convergence_engine' equals True, new stacks are created, updated and backuped with convergence column equals True and old stacks are updated and backuped with convergence column equals False. Otherwise convergence column equals False. blueprint convergence-config-option Change-Id: I34d6fa3a0e387140914f5060c06be890640a970f
This commit is contained in:
parent
fb32508af5
commit
6ec2759324
@ -151,6 +151,11 @@ engine_opts = [
|
||||
cfg.BoolOpt('enable_stack_adopt',
|
||||
default=False,
|
||||
help=_('Enable the preview Stack Adopt feature.')),
|
||||
cfg.BoolOpt('convergence_engine',
|
||||
default=False,
|
||||
help=_('Enables engine with convergence architecture. All '
|
||||
'stacks with this option will be created using '
|
||||
'convergence engine .')),
|
||||
cfg.StrOpt('onready',
|
||||
help=_('Deprecated.'))]
|
||||
|
||||
|
@ -0,0 +1,63 @@
|
||||
#
|
||||
# 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
|
||||
|
||||
|
||||
def upgrade(migrate_engine):
|
||||
meta = sqlalchemy.MetaData(bind=migrate_engine)
|
||||
|
||||
stack = sqlalchemy.Table('stack', meta, autoload=True)
|
||||
convergence = sqlalchemy.Column('convergence', sqlalchemy.Boolean,
|
||||
default=False)
|
||||
convergence.create(stack)
|
||||
|
||||
|
||||
def downgrade(migrate_engine):
|
||||
meta = sqlalchemy.MetaData(bind=migrate_engine)
|
||||
|
||||
stack = sqlalchemy.Table('stack', meta, autoload=True)
|
||||
if migrate_engine.name == 'sqlite':
|
||||
_downgrade_052_sqlite(migrate_engine, meta, stack)
|
||||
else:
|
||||
stack.c.convergence.drop()
|
||||
|
||||
|
||||
def _downgrade_052_sqlite(migrate_engine, metadata, table):
|
||||
|
||||
table_name = table.name
|
||||
|
||||
constraints = [
|
||||
c.copy() for c in table.constraints
|
||||
if not isinstance(c, sqlalchemy.CheckConstraint)
|
||||
]
|
||||
columns = [c.copy() for c in table.columns if c.name != "convergence"]
|
||||
|
||||
new_table = sqlalchemy.Table(table_name + "__tmp__", metadata,
|
||||
*(columns + constraints))
|
||||
new_table.create()
|
||||
|
||||
migrate_data = """
|
||||
INSERT INTO %s__tmp__
|
||||
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,
|
||||
tags
|
||||
FROM stack;""" % table_name
|
||||
|
||||
migrate_engine.execute(migrate_data)
|
||||
|
||||
table.drop()
|
||||
|
||||
new_table.rename(table_name)
|
@ -136,6 +136,7 @@ class Stack(BASE, HeatBase, SoftDelete, StateAware):
|
||||
backup = sqlalchemy.Column('backup', sqlalchemy.Boolean)
|
||||
nested_depth = sqlalchemy.Column('nested_depth', sqlalchemy.Integer)
|
||||
tags = sqlalchemy.Column('tags', types.Json)
|
||||
convergence = sqlalchemy.Column('convergence', sqlalchemy.Boolean)
|
||||
|
||||
# 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
|
||||
|
@ -508,7 +508,8 @@ class EngineService(service.Service):
|
||||
def _parse_template_and_validate_stack(self, cnxt, stack_name, template,
|
||||
params, files, args, owner_id=None,
|
||||
nested_depth=0, user_creds_id=None,
|
||||
stack_user_project_id=None):
|
||||
stack_user_project_id=None,
|
||||
convergence=False):
|
||||
# If it is stack-adopt, use parameters from adopt_stack_data
|
||||
common_params = api.extract_args(args)
|
||||
if (rpc_api.PARAM_ADOPT_STACK_DATA in common_params and
|
||||
@ -531,6 +532,7 @@ class EngineService(service.Service):
|
||||
nested_depth=nested_depth,
|
||||
user_creds_id=user_creds_id,
|
||||
stack_user_project_id=stack_user_project_id,
|
||||
convergence=convergence,
|
||||
**common_params)
|
||||
|
||||
self._validate_deferred_auth_context(cnxt, stack)
|
||||
@ -554,12 +556,18 @@ class EngineService(service.Service):
|
||||
"""
|
||||
|
||||
LOG.info(_LI('previewing stack %s'), stack_name)
|
||||
|
||||
conv_eng = cfg.CONF.convergence_engine
|
||||
if conv_eng:
|
||||
raise exception.NotSupported(feature=_('Convergence engine'))
|
||||
|
||||
stack = self._parse_template_and_validate_stack(cnxt,
|
||||
stack_name,
|
||||
template,
|
||||
params,
|
||||
files,
|
||||
args)
|
||||
args,
|
||||
convergence=conv_eng)
|
||||
|
||||
return api.format_stack_preview(stack)
|
||||
|
||||
@ -612,16 +620,13 @@ class EngineService(service.Service):
|
||||
else:
|
||||
LOG.info(_LI("Stack create failed, status %s"), stack.status)
|
||||
|
||||
stack = self._parse_template_and_validate_stack(cnxt,
|
||||
stack_name,
|
||||
template,
|
||||
params,
|
||||
files,
|
||||
args,
|
||||
owner_id,
|
||||
nested_depth,
|
||||
user_creds_id,
|
||||
stack_user_project_id)
|
||||
convergence = cfg.CONF.convergence_engine
|
||||
if convergence:
|
||||
raise exception.NotSupported(feature=_('Convergence engine'))
|
||||
|
||||
stack = self._parse_template_and_validate_stack(
|
||||
cnxt, stack_name, template, params, files, args, owner_id,
|
||||
nested_depth, user_creds_id, stack_user_project_id, convergence)
|
||||
|
||||
stack.store()
|
||||
|
||||
@ -667,6 +672,7 @@ class EngineService(service.Service):
|
||||
raise exception.RequestLimitExceeded(
|
||||
message=exception.StackResourceLimitExceeded.msg_fmt)
|
||||
stack_name = current_stack.name
|
||||
convergence = current_stack.convergence
|
||||
common_params = api.extract_args(args)
|
||||
common_params.setdefault(rpc_api.PARAM_TIMEOUT,
|
||||
current_stack.timeout_mins)
|
||||
@ -678,7 +684,8 @@ class EngineService(service.Service):
|
||||
current_stack.env,
|
||||
args.get(rpc_api.PARAM_CLEAR_PARAMETERS, []))
|
||||
updated_stack = parser.Stack(cnxt, stack_name, tmpl,
|
||||
env, **common_params)
|
||||
env, convergence=convergence,
|
||||
**common_params)
|
||||
updated_stack.parameters.set_stack_id(current_stack.identifier())
|
||||
|
||||
self._validate_deferred_auth_context(cnxt, updated_stack)
|
||||
|
@ -79,7 +79,7 @@ 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):
|
||||
nested_depth=0, strict_validate=True, convergence=False):
|
||||
'''
|
||||
Initialise from a context, name, Template object and (optionally)
|
||||
Environment object. The database ID may also be initialised, if the
|
||||
@ -119,6 +119,7 @@ class Stack(collections.Mapping):
|
||||
self.user_creds_id = user_creds_id
|
||||
self.nested_depth = nested_depth
|
||||
self.strict_validate = strict_validate
|
||||
self.convergence = convergence
|
||||
|
||||
if use_stored_context:
|
||||
self.context = self.stored_context()
|
||||
@ -295,7 +296,7 @@ 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)
|
||||
username=stack.username, convergence=stack.convergence)
|
||||
|
||||
@profiler.trace('Stack.store', hide_args=False)
|
||||
def store(self, backup=False):
|
||||
@ -319,7 +320,8 @@ class Stack(collections.Mapping):
|
||||
'updated_at': self.updated_time,
|
||||
'user_creds_id': self.user_creds_id,
|
||||
'backup': backup,
|
||||
'nested_depth': self.nested_depth
|
||||
'nested_depth': self.nested_depth,
|
||||
'convergence': self.convergence
|
||||
}
|
||||
if self.id:
|
||||
db_api.stack_update(self.context, self.id, s)
|
||||
@ -683,7 +685,8 @@ class Stack(collections.Mapping):
|
||||
elif create_if_missing:
|
||||
prev = type(self)(self.context, self.name, copy.deepcopy(self.t),
|
||||
self.env, owner_id=self.id,
|
||||
user_creds_id=self.user_creds_id)
|
||||
user_creds_id=self.user_creds_id,
|
||||
convergence=self.convergence)
|
||||
prev.store(backup=True)
|
||||
LOG.debug('Created new backup stack')
|
||||
return prev
|
||||
@ -755,7 +758,7 @@ class Stack(collections.Mapping):
|
||||
# Oldstack is useless when the action is not UPDATE , so we don't
|
||||
# need to build it, this can avoid some unexpected errors.
|
||||
oldstack = Stack(self.context, self.name, copy.deepcopy(self.t),
|
||||
self.env)
|
||||
self.env, convergence=self.convergence)
|
||||
backup_stack = self._backup_stack()
|
||||
try:
|
||||
update_task = update.StackUpdate(
|
||||
|
@ -453,7 +453,8 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
|
||||
parser.Stack(self.ctx, stack.name,
|
||||
stack.t, stack.env, owner_id=None,
|
||||
nested_depth=0, user_creds_id=None,
|
||||
stack_user_project_id=None).AndReturn(stack)
|
||||
stack_user_project_id=None,
|
||||
convergence=False).AndReturn(stack)
|
||||
|
||||
self.m.StubOutWithMock(stack, 'validate')
|
||||
stack.validate().AndReturn(None)
|
||||
@ -507,7 +508,8 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
|
||||
owner_id=None,
|
||||
nested_depth=0,
|
||||
user_creds_id=None,
|
||||
stack_user_project_id=None).AndReturn(stack)
|
||||
stack_user_project_id=None,
|
||||
convergence=False).AndReturn(stack)
|
||||
|
||||
self.m.StubOutWithMock(stack, 'validate')
|
||||
stack.validate().AndRaise(exception.StackValidationFailed(
|
||||
@ -620,6 +622,15 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
|
||||
self.man.create_stack,
|
||||
self.ctx, stack_name, stack.t.t, {}, None, {})
|
||||
|
||||
def test_stack_create_enabled_convergence_engine(self):
|
||||
cfg.CONF.set_override('convergence_engine', True)
|
||||
ex = self.assertRaises(dispatcher.ExpectedException,
|
||||
self.man.create_stack, self.ctx, 'test',
|
||||
wp_template, {}, None, {})
|
||||
self.assertEqual(exception.NotSupported, ex.exc_info[0])
|
||||
self.assertEqual('Convergence engine is not supported.',
|
||||
six.text_type(ex.exc_info[1]))
|
||||
|
||||
def test_stack_create_invalid_resource_name(self):
|
||||
stack_name = 'service_create_test_stack_invalid_res'
|
||||
stack = get_wordpress_stack(stack_name, self.ctx)
|
||||
@ -664,14 +675,16 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
|
||||
parser.Stack(ctx_no_pwd, stack.name,
|
||||
stack.t, stack.env, owner_id=None,
|
||||
nested_depth=0, user_creds_id=None,
|
||||
stack_user_project_id=None).AndReturn(stack)
|
||||
stack_user_project_id=None,
|
||||
convergence=False).AndReturn(stack)
|
||||
|
||||
templatem.Template(template, files=None).AndReturn(stack.t)
|
||||
environment.Environment(params).AndReturn(stack.env)
|
||||
parser.Stack(ctx_no_user, stack.name,
|
||||
stack.t, stack.env, owner_id=None,
|
||||
nested_depth=0, user_creds_id=None,
|
||||
stack_user_project_id=None).AndReturn(stack)
|
||||
stack_user_project_id=None,
|
||||
convergence=False).AndReturn(stack)
|
||||
|
||||
self.m.ReplayAll()
|
||||
|
||||
@ -720,7 +733,8 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
|
||||
owner_id=None,
|
||||
nested_depth=0,
|
||||
user_creds_id=None,
|
||||
stack_user_project_id=None).AndReturn(stack)
|
||||
stack_user_project_id=None,
|
||||
convergence=False).AndReturn(stack)
|
||||
|
||||
self.m.ReplayAll()
|
||||
|
||||
@ -991,7 +1005,8 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
|
||||
environment.Environment(params).AndReturn(stack.env)
|
||||
parser.Stack(self.ctx, stack.name,
|
||||
stack.t, stack.env,
|
||||
timeout_mins=60, disable_rollback=True).AndReturn(stack)
|
||||
timeout_mins=60, disable_rollback=True,
|
||||
convergence=False).AndReturn(stack)
|
||||
|
||||
self.m.StubOutWithMock(stack, 'validate')
|
||||
stack.validate().AndReturn(None)
|
||||
@ -1039,7 +1054,8 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
|
||||
environment.Environment(no_params).AndReturn(old_stack.env)
|
||||
parser.Stack(self.ctx, stack.name,
|
||||
stack.t, old_stack.env,
|
||||
timeout_mins=60, disable_rollback=True).AndReturn(stack)
|
||||
timeout_mins=60, disable_rollback=True,
|
||||
convergence=False).AndReturn(stack)
|
||||
|
||||
self.m.StubOutWithMock(stack, 'validate')
|
||||
stack.validate().AndReturn(None)
|
||||
@ -1082,7 +1098,8 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
|
||||
environment.Environment(params).AndReturn(stack.env)
|
||||
parser.Stack(self.ctx, stack.name,
|
||||
stack.t, stack.env,
|
||||
timeout_mins=1, disable_rollback=False).AndReturn(stack)
|
||||
timeout_mins=1, disable_rollback=False,
|
||||
convergence=False).AndReturn(stack)
|
||||
|
||||
self.m.StubOutWithMock(stack, 'validate')
|
||||
stack.validate().AndReturn(None)
|
||||
@ -1159,7 +1176,8 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
|
||||
environment.Environment(params).AndReturn(stack.env)
|
||||
parser.Stack(self.ctx, stack.name,
|
||||
stack.t, stack.env,
|
||||
timeout_mins=60, disable_rollback=True).AndReturn(stack)
|
||||
timeout_mins=60, disable_rollback=True,
|
||||
convergence=False).AndReturn(stack)
|
||||
|
||||
self.m.StubOutWithMock(stack, 'validate')
|
||||
stack.validate().AndReturn(None)
|
||||
@ -1279,7 +1297,8 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
|
||||
environment.Environment(params).AndReturn(stack.env)
|
||||
parser.Stack(self.ctx, stack.name,
|
||||
stack.t, stack.env,
|
||||
timeout_mins=60, disable_rollback=True).AndReturn(stack)
|
||||
timeout_mins=60, disable_rollback=True,
|
||||
convergence=False).AndReturn(stack)
|
||||
|
||||
self.m.StubOutWithMock(stack, 'validate')
|
||||
stack.validate().AndRaise(exception.StackValidationFailed(
|
||||
@ -1335,8 +1354,8 @@ class StackServiceCreateUpdateDeleteTest(common.HeatTestCase):
|
||||
environment.Environment(params).AndReturn(old_stack.env)
|
||||
parser.Stack(self.ctx, old_stack.name,
|
||||
old_stack.t, old_stack.env,
|
||||
timeout_mins=60, disable_rollback=True
|
||||
).AndReturn(old_stack)
|
||||
timeout_mins=60, disable_rollback=True,
|
||||
convergence=False).AndReturn(old_stack)
|
||||
|
||||
self.m.ReplayAll()
|
||||
|
||||
|
@ -1139,7 +1139,8 @@ class StackTest(common.HeatTestCase):
|
||||
user_creds_id=stack.user_creds_id,
|
||||
tenant_id='test_tenant_id',
|
||||
use_stored_context=False,
|
||||
username=mox.IgnoreArg())
|
||||
username=mox.IgnoreArg(),
|
||||
convergence=False)
|
||||
|
||||
self.m.ReplayAll()
|
||||
parser.Stack.load(self.ctx, stack_id=self.stack.id,
|
||||
|
Loading…
Reference in New Issue
Block a user