Store stack domain credentials for deployments
In order to allow stack domain credentials to be used for deployment API operations, the stack_user_project_id needs to be passed when a deployment resource is created and stored in the database. stack_user_project_id can then be used to compare to the context tenant_id, just as for stack_get. This change is needed since the blueprint hot-software-config and blueprint instance-users landed at the same time. Some stack operations can now be performed with credentials which are scoped to a single resource. It would be very useful to allow these credentials to be used for that polling for deployment metadata too. Closes-Bug: #1293234 Change-Id: Iea9d8bfe216d17fa2d3a9e9251102292be48486d
This commit is contained in:
parent
66d701564c
commit
323ed2566c
@ -72,7 +72,7 @@ class SoftwareDeploymentController(object):
|
||||
"""
|
||||
create_data = dict((k, body.get(k)) for k in (
|
||||
'config_id', 'server_id', 'input_values',
|
||||
'action', 'status', 'status_reason'))
|
||||
'action', 'status', 'status_reason', 'stack_user_project_id'))
|
||||
|
||||
sd = self.rpc_client.create_software_deployment(req.context,
|
||||
**create_data)
|
||||
|
@ -662,7 +662,8 @@ def software_deployment_create(context, values):
|
||||
def software_deployment_get(context, deployment_id):
|
||||
result = model_query(context, models.SoftwareDeployment).get(deployment_id)
|
||||
if (result is not None and context is not None and
|
||||
result.tenant != context.tenant_id):
|
||||
context.tenant_id not in (result.tenant,
|
||||
result.stack_user_project_id)):
|
||||
result = None
|
||||
|
||||
if not result:
|
||||
@ -672,9 +673,13 @@ def software_deployment_get(context, deployment_id):
|
||||
|
||||
|
||||
def software_deployment_get_all(context, server_id=None):
|
||||
query = model_query(context, models.SoftwareDeployment).\
|
||||
filter_by(tenant=context.tenant_id).\
|
||||
order_by(models.SoftwareDeployment.created_at)
|
||||
sd = models.SoftwareDeployment
|
||||
query = model_query(context, sd).\
|
||||
filter(sqlalchemy.or_(
|
||||
sd.tenant == context.tenant_id,
|
||||
sd.stack_user_project_id == context.tenant_id
|
||||
)).\
|
||||
order_by(sd.created_at)
|
||||
if server_id:
|
||||
query = query.filter_by(server_id=server_id)
|
||||
return query.all()
|
||||
|
@ -0,0 +1,31 @@
|
||||
|
||||
# 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('software_deployment', meta, autoload=True)
|
||||
# Align with 64 character length used in keystone project table
|
||||
stack_user_project_id = sqlalchemy.Column('stack_user_project_id',
|
||||
sqlalchemy.String(length=64))
|
||||
stack_user_project_id.create(stack)
|
||||
|
||||
|
||||
def downgrade(migrate_engine):
|
||||
meta = sqlalchemy.MetaData(bind=migrate_engine)
|
||||
|
||||
stack = sqlalchemy.Table('software_deployment', meta, autoload=True)
|
||||
stack.c.stack_user_project_id.drop()
|
@ -299,6 +299,8 @@ class SoftwareDeployment(BASE, HeatBase):
|
||||
output_values = sqlalchemy.Column('output_values', Json)
|
||||
tenant = sqlalchemy.Column(
|
||||
'tenant', sqlalchemy.String(256), nullable=False)
|
||||
stack_user_project_id = sqlalchemy.Column(sqlalchemy.String(64),
|
||||
nullable=True)
|
||||
action = sqlalchemy.Column('action', sqlalchemy.String(255))
|
||||
status = sqlalchemy.Column('status', sqlalchemy.String(255))
|
||||
status_reason = sqlalchemy.Column('status_reason', sqlalchemy.String(255))
|
||||
|
@ -173,7 +173,8 @@ class SoftwareDeployment(signal_responder.SignalResponder):
|
||||
props = {
|
||||
'config_id': config_id,
|
||||
'server_id': properties[SoftwareDeployment.SERVER],
|
||||
'action': action
|
||||
'action': action,
|
||||
'stack_user_project_id': self.stack.stack_user_project_id
|
||||
}
|
||||
|
||||
if self._signal_transport_none():
|
||||
|
@ -1130,12 +1130,14 @@ class EngineService(service.Service):
|
||||
@request_context
|
||||
def create_software_deployment(self, cnxt, server_id, config_id,
|
||||
input_values, action, status,
|
||||
status_reason):
|
||||
status_reason, stack_user_project_id):
|
||||
|
||||
sd = db_api.software_deployment_create(cnxt, {
|
||||
'config_id': config_id,
|
||||
'server_id': server_id,
|
||||
'input_values': input_values,
|
||||
'tenant': cnxt.tenant_id,
|
||||
'stack_user_project_id': stack_user_project_id,
|
||||
'action': action,
|
||||
'status': status,
|
||||
'status_reason': status_reason})
|
||||
|
@ -405,14 +405,17 @@ class EngineClient(heat.openstack.common.rpc.proxy.RpcProxy):
|
||||
|
||||
def create_software_deployment(self, cnxt, server_id, config_id=None,
|
||||
input_values={}, action='INIT',
|
||||
status='COMPLETE', status_reason=''):
|
||||
return self.call(cnxt, self.make_msg('create_software_deployment',
|
||||
server_id=server_id,
|
||||
config_id=config_id,
|
||||
input_values=input_values,
|
||||
action=action,
|
||||
status=status,
|
||||
status_reason=status_reason))
|
||||
status='COMPLETE', status_reason='',
|
||||
stack_user_project_id=None):
|
||||
return self.call(cnxt, self.make_msg(
|
||||
'create_software_deployment',
|
||||
server_id=server_id,
|
||||
config_id=config_id,
|
||||
input_values=input_values,
|
||||
action=action,
|
||||
status=status,
|
||||
status_reason=status_reason,
|
||||
stack_user_project_id=stack_user_project_id))
|
||||
|
||||
def update_software_deployment(self, cnxt, deployment_id,
|
||||
config_id=None, input_values=None,
|
||||
|
@ -2586,14 +2586,15 @@ class SoftwareConfigServiceTest(HeatTestCase):
|
||||
status='COMPLETE', status_reason='',
|
||||
config_group=None,
|
||||
server_id=str(uuid.uuid4()),
|
||||
config_name=None):
|
||||
config_name=None,
|
||||
stack_user_project_id=None):
|
||||
if config_id is None:
|
||||
config = self._create_software_config(group=config_group,
|
||||
name=config_name)
|
||||
config_id = config['id']
|
||||
return self.engine.create_software_deployment(
|
||||
self.ctx, server_id, config_id, input_values,
|
||||
action, status, status_reason)
|
||||
action, status, status_reason, stack_user_project_id)
|
||||
|
||||
def test_list_software_deployments(self):
|
||||
deployment = self._create_software_deployment()
|
||||
@ -2611,15 +2612,22 @@ class SoftwareConfigServiceTest(HeatTestCase):
|
||||
|
||||
def test_metadata_software_deployments(self):
|
||||
server_id = str(uuid.uuid4())
|
||||
d1 = self._create_software_deployment(config_group='mygroup',
|
||||
server_id=server_id,
|
||||
config_name='02_second')
|
||||
d2 = self._create_software_deployment(config_group='mygroup',
|
||||
server_id=server_id,
|
||||
config_name='01_first')
|
||||
d3 = self._create_software_deployment(config_group='myothergroup',
|
||||
server_id=server_id,
|
||||
config_name='03_third')
|
||||
stack_user_project_id = str(uuid.uuid4())
|
||||
d1 = self._create_software_deployment(
|
||||
config_group='mygroup',
|
||||
server_id=server_id,
|
||||
config_name='02_second',
|
||||
stack_user_project_id=stack_user_project_id)
|
||||
d2 = self._create_software_deployment(
|
||||
config_group='mygroup',
|
||||
server_id=server_id,
|
||||
config_name='01_first',
|
||||
stack_user_project_id=stack_user_project_id)
|
||||
d3 = self._create_software_deployment(
|
||||
config_group='myothergroup',
|
||||
server_id=server_id,
|
||||
config_name='03_third',
|
||||
stack_user_project_id=stack_user_project_id)
|
||||
metadata = self.engine.metadata_software_deployments(
|
||||
self.ctx, server_id=server_id)
|
||||
self.assertEqual(3, len(metadata))
|
||||
@ -2637,6 +2645,19 @@ class SoftwareConfigServiceTest(HeatTestCase):
|
||||
self.ctx, server_id=str(uuid.uuid4()))
|
||||
self.assertEqual([], deployments)
|
||||
|
||||
# assert get results when the context tenant_id matches
|
||||
# the stored stack_user_project_id
|
||||
ctx = utils.dummy_context(tenant_id=stack_user_project_id)
|
||||
metadata = self.engine.metadata_software_deployments(
|
||||
ctx, server_id=server_id)
|
||||
self.assertEqual(3, len(metadata))
|
||||
|
||||
# assert get no results when the context tenant_id is unknown
|
||||
ctx = utils.dummy_context(tenant_id=str(uuid.uuid4()))
|
||||
metadata = self.engine.metadata_software_deployments(
|
||||
ctx, server_id=server_id)
|
||||
self.assertEqual(0, len(metadata))
|
||||
|
||||
def test_show_software_deployment(self):
|
||||
deployment_id = str(uuid.uuid4())
|
||||
self.assertRaises(exception.NotFound,
|
||||
|
@ -242,13 +242,15 @@ class EngineRpcAPITestCase(testtools.TestCase):
|
||||
deployment_id=deployment_id)
|
||||
|
||||
def test_create_software_deployment(self):
|
||||
self._test_engine_api('create_software_deployment', 'call',
|
||||
server_id='9f1f0e00-05d2-4ca5-8602-95021f19c9d0',
|
||||
config_id='48e8ade1-9196-42d5-89a2-f709fde42632',
|
||||
input_values={},
|
||||
action='INIT',
|
||||
status='COMPLETE',
|
||||
status_reason=None)
|
||||
self._test_engine_api(
|
||||
'create_software_deployment', 'call',
|
||||
server_id='9f1f0e00-05d2-4ca5-8602-95021f19c9d0',
|
||||
config_id='48e8ade1-9196-42d5-89a2-f709fde42632',
|
||||
stack_user_project_id='65728b74-cfe7-4f17-9c15-11d4f686e591',
|
||||
input_values={},
|
||||
action='INIT',
|
||||
status='COMPLETE',
|
||||
status_reason=None)
|
||||
|
||||
def test_update_software_deployment(self):
|
||||
deployment_id = '86729f02-4648-44d8-af44-d0ec65b6abc9'
|
||||
|
@ -76,7 +76,8 @@ class SoftwareDeploymentTest(HeatTestCase):
|
||||
self.stack = parser.Stack(
|
||||
self.ctx, 'software_deployment_test_stack',
|
||||
template.Template(tmpl),
|
||||
stack_id='42f6f66b-631a-44e7-8d01-e22fb54574a9'
|
||||
stack_id='42f6f66b-631a-44e7-8d01-e22fb54574a9',
|
||||
stack_user_project_id='65728b74-cfe7-4f17-9c15-11d4f686e591'
|
||||
)
|
||||
|
||||
self.patchobject(sd.SoftwareDeployment, '_create_user')
|
||||
@ -189,6 +190,7 @@ class SoftwareDeploymentTest(HeatTestCase):
|
||||
{'action': 'CREATE',
|
||||
'config_id': derived_sc.id,
|
||||
'server_id': '9f1f0e00-05d2-4ca5-8602-95021f19c9d0',
|
||||
'stack_user_project_id': '65728b74-cfe7-4f17-9c15-11d4f686e591',
|
||||
'status': 'COMPLETE',
|
||||
'status_reason': 'Not waiting for outputs signal'},
|
||||
self.deployments.create.call_args[1])
|
||||
@ -207,6 +209,7 @@ class SoftwareDeploymentTest(HeatTestCase):
|
||||
{'action': 'CREATE',
|
||||
'config_id': derived_sc.id,
|
||||
'server_id': '9f1f0e00-05d2-4ca5-8602-95021f19c9d0',
|
||||
'stack_user_project_id': '65728b74-cfe7-4f17-9c15-11d4f686e591',
|
||||
'status': 'IN_PROGRESS',
|
||||
'status_reason': 'Deploy data available'},
|
||||
args)
|
||||
@ -281,6 +284,7 @@ class SoftwareDeploymentTest(HeatTestCase):
|
||||
'action': 'DELETE',
|
||||
'config_id': derived_sc.id,
|
||||
'server_id': '9f1f0e00-05d2-4ca5-8602-95021f19c9d0',
|
||||
'stack_user_project_id': '65728b74-cfe7-4f17-9c15-11d4f686e591',
|
||||
'status': 'IN_PROGRESS',
|
||||
'status_reason': 'Deploy data available'
|
||||
}, args)
|
||||
@ -365,6 +369,7 @@ class SoftwareDeploymentTest(HeatTestCase):
|
||||
'action': 'SUSPEND',
|
||||
'config_id': derived_sc.id,
|
||||
'server_id': '9f1f0e00-05d2-4ca5-8602-95021f19c9d0',
|
||||
'stack_user_project_id': '65728b74-cfe7-4f17-9c15-11d4f686e591',
|
||||
'status': 'IN_PROGRESS',
|
||||
'status_reason': 'Deploy data available'
|
||||
}, args)
|
||||
@ -383,6 +388,7 @@ class SoftwareDeploymentTest(HeatTestCase):
|
||||
'action': 'RESUME',
|
||||
'config_id': derived_sc.id,
|
||||
'server_id': '9f1f0e00-05d2-4ca5-8602-95021f19c9d0',
|
||||
'stack_user_project_id': '65728b74-cfe7-4f17-9c15-11d4f686e591',
|
||||
'status': 'IN_PROGRESS',
|
||||
'status_reason': 'Deploy data available'
|
||||
}, args)
|
||||
|
@ -696,12 +696,14 @@ class SqlAlchemyTest(HeatTestCase):
|
||||
|
||||
def _deployment_values(self):
|
||||
tenant_id = self.ctx.tenant_id
|
||||
stack_user_project_id = str(uuid.uuid4())
|
||||
config_id = db_api.software_config_create(
|
||||
self.ctx, {'name': 'config_mysql', 'tenant': tenant_id}).id
|
||||
server_id = str(uuid.uuid4())
|
||||
input_values = {'foo': 'fooooo', 'bar': 'baaaaa'}
|
||||
values = {
|
||||
'tenant': tenant_id,
|
||||
'stack_user_project_id': stack_user_project_id,
|
||||
'config_id': config_id,
|
||||
'server_id': server_id,
|
||||
'input_values': input_values
|
||||
@ -730,13 +732,23 @@ class SqlAlchemyTest(HeatTestCase):
|
||||
self.assertEqual(values['config_id'], deployment.config_id)
|
||||
self.assertEqual(values['server_id'], deployment.server_id)
|
||||
self.assertEqual(values['input_values'], deployment.input_values)
|
||||
self.ctx.tenant_id = None
|
||||
self.assertEqual(
|
||||
values['stack_user_project_id'], deployment.stack_user_project_id)
|
||||
|
||||
# assert not found with invalid context tenant
|
||||
self.ctx.tenant_id = str(uuid.uuid4())
|
||||
self.assertRaises(
|
||||
exception.NotFound,
|
||||
db_api.software_deployment_get,
|
||||
self.ctx,
|
||||
deployment_id)
|
||||
|
||||
# assert found with stack_user_project_id context tenant
|
||||
self.ctx.tenant_id = deployment.stack_user_project_id
|
||||
deployment = db_api.software_deployment_get(self.ctx, deployment_id)
|
||||
self.assertIsNotNone(deployment)
|
||||
self.assertEqual(values['tenant'], deployment.tenant)
|
||||
|
||||
def test_software_deployment_get_all(self):
|
||||
self.assertEqual([], db_api.software_deployment_get_all(self.ctx))
|
||||
values = self._deployment_values()
|
||||
|
Loading…
Reference in New Issue
Block a user