d5793c08e0
Currently, the event-list output is very resource-centric, despite being scoped to the stack from an API path perspective. This, combined with the fact that the stack updated_at timestamp is only updated after a succesful update (ref bug #1193269) makes it impossible to derive the time when an update started via any API. This is a problem when trying to use the new hook/breakpoint API, because it's necessary to poll for all events since the most recent update started, disregarding any stale hook events from previous updates (which may have failed or timed out without the hooks getting cleared). To work around this, add an event for each stack state transition, such that you can detect the transition to UPDATE_IN_PROGRESS, then use that event as a marker to get post-update-started events. Without this (or some other way to determine when the stack update started), the hooks pre-update functionality landed for kilo is not really usable (particularly mechanically via scripts). Change-Id: Idff342b3aecc2d145dfbc7c0f610ad0ca8e52c8b Partial-Bug: #1448155
2586 lines
102 KiB
Python
2586 lines
102 KiB
Python
#
|
|
# 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 datetime
|
|
import json
|
|
import uuid
|
|
|
|
import mock
|
|
import mox
|
|
from oslo_config import cfg
|
|
from oslo_utils import timeutils
|
|
import six
|
|
|
|
from heat.common import context
|
|
from heat.common import exception
|
|
from heat.common import template_format
|
|
from heat.db.sqlalchemy import api as db_api
|
|
from heat.engine.clients.os import glance
|
|
from heat.engine.clients.os import nova
|
|
from heat.engine import environment
|
|
from heat.engine import resource as rsrc
|
|
from heat.engine.resources.aws.ec2 import instance as instances
|
|
from heat.engine import scheduler
|
|
from heat.engine import stack as parser
|
|
from heat.engine import template as tmpl
|
|
from heat.tests import common
|
|
from heat.tests.nova import fakes as fakes_nova
|
|
from heat.tests import utils
|
|
|
|
|
|
wp_template = '''
|
|
{
|
|
"AWSTemplateFormatVersion" : "2010-09-09",
|
|
"Description" : "WordPress",
|
|
"Parameters" : {
|
|
"KeyName" : {
|
|
"Description" : "KeyName",
|
|
"Type" : "String",
|
|
"Default" : "test"
|
|
}
|
|
},
|
|
"Resources" : {
|
|
"WebServer": {
|
|
"Type": "AWS::EC2::Instance",
|
|
"Properties": {
|
|
"ImageId" : "F17-x86_64-gold",
|
|
"InstanceType" : "m1.large",
|
|
"KeyName" : "test",
|
|
"UserData" : "wordpress"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
'''
|
|
|
|
UUIDs = (UUID1, UUID2, UUID3) = sorted([str(uuid.uuid4())
|
|
for x in range(3)])
|
|
|
|
|
|
class MyResource(rsrc.Resource):
|
|
properties_schema = {
|
|
'ServerName': {'Type': 'String', 'Required': True},
|
|
'Flavor': {'Type': 'String', 'Required': True},
|
|
'ImageName': {'Type': 'String', 'Required': True},
|
|
'UserData': {'Type': 'String'},
|
|
'PublicKey': {'Type': 'String'}
|
|
}
|
|
|
|
@property
|
|
def my_secret(self):
|
|
return db_api.resource_data_get(self, 'my_secret')
|
|
|
|
@my_secret.setter
|
|
def my_secret(self, my_secret):
|
|
self.data_set('my_secret', my_secret, True)
|
|
|
|
|
|
class SqlAlchemyTest(common.HeatTestCase):
|
|
def setUp(self):
|
|
super(SqlAlchemyTest, self).setUp()
|
|
self.fc = fakes_nova.FakeClient()
|
|
self.ctx = utils.dummy_context()
|
|
|
|
def tearDown(self):
|
|
super(SqlAlchemyTest, self).tearDown()
|
|
|
|
def _mock_get_image_id_success(self, imageId_input, imageId):
|
|
self.m.StubOutWithMock(glance.GlanceClientPlugin, 'get_image_id')
|
|
glance.GlanceClientPlugin.get_image_id(
|
|
imageId_input).MultipleTimes().AndReturn(imageId)
|
|
|
|
def _setup_test_stack(self, stack_name, stack_id=None, owner_id=None,
|
|
stack_user_project_id=None, backup=False):
|
|
t = template_format.parse(wp_template)
|
|
template = tmpl.Template(
|
|
t, env=environment.Environment({'KeyName': 'test'}))
|
|
stack_id = stack_id or str(uuid.uuid4())
|
|
stack = parser.Stack(self.ctx, stack_name, template,
|
|
owner_id=owner_id,
|
|
stack_user_project_id=stack_user_project_id)
|
|
with utils.UUIDStub(stack_id):
|
|
stack.store(backup=backup)
|
|
return (template, stack)
|
|
|
|
def _mock_create(self, mocks):
|
|
fc = fakes_nova.FakeClient()
|
|
mocks.StubOutWithMock(instances.Instance, 'nova')
|
|
instances.Instance.nova().MultipleTimes().AndReturn(fc)
|
|
self.m.StubOutWithMock(nova.NovaClientPlugin, '_create')
|
|
nova.NovaClientPlugin._create().AndReturn(self.fc)
|
|
self._mock_get_image_id_success('F17-x86_64-gold', 744)
|
|
|
|
mocks.StubOutWithMock(fc.servers, 'create')
|
|
fc.servers.create(image=744, flavor=3, key_name='test',
|
|
name=mox.IgnoreArg(),
|
|
security_groups=None,
|
|
userdata=mox.IgnoreArg(), scheduler_hints=None,
|
|
meta=None, nics=None,
|
|
availability_zone=None,
|
|
block_device_mapping=None
|
|
).MultipleTimes().AndReturn(fc.servers.list()[4])
|
|
return fc
|
|
|
|
def _mock_delete(self, mocks):
|
|
fc = fakes_nova.FakeClient()
|
|
mocks.StubOutWithMock(instances.Instance, 'nova')
|
|
instances.Instance.nova().MultipleTimes().AndReturn(fc)
|
|
mocks.StubOutWithMock(fc.client, 'get_servers_9999')
|
|
get = fc.client.get_servers_9999
|
|
get().MultipleTimes().AndRaise(fakes_nova.fake_exception())
|
|
|
|
@mock.patch.object(db_api, '_paginate_query')
|
|
def test_filter_and_page_query_paginates_query(self, mock_paginate_query):
|
|
query = mock.Mock()
|
|
db_api._filter_and_page_query(self.ctx, query)
|
|
|
|
assert mock_paginate_query.called
|
|
|
|
@mock.patch.object(db_api, '_events_paginate_query')
|
|
def test_events_filter_and_page_query(self, mock_events_paginate_query):
|
|
query = mock.Mock()
|
|
db_api._events_filter_and_page_query(self.ctx, query)
|
|
|
|
assert mock_events_paginate_query.called
|
|
|
|
@mock.patch.object(db_api.db_filters, 'exact_filter')
|
|
def test_filter_and_page_query_handles_no_filters(self, mock_db_filter):
|
|
query = mock.Mock()
|
|
db_api._filter_and_page_query(self.ctx, query)
|
|
|
|
mock_db_filter.assert_called_once_with(mock.ANY, mock.ANY, {})
|
|
|
|
@mock.patch.object(db_api.db_filters, 'exact_filter')
|
|
def test_events_filter_and_page_query_handles_no_filters(self,
|
|
mock_db_filter):
|
|
query = mock.Mock()
|
|
db_api._events_filter_and_page_query(self.ctx, query)
|
|
|
|
mock_db_filter.assert_called_once_with(mock.ANY, mock.ANY, {})
|
|
|
|
@mock.patch.object(db_api.db_filters, 'exact_filter')
|
|
def test_filter_and_page_query_applies_filters(self, mock_db_filter):
|
|
query = mock.Mock()
|
|
filters = {'foo': 'bar'}
|
|
db_api._filter_and_page_query(self.ctx, query, filters=filters)
|
|
|
|
assert mock_db_filter.called
|
|
|
|
@mock.patch.object(db_api.db_filters, 'exact_filter')
|
|
def test_events_filter_and_page_query_applies_filters(self,
|
|
mock_db_filter):
|
|
query = mock.Mock()
|
|
filters = {'foo': 'bar'}
|
|
db_api._events_filter_and_page_query(self.ctx, query, filters=filters)
|
|
|
|
assert mock_db_filter.called
|
|
|
|
@mock.patch.object(db_api, '_paginate_query')
|
|
def test_filter_and_page_query_whitelists_sort_keys(self,
|
|
mock_paginate_query):
|
|
query = mock.Mock()
|
|
sort_keys = ['stack_name', 'foo']
|
|
db_api._filter_and_page_query(self.ctx, query, sort_keys=sort_keys)
|
|
|
|
args, _ = mock_paginate_query.call_args
|
|
self.assertIn(['name'], args)
|
|
|
|
@mock.patch.object(db_api, '_events_paginate_query')
|
|
def test_events_filter_and_page_query_whitelists_sort_keys(
|
|
self, mock_paginate_query):
|
|
query = mock.Mock()
|
|
sort_keys = ['event_time', 'foo']
|
|
db_api._events_filter_and_page_query(self.ctx, query,
|
|
sort_keys=sort_keys)
|
|
|
|
args, _ = mock_paginate_query.call_args
|
|
self.assertIn(['created_at'], args)
|
|
|
|
@mock.patch.object(db_api.utils, 'paginate_query')
|
|
def test_paginate_query_default_sorts_by_created_at_and_id(
|
|
self, mock_paginate_query):
|
|
query = mock.Mock()
|
|
model = mock.Mock()
|
|
db_api._paginate_query(self.ctx, query, model, sort_keys=None)
|
|
args, _ = mock_paginate_query.call_args
|
|
self.assertIn(['created_at', 'id'], args)
|
|
|
|
@mock.patch.object(db_api.utils, 'paginate_query')
|
|
def test_paginate_query_default_sorts_dir_by_desc(self,
|
|
mock_paginate_query):
|
|
query = mock.Mock()
|
|
model = mock.Mock()
|
|
db_api._paginate_query(self.ctx, query, model, sort_dir=None)
|
|
args, _ = mock_paginate_query.call_args
|
|
self.assertIn('desc', args)
|
|
|
|
@mock.patch.object(db_api.utils, 'paginate_query')
|
|
def test_paginate_query_uses_given_sort_plus_id(self,
|
|
mock_paginate_query):
|
|
query = mock.Mock()
|
|
model = mock.Mock()
|
|
db_api._paginate_query(self.ctx, query, model, sort_keys=['name'])
|
|
args, _ = mock_paginate_query.call_args
|
|
self.assertIn(['name', 'id'], args)
|
|
|
|
@mock.patch.object(db_api.utils, 'paginate_query')
|
|
@mock.patch.object(db_api, 'model_query')
|
|
def test_paginate_query_gets_model_marker(self, mock_query,
|
|
mock_paginate_query):
|
|
query = mock.Mock()
|
|
model = mock.Mock()
|
|
marker = mock.Mock()
|
|
|
|
mock_query_object = mock.Mock()
|
|
mock_query_object.get.return_value = 'real_marker'
|
|
mock_query.return_value = mock_query_object
|
|
|
|
db_api._paginate_query(self.ctx, query, model, marker=marker)
|
|
mock_query_object.get.assert_called_once_with(marker)
|
|
args, _ = mock_paginate_query.call_args
|
|
self.assertIn('real_marker', args)
|
|
|
|
@mock.patch.object(db_api.utils, 'paginate_query')
|
|
def test_paginate_query_raises_invalid_sort_key(self, mock_paginate_query):
|
|
query = mock.Mock()
|
|
model = mock.Mock()
|
|
|
|
mock_paginate_query.side_effect = db_api.utils.InvalidSortKey()
|
|
self.assertRaises(exception.Invalid, db_api._paginate_query,
|
|
self.ctx, query, model, sort_keys=['foo'])
|
|
|
|
def test_get_sort_keys_returns_empty_list_if_no_keys(self):
|
|
sort_keys = None
|
|
mapping = {}
|
|
|
|
filtered_keys = db_api._get_sort_keys(sort_keys, mapping)
|
|
self.assertEqual([], filtered_keys)
|
|
|
|
def test_get_sort_keys_whitelists_single_key(self):
|
|
sort_key = 'foo'
|
|
mapping = {'foo': 'Foo'}
|
|
|
|
filtered_keys = db_api._get_sort_keys(sort_key, mapping)
|
|
self.assertEqual(['Foo'], filtered_keys)
|
|
|
|
def test_get_sort_keys_whitelists_multiple_keys(self):
|
|
sort_keys = ['foo', 'bar', 'nope']
|
|
mapping = {'foo': 'Foo', 'bar': 'Bar'}
|
|
|
|
filtered_keys = db_api._get_sort_keys(sort_keys, mapping)
|
|
self.assertIn('Foo', filtered_keys)
|
|
self.assertIn('Bar', filtered_keys)
|
|
self.assertEqual(2, len(filtered_keys))
|
|
|
|
def test_encryption(self):
|
|
stack_name = 'test_encryption'
|
|
(template, stack) = self._setup_test_stack(stack_name)
|
|
resource_defns = template.resource_definitions(stack)
|
|
cs = MyResource('cs_encryption',
|
|
resource_defns['WebServer'],
|
|
stack)
|
|
|
|
# This gives the fake cloud server an id and created_time attribute
|
|
cs._store_or_update(cs.CREATE, cs.IN_PROGRESS, 'test_store')
|
|
|
|
cs.my_secret = 'fake secret'
|
|
rs = db_api.resource_get_by_name_and_stack(self.ctx,
|
|
'cs_encryption',
|
|
stack.id)
|
|
encrypted_key = rs.data[0]['value']
|
|
self.assertNotEqual(encrypted_key, "fake secret")
|
|
# Test private_key property returns decrypted value
|
|
self.assertEqual("fake secret", cs.my_secret)
|
|
|
|
# do this twice to verify that the orm does not commit the unencrypted
|
|
# value.
|
|
self.assertEqual("fake secret", cs.my_secret)
|
|
scheduler.TaskRunner(cs.destroy)()
|
|
|
|
def test_resource_data_delete(self):
|
|
stack = self._setup_test_stack('stack', UUID1)[1]
|
|
self._mock_create(self.m)
|
|
self.m.ReplayAll()
|
|
stack.create()
|
|
resource = stack['WebServer']
|
|
resource.data_set('test', 'test_data')
|
|
self.assertEqual('test_data', db_api.resource_data_get(resource,
|
|
'test'))
|
|
db_api.resource_data_delete(resource, 'test')
|
|
self.assertRaises(exception.NotFound,
|
|
db_api.resource_data_get, resource, 'test')
|
|
|
|
def test_stack_get_by_name(self):
|
|
stack = self._setup_test_stack('stack', UUID1,
|
|
stack_user_project_id=UUID2)[1]
|
|
|
|
st = db_api.stack_get_by_name(self.ctx, 'stack')
|
|
self.assertEqual(UUID1, st.id)
|
|
|
|
self.ctx.tenant_id = UUID3
|
|
st = db_api.stack_get_by_name(self.ctx, 'stack')
|
|
self.assertIsNone(st)
|
|
|
|
self.ctx.tenant_id = UUID2
|
|
st = db_api.stack_get_by_name(self.ctx, 'stack')
|
|
self.assertEqual(UUID1, st.id)
|
|
|
|
stack.delete()
|
|
|
|
st = db_api.stack_get_by_name(self.ctx, 'stack')
|
|
self.assertIsNone(st)
|
|
|
|
def test_nested_stack_get_by_name(self):
|
|
stack1 = self._setup_test_stack('stack1', UUID1)[1]
|
|
stack2 = self._setup_test_stack('stack2', UUID2,
|
|
owner_id=stack1.id)[1]
|
|
|
|
result = db_api.stack_get_by_name(self.ctx, 'stack2')
|
|
self.assertEqual(UUID2, result.id)
|
|
|
|
stack2.delete()
|
|
|
|
result = db_api.stack_get_by_name(self.ctx, 'stack2')
|
|
self.assertIsNone(result)
|
|
|
|
def test_stack_get_by_name_and_owner_id(self):
|
|
stack1 = self._setup_test_stack('stack1', UUID1,
|
|
stack_user_project_id=UUID3)[1]
|
|
stack2 = self._setup_test_stack('stack2', UUID2,
|
|
owner_id=stack1.id,
|
|
stack_user_project_id=UUID3)[1]
|
|
|
|
result = db_api.stack_get_by_name_and_owner_id(self.ctx, 'stack2',
|
|
None)
|
|
self.assertIsNone(result)
|
|
|
|
result = db_api.stack_get_by_name_and_owner_id(self.ctx, 'stack2',
|
|
stack1.id)
|
|
|
|
self.assertEqual(UUID2, result.id)
|
|
|
|
self.ctx.tenant_id = str(uuid.uuid4())
|
|
result = db_api.stack_get_by_name_and_owner_id(self.ctx, 'stack2',
|
|
None)
|
|
self.assertIsNone(result)
|
|
|
|
self.ctx.tenant_id = UUID3
|
|
result = db_api.stack_get_by_name_and_owner_id(self.ctx, 'stack2',
|
|
stack1.id)
|
|
|
|
self.assertEqual(UUID2, result.id)
|
|
|
|
stack2.delete()
|
|
|
|
result = db_api.stack_get_by_name_and_owner_id(self.ctx, 'stack2',
|
|
stack1.id)
|
|
self.assertIsNone(result)
|
|
|
|
def test_stack_get(self):
|
|
stack = self._setup_test_stack('stack', UUID1)[1]
|
|
|
|
st = db_api.stack_get(self.ctx, UUID1, show_deleted=False)
|
|
self.assertEqual(UUID1, st.id)
|
|
|
|
stack.delete()
|
|
st = db_api.stack_get(self.ctx, UUID1, show_deleted=False)
|
|
self.assertIsNone(st)
|
|
|
|
st = db_api.stack_get(self.ctx, UUID1, show_deleted=True)
|
|
self.assertEqual(UUID1, st.id)
|
|
|
|
def test_stack_get_show_deleted_context(self):
|
|
stack = self._setup_test_stack('stack', UUID1)[1]
|
|
|
|
self.assertFalse(self.ctx.show_deleted)
|
|
st = db_api.stack_get(self.ctx, UUID1)
|
|
self.assertEqual(UUID1, st.id)
|
|
|
|
stack.delete()
|
|
st = db_api.stack_get(self.ctx, UUID1)
|
|
self.assertIsNone(st)
|
|
|
|
self.ctx.show_deleted = True
|
|
st = db_api.stack_get(self.ctx, UUID1)
|
|
self.assertEqual(UUID1, st.id)
|
|
|
|
def test_stack_get_all(self):
|
|
stacks = [self._setup_test_stack('stack', x)[1] for x in UUIDs]
|
|
|
|
st_db = db_api.stack_get_all(self.ctx)
|
|
self.assertEqual(3, len(st_db))
|
|
|
|
stacks[0].delete()
|
|
st_db = db_api.stack_get_all(self.ctx)
|
|
self.assertEqual(2, len(st_db))
|
|
|
|
stacks[1].delete()
|
|
st_db = db_api.stack_get_all(self.ctx)
|
|
self.assertEqual(1, len(st_db))
|
|
|
|
def test_stack_get_all_show_deleted(self):
|
|
stacks = [self._setup_test_stack('stack', x)[1] for x in UUIDs]
|
|
|
|
st_db = db_api.stack_get_all(self.ctx)
|
|
self.assertEqual(3, len(st_db))
|
|
|
|
stacks[0].delete()
|
|
st_db = db_api.stack_get_all(self.ctx)
|
|
self.assertEqual(2, len(st_db))
|
|
|
|
st_db = db_api.stack_get_all(self.ctx, show_deleted=True)
|
|
self.assertEqual(3, len(st_db))
|
|
|
|
def test_stack_get_all_show_nested(self):
|
|
stack1 = self._setup_test_stack('stack1', UUID1)[1]
|
|
stack2 = self._setup_test_stack('stack2', UUID2,
|
|
owner_id=stack1.id)[1]
|
|
# Backup stack should not be returned
|
|
stack3 = self._setup_test_stack('stack1*', UUID3,
|
|
owner_id=stack1.id,
|
|
backup=True)[1]
|
|
|
|
st_db = db_api.stack_get_all(self.ctx)
|
|
self.assertEqual(1, len(st_db))
|
|
self.assertEqual(stack1.id, st_db[0].id)
|
|
|
|
st_db = db_api.stack_get_all(self.ctx, show_nested=True)
|
|
self.assertEqual(2, len(st_db))
|
|
st_ids = [s.id for s in st_db]
|
|
self.assertNotIn(stack3.id, st_ids)
|
|
self.assertIn(stack1.id, st_ids)
|
|
self.assertIn(stack2.id, st_ids)
|
|
|
|
def test_stack_get_all_with_filters(self):
|
|
self._setup_test_stack('foo', UUID1)
|
|
self._setup_test_stack('bar', UUID2)
|
|
|
|
filters = {'name': 'foo'}
|
|
results = db_api.stack_get_all(self.ctx,
|
|
filters=filters)
|
|
|
|
self.assertEqual(1, len(results))
|
|
self.assertEqual('foo', results[0]['name'])
|
|
|
|
def test_stack_get_all_filter_matches_in_list(self):
|
|
self._setup_test_stack('foo', UUID1)
|
|
self._setup_test_stack('bar', UUID2)
|
|
|
|
filters = {'name': ['bar', 'quux']}
|
|
results = db_api.stack_get_all(self.ctx,
|
|
filters=filters)
|
|
|
|
self.assertEqual(1, len(results))
|
|
self.assertEqual('bar', results[0]['name'])
|
|
|
|
def test_stack_get_all_returns_all_if_no_filters(self):
|
|
self._setup_test_stack('foo', UUID1)
|
|
self._setup_test_stack('bar', UUID2)
|
|
|
|
filters = None
|
|
results = db_api.stack_get_all(self.ctx,
|
|
filters=filters)
|
|
|
|
self.assertEqual(2, len(results))
|
|
|
|
def test_stack_get_all_default_sort_keys_and_dir(self):
|
|
stacks = [self._setup_test_stack('stack', x)[1] for x in UUIDs]
|
|
|
|
st_db = db_api.stack_get_all(self.ctx)
|
|
self.assertEqual(3, len(st_db))
|
|
self.assertEqual(stacks[2].id, st_db[0].id)
|
|
self.assertEqual(stacks[1].id, st_db[1].id)
|
|
self.assertEqual(stacks[0].id, st_db[2].id)
|
|
|
|
def test_stack_get_all_default_sort_dir(self):
|
|
stacks = [self._setup_test_stack('stack', x)[1] for x in UUIDs]
|
|
|
|
st_db = db_api.stack_get_all(self.ctx, sort_dir='asc')
|
|
self.assertEqual(3, len(st_db))
|
|
self.assertEqual(stacks[0].id, st_db[0].id)
|
|
self.assertEqual(stacks[1].id, st_db[1].id)
|
|
self.assertEqual(stacks[2].id, st_db[2].id)
|
|
|
|
def test_stack_get_all_str_sort_keys(self):
|
|
stacks = [self._setup_test_stack('stack', x)[1] for x in UUIDs]
|
|
|
|
st_db = db_api.stack_get_all(self.ctx,
|
|
sort_keys='creation_time')
|
|
self.assertEqual(3, len(st_db))
|
|
self.assertEqual(stacks[0].id, st_db[0].id)
|
|
self.assertEqual(stacks[1].id, st_db[1].id)
|
|
self.assertEqual(stacks[2].id, st_db[2].id)
|
|
|
|
@mock.patch.object(db_api.utils, 'paginate_query')
|
|
def test_stack_get_all_filters_sort_keys(self, mock_paginate):
|
|
sort_keys = ['stack_name', 'stack_status', 'creation_time',
|
|
'updated_time', 'stack_owner']
|
|
db_api.stack_get_all(self.ctx, sort_keys=sort_keys)
|
|
|
|
args = mock_paginate.call_args[0]
|
|
used_sort_keys = set(args[3])
|
|
expected_keys = set(['name', 'status', 'created_at',
|
|
'updated_at', 'id'])
|
|
self.assertEqual(expected_keys, used_sort_keys)
|
|
|
|
def test_stack_get_all_marker(self):
|
|
stacks = [self._setup_test_stack('stack', x)[1] for x in UUIDs]
|
|
|
|
st_db = db_api.stack_get_all(self.ctx, marker=stacks[1].id)
|
|
self.assertEqual(1, len(st_db))
|
|
self.assertEqual(stacks[0].id, st_db[0].id)
|
|
|
|
def test_stack_get_all_non_existing_marker(self):
|
|
[self._setup_test_stack('stack', x)[1] for x in UUIDs]
|
|
|
|
uuid = 'this stack doesn\'t exist'
|
|
st_db = db_api.stack_get_all(self.ctx, marker=uuid)
|
|
self.assertEqual(3, len(st_db))
|
|
|
|
def test_stack_get_all_doesnt_mutate_sort_keys(self):
|
|
[self._setup_test_stack('stack', x)[1] for x in UUIDs]
|
|
sort_keys = ['id']
|
|
|
|
db_api.stack_get_all(self.ctx, sort_keys=sort_keys)
|
|
self.assertEqual(['id'], sort_keys)
|
|
|
|
def test_stack_get_all_hidden_tags(self):
|
|
cfg.CONF.set_override('hidden_stack_tags', ['hidden'])
|
|
|
|
stacks = [self._setup_test_stack('stack', x)[1] for x in UUIDs]
|
|
stacks[0].tags = ['hidden']
|
|
stacks[0].store()
|
|
stacks[1].tags = ['random']
|
|
stacks[1].store()
|
|
|
|
st_db = db_api.stack_get_all(self.ctx, show_hidden=True)
|
|
self.assertEqual(3, len(st_db))
|
|
|
|
st_db_visible = db_api.stack_get_all(self.ctx, show_hidden=False)
|
|
self.assertEqual(2, len(st_db_visible))
|
|
|
|
# Make sure the hidden stack isn't in the stacks returned by
|
|
# stack_get_all_visible()
|
|
for stack in st_db_visible:
|
|
self.assertNotEqual(stacks[0].id, stack.id)
|
|
|
|
def test_stack_get_all_by_tags(self):
|
|
stacks = [self._setup_test_stack('stack', x)[1] for x in UUIDs]
|
|
stacks[0].tags = ['tag1']
|
|
stacks[0].store()
|
|
stacks[1].tags = ['tag1', 'tag2']
|
|
stacks[1].store()
|
|
stacks[2].tags = ['tag1', 'tag2', 'tag3']
|
|
stacks[2].store()
|
|
|
|
st_db = db_api.stack_get_all(self.ctx, tags=['tag2'])
|
|
self.assertEqual(2, len(st_db))
|
|
|
|
st_db = db_api.stack_get_all(self.ctx, tags=['tag1', 'tag2'])
|
|
self.assertEqual(2, len(st_db))
|
|
|
|
st_db = db_api.stack_get_all(self.ctx, tags=['tag1', 'tag2', 'tag3'])
|
|
self.assertEqual(1, len(st_db))
|
|
|
|
def test_stack_get_all_by_tags_any(self):
|
|
stacks = [self._setup_test_stack('stack', x)[1] for x in UUIDs]
|
|
stacks[0].tags = ['tag2']
|
|
stacks[0].store()
|
|
stacks[1].tags = ['tag1', 'tag2']
|
|
stacks[1].store()
|
|
stacks[2].tags = ['tag1', 'tag3']
|
|
stacks[2].store()
|
|
|
|
st_db = db_api.stack_get_all(self.ctx, tags_any=['tag1'])
|
|
self.assertEqual(2, len(st_db))
|
|
|
|
st_db = db_api.stack_get_all(self.ctx, tags_any=['tag1', 'tag2',
|
|
'tag3'])
|
|
self.assertEqual(3, len(st_db))
|
|
|
|
def test_stack_get_all_by_not_tags(self):
|
|
stacks = [self._setup_test_stack('stack', x)[1] for x in UUIDs]
|
|
stacks[0].tags = ['tag1']
|
|
stacks[0].store()
|
|
stacks[1].tags = ['tag1', 'tag2']
|
|
stacks[1].store()
|
|
stacks[2].tags = ['tag1', 'tag2', 'tag3']
|
|
stacks[2].store()
|
|
|
|
st_db = db_api.stack_get_all(self.ctx, not_tags=['tag2'])
|
|
self.assertEqual(1, len(st_db))
|
|
|
|
st_db = db_api.stack_get_all(self.ctx, not_tags=['tag1', 'tag2'])
|
|
self.assertEqual(1, len(st_db))
|
|
|
|
st_db = db_api.stack_get_all(self.ctx, not_tags=['tag1', 'tag2',
|
|
'tag3'])
|
|
self.assertEqual(2, len(st_db))
|
|
|
|
def test_stack_get_all_by_not_tags_any(self):
|
|
stacks = [self._setup_test_stack('stack', x)[1] for x in UUIDs]
|
|
stacks[0].tags = ['tag2']
|
|
stacks[0].store()
|
|
stacks[1].tags = ['tag1', 'tag2']
|
|
stacks[1].store()
|
|
stacks[2].tags = ['tag1', 'tag3']
|
|
stacks[2].store()
|
|
|
|
st_db = db_api.stack_get_all(self.ctx, not_tags_any=['tag1'])
|
|
self.assertEqual(1, len(st_db))
|
|
|
|
st_db = db_api.stack_get_all(self.ctx, not_tags_any=['tag1', 'tag2',
|
|
'tag3'])
|
|
self.assertEqual(0, len(st_db))
|
|
|
|
def test_stack_get_all_by_tag_with_pagination(self):
|
|
stacks = [self._setup_test_stack('stack', x)[1] for x in UUIDs]
|
|
stacks[0].tags = ['tag1']
|
|
stacks[0].store()
|
|
stacks[1].tags = ['tag2']
|
|
stacks[1].store()
|
|
stacks[2].tags = ['tag1']
|
|
stacks[2].store()
|
|
|
|
st_db = db_api.stack_get_all(self.ctx, tags=['tag1'])
|
|
self.assertEqual(2, len(st_db))
|
|
|
|
st_db = db_api.stack_get_all(self.ctx, tags=['tag1'], limit=1)
|
|
self.assertEqual(1, len(st_db))
|
|
self.assertEqual(stacks[2].id, st_db[0].id)
|
|
|
|
st_db = db_api.stack_get_all(self.ctx, tags=['tag1'], limit=1,
|
|
marker=stacks[2].id)
|
|
self.assertEqual(1, len(st_db))
|
|
self.assertEqual(stacks[0].id, st_db[0].id)
|
|
|
|
def test_stack_get_all_by_tag_with_show_hidden(self):
|
|
cfg.CONF.set_override('hidden_stack_tags', ['hidden'])
|
|
|
|
stacks = [self._setup_test_stack('stack', x)[1] for x in UUIDs]
|
|
stacks[0].tags = ['tag1']
|
|
stacks[0].store()
|
|
stacks[1].tags = ['hidden', 'tag1']
|
|
stacks[1].store()
|
|
|
|
st_db = db_api.stack_get_all(self.ctx, tags=['tag1'],
|
|
show_hidden=True)
|
|
self.assertEqual(2, len(st_db))
|
|
|
|
st_db = db_api.stack_get_all(self.ctx, tags=['tag1'],
|
|
show_hidden=False)
|
|
self.assertEqual(1, len(st_db))
|
|
|
|
def test_stack_count_all(self):
|
|
stacks = [self._setup_test_stack('stack', x)[1] for x in UUIDs]
|
|
|
|
st_db = db_api.stack_count_all(self.ctx)
|
|
self.assertEqual(3, st_db)
|
|
|
|
stacks[0].delete()
|
|
st_db = db_api.stack_count_all(self.ctx)
|
|
self.assertEqual(2, st_db)
|
|
# show deleted
|
|
st_db = db_api.stack_count_all(self.ctx, show_deleted=True)
|
|
self.assertEqual(3, st_db)
|
|
|
|
stacks[1].delete()
|
|
st_db = db_api.stack_count_all(self.ctx)
|
|
self.assertEqual(1, st_db)
|
|
# show deleted
|
|
st_db = db_api.stack_count_all(self.ctx, show_deleted=True)
|
|
self.assertEqual(3, st_db)
|
|
|
|
def test_count_all_hidden_tags(self):
|
|
cfg.CONF.set_override('hidden_stack_tags', ['hidden'])
|
|
|
|
stacks = [self._setup_test_stack('stack', x)[1] for x in UUIDs]
|
|
stacks[0].tags = ['hidden']
|
|
stacks[0].store()
|
|
stacks[1].tags = ['random']
|
|
stacks[1].store()
|
|
|
|
st_db = db_api.stack_count_all(self.ctx, show_hidden=True)
|
|
self.assertEqual(3, st_db)
|
|
|
|
st_db_visible = db_api.stack_count_all(self.ctx, show_hidden=False)
|
|
self.assertEqual(2, st_db_visible)
|
|
|
|
def test_count_all_by_tags(self):
|
|
stacks = [self._setup_test_stack('stack', x)[1] for x in UUIDs]
|
|
stacks[0].tags = ['tag1']
|
|
stacks[0].store()
|
|
stacks[1].tags = ['tag2']
|
|
stacks[1].store()
|
|
stacks[2].tags = ['tag2']
|
|
stacks[2].store()
|
|
|
|
st_db = db_api.stack_count_all(self.ctx, tags=['tag1'])
|
|
self.assertEqual(1, st_db)
|
|
|
|
st_db = db_api.stack_count_all(self.ctx, tags=['tag2'])
|
|
self.assertEqual(2, st_db)
|
|
|
|
def test_count_all_by_tag_with_show_hidden(self):
|
|
cfg.CONF.set_override('hidden_stack_tags', ['hidden'])
|
|
|
|
stacks = [self._setup_test_stack('stack', x)[1] for x in UUIDs]
|
|
stacks[0].tags = ['tag1']
|
|
stacks[0].store()
|
|
stacks[1].tags = ['hidden', 'tag1']
|
|
stacks[1].store()
|
|
|
|
st_db = db_api.stack_count_all(self.ctx, tags=['tag1'],
|
|
show_hidden=True)
|
|
self.assertEqual(2, st_db)
|
|
|
|
st_db = db_api.stack_count_all(self.ctx, tags=['tag1'],
|
|
show_hidden=False)
|
|
self.assertEqual(1, st_db)
|
|
|
|
def test_stack_count_all_with_filters(self):
|
|
self._setup_test_stack('foo', UUID1)
|
|
self._setup_test_stack('bar', UUID2)
|
|
self._setup_test_stack('bar', UUID3)
|
|
filters = {'name': 'bar'}
|
|
|
|
st_db = db_api.stack_count_all(self.ctx, filters=filters)
|
|
self.assertEqual(2, st_db)
|
|
|
|
def test_stack_count_all_show_nested(self):
|
|
stack1 = self._setup_test_stack('stack1', UUID1)[1]
|
|
self._setup_test_stack('stack2', UUID2,
|
|
owner_id=stack1.id)
|
|
# Backup stack should not be counted
|
|
self._setup_test_stack('stack1*', UUID3,
|
|
owner_id=stack1.id,
|
|
backup=True)
|
|
|
|
st_db = db_api.stack_count_all(self.ctx)
|
|
self.assertEqual(1, st_db)
|
|
|
|
st_db = db_api.stack_count_all(self.ctx, show_nested=True)
|
|
self.assertEqual(2, st_db)
|
|
|
|
def test_event_get_all_by_stack(self):
|
|
stack = self._setup_test_stack('stack', UUID1)[1]
|
|
|
|
self._mock_create(self.m)
|
|
self.m.ReplayAll()
|
|
stack.create()
|
|
self.m.UnsetStubs()
|
|
|
|
events = db_api.event_get_all_by_stack(self.ctx, UUID1)
|
|
self.assertEqual(4, len(events))
|
|
|
|
# test filter by resource_status
|
|
filters = {'resource_status': 'COMPLETE'}
|
|
events = db_api.event_get_all_by_stack(self.ctx, UUID1,
|
|
filters=filters)
|
|
self.assertEqual(2, len(events))
|
|
self.assertEqual('COMPLETE', events[0].resource_status)
|
|
self.assertEqual('COMPLETE', events[1].resource_status)
|
|
# test filter by resource_action
|
|
filters = {'resource_action': 'CREATE'}
|
|
events = db_api.event_get_all_by_stack(self.ctx, UUID1,
|
|
filters=filters)
|
|
self.assertEqual(4, len(events))
|
|
self.assertEqual('CREATE', events[0].resource_action)
|
|
self.assertEqual('CREATE', events[1].resource_action)
|
|
self.assertEqual('CREATE', events[2].resource_action)
|
|
self.assertEqual('CREATE', events[3].resource_action)
|
|
# test filter by resource_type
|
|
filters = {'resource_type': 'AWS::EC2::Instance'}
|
|
events = db_api.event_get_all_by_stack(self.ctx, UUID1,
|
|
filters=filters)
|
|
self.assertEqual(2, len(events))
|
|
self.assertEqual('AWS::EC2::Instance', events[0].resource_type)
|
|
self.assertEqual('AWS::EC2::Instance', events[1].resource_type)
|
|
|
|
filters = {'resource_type': 'OS::Nova::Server'}
|
|
events = db_api.event_get_all_by_stack(self.ctx, UUID1,
|
|
filters=filters)
|
|
self.assertEqual(0, len(events))
|
|
# test limit and marker
|
|
events_all = db_api.event_get_all_by_stack(self.ctx, UUID1)
|
|
marker = events_all[0].uuid
|
|
expected = events_all[1].uuid
|
|
events = db_api.event_get_all_by_stack(self.ctx, UUID1,
|
|
limit=1, marker=marker)
|
|
self.assertEqual(1, len(events))
|
|
self.assertEqual(expected, events[0].uuid)
|
|
|
|
self._mock_delete(self.m)
|
|
self.m.ReplayAll()
|
|
stack.delete()
|
|
|
|
# test filter by resource_status
|
|
filters = {'resource_status': 'COMPLETE'}
|
|
events = db_api.event_get_all_by_stack(self.ctx, UUID1,
|
|
filters=filters)
|
|
self.assertEqual(4, len(events))
|
|
self.assertEqual('COMPLETE', events[0].resource_status)
|
|
self.assertEqual('COMPLETE', events[1].resource_status)
|
|
self.assertEqual('COMPLETE', events[2].resource_status)
|
|
self.assertEqual('COMPLETE', events[3].resource_status)
|
|
# test filter by resource_action
|
|
filters = {'resource_action': 'DELETE',
|
|
'resource_status': 'COMPLETE'}
|
|
events = db_api.event_get_all_by_stack(self.ctx, UUID1,
|
|
filters=filters)
|
|
self.assertEqual(2, len(events))
|
|
self.assertEqual('DELETE', events[0].resource_action)
|
|
self.assertEqual('COMPLETE', events[0].resource_status)
|
|
self.assertEqual('DELETE', events[1].resource_action)
|
|
self.assertEqual('COMPLETE', events[1].resource_status)
|
|
# test limit and marker
|
|
events_all = db_api.event_get_all_by_stack(self.ctx, UUID1)
|
|
self.assertEqual(8, len(events_all))
|
|
|
|
marker = events_all[1].uuid
|
|
events2_uuid = events_all[2].uuid
|
|
events3_uuid = events_all[3].uuid
|
|
events = db_api.event_get_all_by_stack(self.ctx, UUID1,
|
|
limit=1, marker=marker)
|
|
self.assertEqual(1, len(events))
|
|
self.assertEqual(events2_uuid, events[0].uuid)
|
|
|
|
events = db_api.event_get_all_by_stack(self.ctx, UUID1,
|
|
limit=2, marker=marker)
|
|
self.assertEqual(2, len(events))
|
|
self.assertEqual(events2_uuid, events[0].uuid)
|
|
self.assertEqual(events3_uuid, events[1].uuid)
|
|
|
|
self.m.VerifyAll()
|
|
|
|
def test_event_count_all_by_stack(self):
|
|
stack = self._setup_test_stack('stack', UUID1)[1]
|
|
|
|
self._mock_create(self.m)
|
|
self.m.ReplayAll()
|
|
stack.create()
|
|
self.m.UnsetStubs()
|
|
|
|
num_events = db_api.event_count_all_by_stack(self.ctx, UUID1)
|
|
self.assertEqual(4, num_events)
|
|
|
|
self._mock_delete(self.m)
|
|
self.m.ReplayAll()
|
|
stack.delete()
|
|
|
|
num_events = db_api.event_count_all_by_stack(self.ctx, UUID1)
|
|
self.assertEqual(8, num_events)
|
|
|
|
self.m.VerifyAll()
|
|
|
|
def test_event_get_all_by_tenant(self):
|
|
stacks = [self._setup_test_stack('stack', x)[1] for x in UUIDs]
|
|
|
|
self._mock_create(self.m)
|
|
self.m.ReplayAll()
|
|
[s.create() for s in stacks]
|
|
self.m.UnsetStubs()
|
|
|
|
events = db_api.event_get_all_by_tenant(self.ctx)
|
|
self.assertEqual(12, len(events))
|
|
|
|
self._mock_delete(self.m)
|
|
self.m.ReplayAll()
|
|
[s.delete() for s in stacks]
|
|
|
|
events = db_api.event_get_all_by_tenant(self.ctx)
|
|
self.assertEqual(0, len(events))
|
|
|
|
self.m.VerifyAll()
|
|
|
|
def test_event_get_all(self):
|
|
stacks = [self._setup_test_stack('stack', x)[1] for x in UUIDs]
|
|
|
|
self._mock_create(self.m)
|
|
self.m.ReplayAll()
|
|
[s.create() for s in stacks]
|
|
self.m.UnsetStubs()
|
|
|
|
events = db_api.event_get_all(self.ctx)
|
|
self.assertEqual(12, len(events))
|
|
|
|
self._mock_delete(self.m)
|
|
self.m.ReplayAll()
|
|
stacks[0].delete()
|
|
|
|
events = db_api.event_get_all(self.ctx)
|
|
self.assertEqual(8, len(events))
|
|
|
|
self.m.VerifyAll()
|
|
|
|
def test_user_creds_password(self):
|
|
self.ctx.trust_id = None
|
|
self.ctx.region_name = 'RegionOne'
|
|
db_creds = db_api.user_creds_create(self.ctx)
|
|
load_creds = db_api.user_creds_get(db_creds.id)
|
|
|
|
self.assertEqual('test_username', load_creds.get('username'))
|
|
self.assertEqual('password', load_creds.get('password'))
|
|
self.assertEqual('test_tenant', load_creds.get('tenant'))
|
|
self.assertEqual('test_tenant_id', load_creds.get('tenant_id'))
|
|
self.assertEqual('RegionOne', load_creds.get('region_name'))
|
|
self.assertIsNotNone(load_creds.get('created_at'))
|
|
self.assertIsNone(load_creds.get('updated_at'))
|
|
self.assertEqual('http://server.test:5000/v2.0',
|
|
load_creds.get('auth_url'))
|
|
self.assertIsNone(load_creds.get('trust_id'))
|
|
self.assertIsNone(load_creds.get('trustor_user_id'))
|
|
|
|
def test_user_creds_password_too_long(self):
|
|
self.ctx.trust_id = None
|
|
self.ctx.password = 'O123456789O1234567' * 20
|
|
error = self.assertRaises(exception.Error,
|
|
db_api.user_creds_create,
|
|
self.ctx)
|
|
self.assertIn('Length of OS_PASSWORD after encryption exceeds '
|
|
'Heat limit (255 chars)', six.text_type(error))
|
|
|
|
def test_user_creds_trust(self):
|
|
self.ctx.username = None
|
|
self.ctx.password = None
|
|
self.ctx.trust_id = 'atrust123'
|
|
self.ctx.trustor_user_id = 'atrustor123'
|
|
self.ctx.tenant_id = 'atenant123'
|
|
self.ctx.tenant = 'atenant'
|
|
self.ctx.auth_url = 'anauthurl'
|
|
self.ctx.region_name = 'aregion'
|
|
db_creds = db_api.user_creds_create(self.ctx)
|
|
load_creds = db_api.user_creds_get(db_creds.id)
|
|
|
|
self.assertIsNone(load_creds.get('username'))
|
|
self.assertIsNone(load_creds.get('password'))
|
|
self.assertIsNotNone(load_creds.get('created_at'))
|
|
self.assertIsNone(load_creds.get('updated_at'))
|
|
self.assertEqual('anauthurl', load_creds.get('auth_url'))
|
|
self.assertEqual('aregion', load_creds.get('region_name'))
|
|
self.assertEqual('atenant123', load_creds.get('tenant_id'))
|
|
self.assertEqual('atenant', load_creds.get('tenant'))
|
|
self.assertEqual('atrust123', load_creds.get('trust_id'))
|
|
self.assertEqual('atrustor123', load_creds.get('trustor_user_id'))
|
|
|
|
def test_user_creds_none(self):
|
|
self.ctx.username = None
|
|
self.ctx.password = None
|
|
self.ctx.trust_id = None
|
|
self.ctx.region_name = None
|
|
db_creds = db_api.user_creds_create(self.ctx)
|
|
load_creds = db_api.user_creds_get(db_creds.id)
|
|
|
|
self.assertIsNone(load_creds.get('username'))
|
|
self.assertIsNone(load_creds.get('password'))
|
|
self.assertIsNone(load_creds.get('trust_id'))
|
|
self.assertIsNone(load_creds.get('region_name'))
|
|
|
|
def test_software_config_create(self):
|
|
tenant_id = self.ctx.tenant_id
|
|
config = db_api.software_config_create(
|
|
self.ctx, {'name': 'config_mysql',
|
|
'tenant': tenant_id})
|
|
self.assertIsNotNone(config)
|
|
self.assertEqual('config_mysql', config.name)
|
|
self.assertEqual(tenant_id, config.tenant)
|
|
|
|
def test_software_config_get(self):
|
|
self.assertRaises(
|
|
exception.NotFound,
|
|
db_api.software_config_get,
|
|
self.ctx,
|
|
str(uuid.uuid4()))
|
|
conf = ('#!/bin/bash\n'
|
|
'echo "$bar and $foo"\n')
|
|
config = {
|
|
'inputs': [{'name': 'foo'}, {'name': 'bar'}],
|
|
'outputs': [{'name': 'result'}],
|
|
'config': conf,
|
|
'options': {}
|
|
}
|
|
tenant_id = self.ctx.tenant_id
|
|
values = {'name': 'config_mysql',
|
|
'tenant': tenant_id,
|
|
'group': 'Heat::Shell',
|
|
'config': config}
|
|
config = db_api.software_config_create(
|
|
self.ctx, values)
|
|
config_id = config.id
|
|
config = db_api.software_config_get(self.ctx, config_id)
|
|
self.assertIsNotNone(config)
|
|
self.assertEqual('config_mysql', config.name)
|
|
self.assertEqual(tenant_id, config.tenant)
|
|
self.assertEqual('Heat::Shell', config.group)
|
|
self.assertEqual(conf, config.config['config'])
|
|
self.ctx.tenant_id = None
|
|
self.assertRaises(
|
|
exception.NotFound,
|
|
db_api.software_config_get,
|
|
self.ctx,
|
|
config_id)
|
|
|
|
def test_software_config_delete(self):
|
|
tenant_id = self.ctx.tenant_id
|
|
config = db_api.software_config_create(
|
|
self.ctx, {'name': 'config_mysql',
|
|
'tenant': tenant_id})
|
|
config_id = config.id
|
|
db_api.software_config_delete(self.ctx, config_id)
|
|
err = self.assertRaises(
|
|
exception.NotFound,
|
|
db_api.software_config_get,
|
|
self.ctx,
|
|
config_id)
|
|
self.assertIn(config_id, six.text_type(err))
|
|
|
|
err = self.assertRaises(
|
|
exception.NotFound, db_api.software_config_delete,
|
|
self.ctx, config_id)
|
|
self.assertIn(config_id, six.text_type(err))
|
|
|
|
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
|
|
}
|
|
return values
|
|
|
|
def test_software_deployment_create(self):
|
|
values = self._deployment_values()
|
|
deployment = db_api.software_deployment_create(self.ctx, values)
|
|
self.assertIsNotNone(deployment)
|
|
self.assertEqual(values['tenant'], deployment.tenant)
|
|
|
|
def test_software_deployment_get(self):
|
|
self.assertRaises(
|
|
exception.NotFound,
|
|
db_api.software_deployment_get,
|
|
self.ctx,
|
|
str(uuid.uuid4()))
|
|
values = self._deployment_values()
|
|
deployment = db_api.software_deployment_create(self.ctx, values)
|
|
self.assertIsNotNone(deployment)
|
|
deployment_id = deployment.id
|
|
deployment = db_api.software_deployment_get(self.ctx, deployment_id)
|
|
self.assertIsNotNone(deployment)
|
|
self.assertEqual(values['tenant'], deployment.tenant)
|
|
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.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()
|
|
deployment = db_api.software_deployment_create(self.ctx, values)
|
|
self.assertIsNotNone(deployment)
|
|
all = db_api.software_deployment_get_all(self.ctx)
|
|
self.assertEqual(1, len(all))
|
|
self.assertEqual(deployment, all[0])
|
|
all = db_api.software_deployment_get_all(
|
|
self.ctx, server_id=values['server_id'])
|
|
self.assertEqual(1, len(all))
|
|
self.assertEqual(deployment, all[0])
|
|
all = db_api.software_deployment_get_all(
|
|
self.ctx, server_id=str(uuid.uuid4()))
|
|
self.assertEqual([], all)
|
|
|
|
def test_software_deployment_update(self):
|
|
deployment_id = str(uuid.uuid4())
|
|
err = self.assertRaises(exception.NotFound,
|
|
db_api.software_deployment_update,
|
|
self.ctx, deployment_id, values={})
|
|
self.assertIn(deployment_id, six.text_type(err))
|
|
values = self._deployment_values()
|
|
deployment = db_api.software_deployment_create(self.ctx, values)
|
|
deployment_id = deployment.id
|
|
values = {'status': 'COMPLETED'}
|
|
deployment = db_api.software_deployment_update(
|
|
self.ctx, deployment_id, values)
|
|
self.assertIsNotNone(deployment)
|
|
self.assertEqual(values['status'], deployment.status)
|
|
|
|
def test_software_deployment_delete(self):
|
|
deployment_id = str(uuid.uuid4())
|
|
err = self.assertRaises(exception.NotFound,
|
|
db_api.software_deployment_delete,
|
|
self.ctx, deployment_id)
|
|
self.assertIn(deployment_id, six.text_type(err))
|
|
values = self._deployment_values()
|
|
deployment = db_api.software_deployment_create(self.ctx, values)
|
|
deployment_id = deployment.id
|
|
deployment = db_api.software_deployment_get(self.ctx, deployment_id)
|
|
self.assertIsNotNone(deployment)
|
|
db_api.software_deployment_delete(self.ctx, deployment_id)
|
|
|
|
err = self.assertRaises(
|
|
exception.NotFound,
|
|
db_api.software_deployment_get,
|
|
self.ctx,
|
|
deployment_id)
|
|
|
|
self.assertIn(deployment_id, six.text_type(err))
|
|
|
|
def test_snapshot_create(self):
|
|
template = create_raw_template(self.ctx)
|
|
user_creds = create_user_creds(self.ctx)
|
|
stack = create_stack(self.ctx, template, user_creds)
|
|
values = {'tenant': self.ctx.tenant_id, 'status': 'IN_PROGRESS',
|
|
'stack_id': stack.id}
|
|
snapshot = db_api.snapshot_create(self.ctx, values)
|
|
self.assertIsNotNone(snapshot)
|
|
self.assertEqual(values['tenant'], snapshot.tenant)
|
|
|
|
def test_snapshot_create_with_name(self):
|
|
template = create_raw_template(self.ctx)
|
|
user_creds = create_user_creds(self.ctx)
|
|
stack = create_stack(self.ctx, template, user_creds)
|
|
values = {'tenant': self.ctx.tenant_id, 'status': 'IN_PROGRESS',
|
|
'stack_id': stack.id, 'name': 'snap1'}
|
|
snapshot = db_api.snapshot_create(self.ctx, values)
|
|
self.assertIsNotNone(snapshot)
|
|
self.assertEqual(values['tenant'], snapshot.tenant)
|
|
self.assertEqual('snap1', snapshot.name)
|
|
|
|
def test_snapshot_get_not_found(self):
|
|
self.assertRaises(
|
|
exception.NotFound,
|
|
db_api.snapshot_get,
|
|
self.ctx,
|
|
str(uuid.uuid4()))
|
|
|
|
def test_snapshot_get(self):
|
|
template = create_raw_template(self.ctx)
|
|
user_creds = create_user_creds(self.ctx)
|
|
stack = create_stack(self.ctx, template, user_creds)
|
|
values = {'tenant': self.ctx.tenant_id, 'status': 'IN_PROGRESS',
|
|
'stack_id': stack.id}
|
|
snapshot = db_api.snapshot_create(self.ctx, values)
|
|
self.assertIsNotNone(snapshot)
|
|
snapshot_id = snapshot.id
|
|
snapshot = db_api.snapshot_get(self.ctx, snapshot_id)
|
|
self.assertIsNotNone(snapshot)
|
|
self.assertEqual(values['tenant'], snapshot.tenant)
|
|
self.assertEqual(values['status'], snapshot.status)
|
|
self.assertIsNotNone(snapshot.created_at)
|
|
|
|
def test_snapshot_get_by_another_stack(self):
|
|
template = create_raw_template(self.ctx)
|
|
user_creds = create_user_creds(self.ctx)
|
|
stack = create_stack(self.ctx, template, user_creds)
|
|
stack1 = create_stack(self.ctx, template, user_creds)
|
|
values = {'tenant': self.ctx.tenant_id, 'status': 'IN_PROGRESS',
|
|
'stack_id': stack.id}
|
|
snapshot = db_api.snapshot_create(self.ctx, values)
|
|
self.assertIsNotNone(snapshot)
|
|
snapshot_id = snapshot.id
|
|
self.assertRaises(exception.SnapshotNotFound,
|
|
db_api.snapshot_get_by_stack,
|
|
self.ctx, snapshot_id, stack1)
|
|
|
|
def test_snapshot_get_not_found_invalid_tenant(self):
|
|
template = create_raw_template(self.ctx)
|
|
user_creds = create_user_creds(self.ctx)
|
|
stack = create_stack(self.ctx, template, user_creds)
|
|
values = {'tenant': self.ctx.tenant_id, 'status': 'IN_PROGRESS',
|
|
'stack_id': stack.id}
|
|
snapshot = db_api.snapshot_create(self.ctx, values)
|
|
self.ctx.tenant_id = str(uuid.uuid4())
|
|
self.assertRaises(
|
|
exception.NotFound,
|
|
db_api.snapshot_get,
|
|
self.ctx,
|
|
snapshot.id)
|
|
|
|
def test_snapshot_update_not_found(self):
|
|
snapshot_id = str(uuid.uuid4())
|
|
err = self.assertRaises(exception.NotFound,
|
|
db_api.snapshot_update,
|
|
self.ctx, snapshot_id, values={})
|
|
self.assertIn(snapshot_id, six.text_type(err))
|
|
|
|
def test_snapshot_update(self):
|
|
template = create_raw_template(self.ctx)
|
|
user_creds = create_user_creds(self.ctx)
|
|
stack = create_stack(self.ctx, template, user_creds)
|
|
values = {'tenant': self.ctx.tenant_id, 'status': 'IN_PROGRESS',
|
|
'stack_id': stack.id}
|
|
snapshot = db_api.snapshot_create(self.ctx, values)
|
|
snapshot_id = snapshot.id
|
|
values = {'status': 'COMPLETED'}
|
|
snapshot = db_api.snapshot_update(self.ctx, snapshot_id, values)
|
|
self.assertIsNotNone(snapshot)
|
|
self.assertEqual(values['status'], snapshot.status)
|
|
|
|
def test_snapshot_delete_not_found(self):
|
|
snapshot_id = str(uuid.uuid4())
|
|
err = self.assertRaises(exception.NotFound,
|
|
db_api.snapshot_delete,
|
|
self.ctx, snapshot_id)
|
|
self.assertIn(snapshot_id, six.text_type(err))
|
|
|
|
def test_snapshot_delete(self):
|
|
template = create_raw_template(self.ctx)
|
|
user_creds = create_user_creds(self.ctx)
|
|
stack = create_stack(self.ctx, template, user_creds)
|
|
values = {'tenant': self.ctx.tenant_id, 'status': 'IN_PROGRESS',
|
|
'stack_id': stack.id}
|
|
snapshot = db_api.snapshot_create(self.ctx, values)
|
|
snapshot_id = snapshot.id
|
|
snapshot = db_api.snapshot_get(self.ctx, snapshot_id)
|
|
self.assertIsNotNone(snapshot)
|
|
db_api.snapshot_delete(self.ctx, snapshot_id)
|
|
|
|
err = self.assertRaises(
|
|
exception.NotFound,
|
|
db_api.snapshot_get,
|
|
self.ctx,
|
|
snapshot_id)
|
|
|
|
self.assertIn(snapshot_id, six.text_type(err))
|
|
|
|
def test_snapshot_get_all(self):
|
|
template = create_raw_template(self.ctx)
|
|
user_creds = create_user_creds(self.ctx)
|
|
stack = create_stack(self.ctx, template, user_creds)
|
|
values = {'tenant': self.ctx.tenant_id, 'status': 'IN_PROGRESS',
|
|
'stack_id': stack.id}
|
|
snapshot = db_api.snapshot_create(self.ctx, values)
|
|
self.assertIsNotNone(snapshot)
|
|
[snapshot] = db_api.snapshot_get_all(self.ctx, stack.id)
|
|
self.assertIsNotNone(snapshot)
|
|
self.assertEqual(values['tenant'], snapshot.tenant)
|
|
self.assertEqual(values['status'], snapshot.status)
|
|
self.assertIsNotNone(snapshot.created_at)
|
|
|
|
|
|
def create_raw_template(context, **kwargs):
|
|
t = template_format.parse(wp_template)
|
|
template = {
|
|
'template': t,
|
|
'files': {'foo': 'bar'}
|
|
}
|
|
template.update(kwargs)
|
|
return db_api.raw_template_create(context, template)
|
|
|
|
|
|
def create_user_creds(ctx, **kwargs):
|
|
ctx_dict = ctx.to_dict()
|
|
ctx_dict.update(kwargs)
|
|
ctx = context.RequestContext.from_dict(ctx_dict)
|
|
return db_api.user_creds_create(ctx)
|
|
|
|
|
|
def create_stack(ctx, template, user_creds, **kwargs):
|
|
values = {
|
|
'name': 'db_test_stack_name',
|
|
'raw_template_id': template.id,
|
|
'username': ctx.username,
|
|
'tenant': ctx.tenant_id,
|
|
'action': 'create',
|
|
'status': 'complete',
|
|
'status_reason': 'create_complete',
|
|
'parameters': {},
|
|
'user_creds_id': user_creds.id,
|
|
'owner_id': None,
|
|
'timeout': '60',
|
|
'disable_rollback': 0,
|
|
'current_traversal': 'dummy-uuid'
|
|
}
|
|
values.update(kwargs)
|
|
return db_api.stack_create(ctx, values)
|
|
|
|
|
|
def create_resource(ctx, stack, **kwargs):
|
|
values = {
|
|
'name': 'test_resource_name',
|
|
'nova_instance': UUID1,
|
|
'action': 'create',
|
|
'status': 'complete',
|
|
'status_reason': 'create_complete',
|
|
'rsrc_metadata': json.loads('{"foo": "123"}'),
|
|
'stack_id': stack.id
|
|
}
|
|
values.update(kwargs)
|
|
return db_api.resource_create(ctx, values)
|
|
|
|
|
|
def create_resource_data(ctx, resource, **kwargs):
|
|
values = {
|
|
'key': 'test_resource_key',
|
|
'value': 'test_value',
|
|
'redact': 0,
|
|
}
|
|
values.update(kwargs)
|
|
return db_api.resource_data_set(resource, **values)
|
|
|
|
|
|
def create_event(ctx, **kwargs):
|
|
values = {
|
|
'stack_id': 'test_stack_id',
|
|
'resource_action': 'create',
|
|
'resource_status': 'complete',
|
|
'resource_name': 'res',
|
|
'physical_resource_id': UUID1,
|
|
'resource_status_reason': "create_complete",
|
|
'resource_properties': {'name': 'foo'}
|
|
}
|
|
values.update(kwargs)
|
|
return db_api.event_create(ctx, values)
|
|
|
|
|
|
def create_watch_rule(ctx, stack, **kwargs):
|
|
values = {
|
|
'name': 'test_rule',
|
|
'rule': json.loads('{"foo": "123"}'),
|
|
'state': 'normal',
|
|
'last_evaluated': timeutils.utcnow(),
|
|
'stack_id': stack.id,
|
|
}
|
|
values.update(kwargs)
|
|
return db_api.watch_rule_create(ctx, values)
|
|
|
|
|
|
def create_watch_data(ctx, watch_rule, **kwargs):
|
|
values = {
|
|
'data': json.loads('{"foo": "bar"}'),
|
|
'watch_rule_id': watch_rule.id
|
|
}
|
|
values.update(kwargs)
|
|
return db_api.watch_data_create(ctx, values)
|
|
|
|
|
|
def create_service(ctx, **kwargs):
|
|
values = {
|
|
'id': '7079762f-c863-4954-ba61-9dccb68c57e2',
|
|
'engine_id': 'f9aff81e-bc1f-4119-941d-ad1ea7f31d19',
|
|
'host': 'engine-1',
|
|
'hostname': 'host1.devstack.org',
|
|
'binary': 'heat-engine',
|
|
'topic': 'engine',
|
|
'report_interval': 60}
|
|
|
|
values.update(kwargs)
|
|
return db_api.service_create(ctx, values)
|
|
|
|
|
|
def create_sync_point(ctx, **kwargs):
|
|
values = {'entity_id': '0782c463-064a-468d-98fd-442efb638e3a',
|
|
'is_update': True,
|
|
'traversal_id': '899ff81e-fc1f-41f9-f41d-ad1ea7f31d19',
|
|
'atomic_key': 0,
|
|
'stack_id': 'f6359498-764b-49e7-a515-ad31cbef885b',
|
|
'input_data': {}}
|
|
values.update(kwargs)
|
|
return db_api.sync_point_create(ctx, values)
|
|
|
|
|
|
class DBAPIRawTemplateTest(common.HeatTestCase):
|
|
def setUp(self):
|
|
super(DBAPIRawTemplateTest, self).setUp()
|
|
self.ctx = utils.dummy_context()
|
|
|
|
def test_raw_template_create(self):
|
|
t = template_format.parse(wp_template)
|
|
tp = create_raw_template(self.ctx, template=t)
|
|
self.assertIsNotNone(tp.id)
|
|
self.assertEqual(t, tp.template)
|
|
self.assertEqual({'foo': 'bar'}, tp.files)
|
|
|
|
def test_raw_template_get(self):
|
|
t = template_format.parse(wp_template)
|
|
tp = create_raw_template(self.ctx, template=t)
|
|
template = db_api.raw_template_get(self.ctx, tp.id)
|
|
self.assertEqual(tp.id, template.id)
|
|
self.assertEqual(tp.template, template.template)
|
|
|
|
def test_raw_template_update(self):
|
|
another_wp_template = '''
|
|
{
|
|
"AWSTemplateFormatVersion" : "2010-09-09",
|
|
"Description" : "WordPress",
|
|
"Parameters" : {
|
|
"KeyName" : {
|
|
"Description" : "KeyName",
|
|
"Type" : "String",
|
|
"Default" : "test"
|
|
}
|
|
},
|
|
"Resources" : {
|
|
"WebServer": {
|
|
"Type": "AWS::EC2::Instance",
|
|
"Properties": {
|
|
"ImageId" : "fedora-20.x86_64.qcow2",
|
|
"InstanceType" : "m1.xlarge",
|
|
"KeyName" : "test",
|
|
"UserData" : "wordpress"
|
|
}
|
|
}
|
|
}
|
|
}
|
|
'''
|
|
new_t = template_format.parse(another_wp_template)
|
|
new_files = {
|
|
'foo': 'bar',
|
|
'myfile': 'file:///home/somefile'
|
|
}
|
|
new_values = {
|
|
'template': new_t,
|
|
'files': new_files
|
|
}
|
|
orig_tp = create_raw_template(self.ctx)
|
|
updated_tp = db_api.raw_template_update(self.ctx,
|
|
orig_tp.id, new_values)
|
|
|
|
self.assertEqual(orig_tp.id, updated_tp.id)
|
|
self.assertEqual(new_t, updated_tp.template)
|
|
self.assertEqual(new_files, updated_tp.files)
|
|
|
|
|
|
class DBAPIUserCredsTest(common.HeatTestCase):
|
|
def setUp(self):
|
|
super(DBAPIUserCredsTest, self).setUp()
|
|
self.ctx = utils.dummy_context()
|
|
|
|
def test_user_creds_create_trust(self):
|
|
user_creds = create_user_creds(self.ctx, trust_id='test_trust_id',
|
|
trustor_user_id='trustor_id')
|
|
self.assertIsNotNone(user_creds.id)
|
|
self.assertEqual('test_trust_id',
|
|
db_api._decrypt(user_creds.trust_id,
|
|
user_creds.decrypt_method))
|
|
self.assertEqual('trustor_id', user_creds.trustor_user_id)
|
|
self.assertIsNone(user_creds.username)
|
|
self.assertIsNone(user_creds.password)
|
|
self.assertEqual(self.ctx.tenant, user_creds.tenant)
|
|
self.assertEqual(self.ctx.tenant_id, user_creds.tenant_id)
|
|
|
|
def test_user_creds_create_password(self):
|
|
user_creds = create_user_creds(self.ctx)
|
|
self.assertIsNotNone(user_creds.id)
|
|
self.assertEqual(self.ctx.password,
|
|
db_api._decrypt(user_creds.password,
|
|
user_creds.decrypt_method))
|
|
|
|
def test_user_creds_get(self):
|
|
user_creds = create_user_creds(self.ctx)
|
|
ret_user_creds = db_api.user_creds_get(user_creds.id)
|
|
self.assertEqual(db_api._decrypt(user_creds.password,
|
|
user_creds.decrypt_method),
|
|
ret_user_creds['password'])
|
|
|
|
def test_user_creds_get_noexist(self):
|
|
self.assertIsNone(db_api.user_creds_get(123456))
|
|
|
|
def test_user_creds_delete(self):
|
|
user_creds = create_user_creds(self.ctx)
|
|
self.assertIsNotNone(user_creds.id)
|
|
db_api.user_creds_delete(self.ctx, user_creds.id)
|
|
creds = db_api.user_creds_get(user_creds.id)
|
|
self.assertIsNone(creds)
|
|
err = self.assertRaises(
|
|
exception.NotFound, db_api.user_creds_delete,
|
|
self.ctx, user_creds.id)
|
|
exp_msg = ('Attempt to delete user creds with id '
|
|
'%s that does not exist' % user_creds.id)
|
|
self.assertIn(exp_msg, six.text_type(err))
|
|
|
|
|
|
class DBAPIStackTagTest(common.HeatTestCase):
|
|
def setUp(self):
|
|
super(DBAPIStackTagTest, self).setUp()
|
|
self.ctx = utils.dummy_context()
|
|
self.template = create_raw_template(self.ctx)
|
|
self.user_creds = create_user_creds(self.ctx)
|
|
self.stack = create_stack(self.ctx, self.template, self.user_creds)
|
|
|
|
def test_stack_tags_set(self):
|
|
tags = db_api.stack_tags_set(self.ctx, self.stack.id, ['tag1', 'tag2'])
|
|
self.assertEqual(self.stack.id, tags[0].stack_id)
|
|
self.assertEqual('tag1', tags[0].tag)
|
|
|
|
tags = db_api.stack_tags_set(self.ctx, self.stack.id, [])
|
|
self.assertIsNone(tags)
|
|
|
|
def test_stack_tags_get(self):
|
|
db_api.stack_tags_set(self.ctx, self.stack.id, ['tag1', 'tag2'])
|
|
tags = db_api.stack_tags_get(self.ctx, self.stack.id)
|
|
self.assertEqual(self.stack.id, tags[0].stack_id)
|
|
self.assertEqual('tag1', tags[0].tag)
|
|
|
|
tags = db_api.stack_tags_get(self.ctx, UUID1)
|
|
self.assertIsNone(tags)
|
|
|
|
def test_stack_tags_delete(self):
|
|
db_api.stack_tags_set(self.ctx, self.stack.id, ['tag1', 'tag2'])
|
|
db_api.stack_tags_delete(self.ctx, self.stack.id)
|
|
tags = db_api.stack_tags_get(self.ctx, self.stack.id)
|
|
self.assertIsNone(tags)
|
|
|
|
|
|
class DBAPIStackTest(common.HeatTestCase):
|
|
def setUp(self):
|
|
super(DBAPIStackTest, self).setUp()
|
|
self.ctx = utils.dummy_context()
|
|
self.template = create_raw_template(self.ctx)
|
|
self.user_creds = create_user_creds(self.ctx)
|
|
|
|
def test_stack_create(self):
|
|
stack = create_stack(self.ctx, self.template, self.user_creds)
|
|
self.assertIsNotNone(stack.id)
|
|
self.assertEqual('db_test_stack_name', stack.name)
|
|
self.assertEqual(self.template.id, stack.raw_template_id)
|
|
self.assertEqual(self.ctx.username, stack.username)
|
|
self.assertEqual(self.ctx.tenant_id, stack.tenant)
|
|
self.assertEqual('create', stack.action)
|
|
self.assertEqual('complete', stack.status)
|
|
self.assertEqual('create_complete', stack.status_reason)
|
|
self.assertEqual({}, stack.parameters)
|
|
self.assertEqual(self.user_creds.id, stack.user_creds_id)
|
|
self.assertIsNone(stack.owner_id)
|
|
self.assertEqual('60', stack.timeout)
|
|
self.assertFalse(stack.disable_rollback)
|
|
|
|
def test_stack_delete(self):
|
|
stack = create_stack(self.ctx, self.template, self.user_creds)
|
|
stack_id = stack.id
|
|
resource = create_resource(self.ctx, stack)
|
|
db_api.stack_delete(self.ctx, stack_id)
|
|
self.assertIsNone(db_api.stack_get(self.ctx, stack_id,
|
|
show_deleted=False))
|
|
self.assertRaises(exception.NotFound, db_api.resource_get,
|
|
self.ctx, resource.id)
|
|
|
|
self.assertRaises(exception.NotFound, db_api.stack_delete,
|
|
self.ctx, stack_id)
|
|
|
|
# Testing soft delete
|
|
ret_stack = db_api.stack_get(self.ctx, stack_id, show_deleted=True)
|
|
self.assertIsNotNone(ret_stack)
|
|
self.assertEqual(stack_id, ret_stack.id)
|
|
self.assertEqual('db_test_stack_name', ret_stack.name)
|
|
|
|
# Testing child resources deletion
|
|
self.assertRaises(exception.NotFound, db_api.resource_get,
|
|
self.ctx, resource.id)
|
|
|
|
def test_stack_update(self):
|
|
stack = create_stack(self.ctx, self.template, self.user_creds)
|
|
values = {
|
|
'name': 'db_test_stack_name2',
|
|
'action': 'update',
|
|
'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)
|
|
self.assertEqual('db_test_stack_name2', stack.name)
|
|
self.assertEqual('update', stack.action)
|
|
self.assertEqual('failed', stack.status)
|
|
self.assertEqual('update_failed', stack.status_reason)
|
|
self.assertEqual(90, stack.timeout)
|
|
self.assertEqual('dummy-uuid', stack.current_traversal)
|
|
|
|
self.assertRaises(exception.NotFound, db_api.stack_update, self.ctx,
|
|
UUID2, values)
|
|
|
|
def test_stack_get_returns_a_stack(self):
|
|
stack = create_stack(self.ctx, self.template, self.user_creds)
|
|
ret_stack = db_api.stack_get(self.ctx, stack.id, show_deleted=False)
|
|
self.assertIsNotNone(ret_stack)
|
|
self.assertEqual(stack.id, ret_stack.id)
|
|
self.assertEqual('db_test_stack_name', ret_stack.name)
|
|
|
|
def test_stack_get_returns_none_if_stack_does_not_exist(self):
|
|
stack = db_api.stack_get(self.ctx, UUID1, show_deleted=False)
|
|
self.assertIsNone(stack)
|
|
|
|
def test_stack_get_returns_none_if_tenant_id_does_not_match(self):
|
|
stack = create_stack(self.ctx, self.template, self.user_creds)
|
|
self.ctx.tenant_id = 'abc'
|
|
stack = db_api.stack_get(self.ctx, UUID1, show_deleted=False)
|
|
self.assertIsNone(stack)
|
|
|
|
def test_stack_get_tenant_is_stack_user_project_id(self):
|
|
stack = create_stack(self.ctx, self.template, self.user_creds,
|
|
stack_user_project_id='astackuserproject')
|
|
self.ctx.tenant_id = 'astackuserproject'
|
|
ret_stack = db_api.stack_get(self.ctx, stack.id, show_deleted=False)
|
|
self.assertIsNotNone(ret_stack)
|
|
self.assertEqual(stack.id, ret_stack.id)
|
|
self.assertEqual('db_test_stack_name', ret_stack.name)
|
|
|
|
def test_stack_get_can_return_a_stack_from_different_tenant(self):
|
|
stack = create_stack(self.ctx, self.template, self.user_creds)
|
|
self.ctx.tenant_id = 'abc'
|
|
ret_stack = db_api.stack_get(self.ctx, stack.id,
|
|
show_deleted=False, tenant_safe=False)
|
|
self.assertEqual(stack.id, ret_stack.id)
|
|
self.assertEqual('db_test_stack_name', ret_stack.name)
|
|
|
|
def test_stack_get_by_name(self):
|
|
stack = create_stack(self.ctx, self.template, self.user_creds)
|
|
ret_stack = db_api.stack_get_by_name(self.ctx, stack.name)
|
|
self.assertIsNotNone(ret_stack)
|
|
self.assertEqual(stack.id, ret_stack.id)
|
|
self.assertEqual('db_test_stack_name', ret_stack.name)
|
|
|
|
self.assertIsNone(db_api.stack_get_by_name(self.ctx, 'abc'))
|
|
|
|
self.ctx.tenant_id = 'abc'
|
|
self.assertIsNone(db_api.stack_get_by_name(self.ctx, 'abc'))
|
|
|
|
def test_stack_get_all(self):
|
|
values = [
|
|
{'name': 'stack1'},
|
|
{'name': 'stack2'},
|
|
{'name': 'stack3'},
|
|
{'name': 'stack4'}
|
|
]
|
|
[create_stack(self.ctx, self.template, self.user_creds,
|
|
**val) for val in values]
|
|
|
|
ret_stacks = db_api.stack_get_all(self.ctx)
|
|
self.assertEqual(4, len(ret_stacks))
|
|
names = [ret_stack.name for ret_stack in ret_stacks]
|
|
[self.assertIn(val['name'], names) for val in values]
|
|
|
|
def test_stack_get_all_by_owner_id(self):
|
|
parent_stack1 = create_stack(self.ctx, self.template, self.user_creds)
|
|
parent_stack2 = create_stack(self.ctx, self.template, self.user_creds)
|
|
values = [
|
|
{'owner_id': parent_stack1.id},
|
|
{'owner_id': parent_stack1.id},
|
|
{'owner_id': parent_stack2.id},
|
|
{'owner_id': parent_stack2.id},
|
|
]
|
|
[create_stack(self.ctx, self.template, self.user_creds,
|
|
**val) for val in values]
|
|
|
|
stack1_children = db_api.stack_get_all_by_owner_id(self.ctx,
|
|
parent_stack1.id)
|
|
self.assertEqual(2, len(stack1_children))
|
|
stack2_children = db_api.stack_get_all_by_owner_id(self.ctx,
|
|
parent_stack2.id)
|
|
self.assertEqual(2, len(stack2_children))
|
|
|
|
def test_stack_get_all_with_regular_tenant(self):
|
|
values = [
|
|
{'tenant': UUID1},
|
|
{'tenant': UUID1},
|
|
{'tenant': UUID2},
|
|
{'tenant': UUID2},
|
|
{'tenant': UUID2},
|
|
]
|
|
[create_stack(self.ctx, self.template, self.user_creds,
|
|
**val) for val in values]
|
|
|
|
self.ctx.tenant_id = UUID1
|
|
stacks = db_api.stack_get_all(self.ctx)
|
|
self.assertEqual(2, len(stacks))
|
|
|
|
self.ctx.tenant_id = UUID2
|
|
stacks = db_api.stack_get_all(self.ctx)
|
|
self.assertEqual(3, len(stacks))
|
|
|
|
self.ctx.tenant_id = UUID3
|
|
self.assertEqual([], db_api.stack_get_all(self.ctx))
|
|
|
|
def test_stack_get_all_with_tenant_safe_false(self):
|
|
values = [
|
|
{'tenant': UUID1},
|
|
{'tenant': UUID1},
|
|
{'tenant': UUID2},
|
|
{'tenant': UUID2},
|
|
{'tenant': UUID2},
|
|
]
|
|
[create_stack(self.ctx, self.template, self.user_creds,
|
|
**val) for val in values]
|
|
|
|
stacks = db_api.stack_get_all(self.ctx, tenant_safe=False)
|
|
self.assertEqual(5, len(stacks))
|
|
|
|
def test_stack_count_all_with_regular_tenant(self):
|
|
values = [
|
|
{'tenant': UUID1},
|
|
{'tenant': UUID1},
|
|
{'tenant': UUID2},
|
|
{'tenant': UUID2},
|
|
{'tenant': UUID2},
|
|
]
|
|
[create_stack(self.ctx, self.template, self.user_creds,
|
|
**val) for val in values]
|
|
|
|
self.ctx.tenant_id = UUID1
|
|
self.assertEqual(2, db_api.stack_count_all(self.ctx))
|
|
|
|
self.ctx.tenant_id = UUID2
|
|
self.assertEqual(3, db_api.stack_count_all(self.ctx))
|
|
|
|
def test_stack_count_all_with_tenant_safe_false(self):
|
|
values = [
|
|
{'tenant': UUID1},
|
|
{'tenant': UUID1},
|
|
{'tenant': UUID2},
|
|
{'tenant': UUID2},
|
|
{'tenant': UUID2},
|
|
]
|
|
[create_stack(self.ctx, self.template, self.user_creds,
|
|
**val) for val in values]
|
|
|
|
self.assertEqual(5,
|
|
db_api.stack_count_all(self.ctx, tenant_safe=False))
|
|
|
|
def test_purge_deleted(self):
|
|
now = datetime.datetime.now()
|
|
delta = datetime.timedelta(seconds=3600 * 7)
|
|
deleted = [now - delta * i for i in range(1, 6)]
|
|
templates = [create_raw_template(self.ctx) for i in range(5)]
|
|
creds = [create_user_creds(self.ctx) for i in range(5)]
|
|
stacks = [create_stack(self.ctx, templates[i], creds[i],
|
|
deleted_at=deleted[i]) for i in range(5)]
|
|
|
|
db_api.purge_deleted(age=1, granularity='days')
|
|
self._deleted_stack_existance(utils.dummy_context(), stacks,
|
|
(0, 1, 2), (3, 4))
|
|
|
|
db_api.purge_deleted(age=22, granularity='hours')
|
|
self._deleted_stack_existance(utils.dummy_context(), stacks,
|
|
(0, 1, 2), (3, 4))
|
|
|
|
db_api.purge_deleted(age=1100, granularity='minutes')
|
|
self._deleted_stack_existance(utils.dummy_context(), stacks,
|
|
(0, 1), (2, 3, 4))
|
|
|
|
db_api.purge_deleted(age=3600, granularity='seconds')
|
|
self._deleted_stack_existance(utils.dummy_context(), stacks,
|
|
(), (0, 1, 2, 3, 4))
|
|
|
|
def _deleted_stack_existance(self, ctx, stacks, existing, deleted):
|
|
for s in existing:
|
|
self.assertIsNotNone(db_api.stack_get(ctx, stacks[s].id,
|
|
show_deleted=True))
|
|
for s in deleted:
|
|
self.assertIsNone(db_api.stack_get(ctx, stacks[s].id,
|
|
show_deleted=True))
|
|
|
|
|
|
class DBAPIResourceTest(common.HeatTestCase):
|
|
def setUp(self):
|
|
super(DBAPIResourceTest, self).setUp()
|
|
self.ctx = utils.dummy_context()
|
|
self.template = create_raw_template(self.ctx)
|
|
self.user_creds = create_user_creds(self.ctx)
|
|
self.stack = create_stack(self.ctx, self.template, self.user_creds)
|
|
|
|
def test_resource_create(self):
|
|
res = create_resource(self.ctx, self.stack)
|
|
ret_res = db_api.resource_get(self.ctx, res.id)
|
|
self.assertIsNotNone(ret_res)
|
|
self.assertEqual('test_resource_name', ret_res.name)
|
|
self.assertEqual(UUID1, ret_res.nova_instance)
|
|
self.assertEqual('create', ret_res.action)
|
|
self.assertEqual('complete', ret_res.status)
|
|
self.assertEqual('create_complete', ret_res.status_reason)
|
|
self.assertEqual('{"foo": "123"}', json.dumps(ret_res.rsrc_metadata))
|
|
self.assertEqual(self.stack.id, ret_res.stack_id)
|
|
|
|
def test_resource_get(self):
|
|
res = create_resource(self.ctx, self.stack)
|
|
ret_res = db_api.resource_get(self.ctx, res.id)
|
|
self.assertIsNotNone(ret_res)
|
|
|
|
self.assertRaises(exception.NotFound, db_api.resource_get,
|
|
self.ctx, UUID2)
|
|
|
|
def test_resource_get_by_name_and_stack(self):
|
|
create_resource(self.ctx, self.stack)
|
|
|
|
ret_res = db_api.resource_get_by_name_and_stack(self.ctx,
|
|
'test_resource_name',
|
|
self.stack.id)
|
|
|
|
self.assertIsNotNone(ret_res)
|
|
self.assertEqual('test_resource_name', ret_res.name)
|
|
self.assertEqual(self.stack.id, ret_res.stack_id)
|
|
|
|
self.assertIsNone(db_api.resource_get_by_name_and_stack(self.ctx,
|
|
'abc',
|
|
self.stack.id))
|
|
|
|
def test_resource_get_by_physical_resource_id(self):
|
|
create_resource(self.ctx, self.stack)
|
|
|
|
ret_res = db_api.resource_get_by_physical_resource_id(self.ctx, UUID1)
|
|
self.assertIsNotNone(ret_res)
|
|
self.assertEqual(UUID1, ret_res.nova_instance)
|
|
|
|
self.assertIsNone(db_api.resource_get_by_physical_resource_id(self.ctx,
|
|
UUID2))
|
|
|
|
def test_resource_get_all(self):
|
|
values = [
|
|
{'name': 'res1'},
|
|
{'name': 'res2'},
|
|
{'name': 'res3'},
|
|
]
|
|
[create_resource(self.ctx, self.stack, **val) for val in values]
|
|
|
|
resources = db_api.resource_get_all(self.ctx)
|
|
self.assertEqual(3, len(resources))
|
|
|
|
names = [resource.name for resource in resources]
|
|
[self.assertIn(val['name'], names) for val in values]
|
|
|
|
def test_resource_get_all_by_stack(self):
|
|
self.stack1 = create_stack(self.ctx, self.template, self.user_creds)
|
|
self.stack2 = create_stack(self.ctx, self.template, self.user_creds)
|
|
values = [
|
|
{'name': 'res1', 'stack_id': self.stack.id},
|
|
{'name': 'res2', 'stack_id': self.stack.id},
|
|
{'name': 'res3', 'stack_id': self.stack1.id},
|
|
]
|
|
[create_resource(self.ctx, self.stack, **val) for val in values]
|
|
|
|
resources = db_api.resource_get_all_by_stack(self.ctx, self.stack.id)
|
|
self.assertEqual(2, len(resources))
|
|
self.assertEqual('res1', resources.get('res1').name)
|
|
self.assertEqual('res2', resources.get('res2').name)
|
|
|
|
self.assertRaises(exception.NotFound, db_api.resource_get_all_by_stack,
|
|
self.ctx, self.stack2.id)
|
|
|
|
|
|
class DBAPIStackLockTest(common.HeatTestCase):
|
|
def setUp(self):
|
|
super(DBAPIStackLockTest, self).setUp()
|
|
self.ctx = utils.dummy_context()
|
|
self.template = create_raw_template(self.ctx)
|
|
self.user_creds = create_user_creds(self.ctx)
|
|
self.stack = create_stack(self.ctx, self.template, self.user_creds)
|
|
|
|
def test_stack_lock_create_success(self):
|
|
observed = db_api.stack_lock_create(self.stack.id, UUID1)
|
|
self.assertIsNone(observed)
|
|
|
|
def test_stack_lock_create_fail_double_same(self):
|
|
db_api.stack_lock_create(self.stack.id, UUID1)
|
|
observed = db_api.stack_lock_create(self.stack.id, UUID1)
|
|
self.assertEqual(UUID1, observed)
|
|
|
|
def test_stack_lock_create_fail_double_different(self):
|
|
db_api.stack_lock_create(self.stack.id, UUID1)
|
|
observed = db_api.stack_lock_create(self.stack.id, UUID2)
|
|
self.assertEqual(UUID1, observed)
|
|
|
|
def test_stack_lock_get_id_success(self):
|
|
db_api.stack_lock_create(self.stack.id, UUID1)
|
|
observed = db_api.stack_lock_get_engine_id(self.stack.id)
|
|
self.assertEqual(UUID1, observed)
|
|
|
|
def test_stack_lock_get_id_return_none(self):
|
|
observed = db_api.stack_lock_get_engine_id(self.stack.id)
|
|
self.assertIsNone(observed)
|
|
|
|
def test_stack_lock_steal_success(self):
|
|
db_api.stack_lock_create(self.stack.id, UUID1)
|
|
observed = db_api.stack_lock_steal(self.stack.id, UUID1, UUID2)
|
|
self.assertIsNone(observed)
|
|
|
|
def test_stack_lock_steal_fail_gone(self):
|
|
db_api.stack_lock_create(self.stack.id, UUID1)
|
|
db_api.stack_lock_release(self.stack.id, UUID1)
|
|
observed = db_api.stack_lock_steal(self.stack.id, UUID1, UUID2)
|
|
self.assertTrue(observed)
|
|
|
|
def test_stack_lock_steal_fail_stolen(self):
|
|
db_api.stack_lock_create(self.stack.id, UUID1)
|
|
|
|
# Simulate stolen lock
|
|
db_api.stack_lock_release(self.stack.id, UUID1)
|
|
db_api.stack_lock_create(self.stack.id, UUID2)
|
|
|
|
observed = db_api.stack_lock_steal(self.stack.id, UUID3, UUID2)
|
|
self.assertEqual(UUID2, observed)
|
|
|
|
def test_stack_lock_release_success(self):
|
|
db_api.stack_lock_create(self.stack.id, UUID1)
|
|
observed = db_api.stack_lock_release(self.stack.id, UUID1)
|
|
self.assertIsNone(observed)
|
|
|
|
def test_stack_lock_release_fail_double(self):
|
|
db_api.stack_lock_create(self.stack.id, UUID1)
|
|
db_api.stack_lock_release(self.stack.id, UUID1)
|
|
observed = db_api.stack_lock_release(self.stack.id, UUID1)
|
|
self.assertTrue(observed)
|
|
|
|
def test_stack_lock_release_fail_wrong_engine_id(self):
|
|
db_api.stack_lock_create(self.stack.id, UUID1)
|
|
observed = db_api.stack_lock_release(self.stack.id, UUID2)
|
|
self.assertTrue(observed)
|
|
|
|
|
|
class DBAPIResourceDataTest(common.HeatTestCase):
|
|
def setUp(self):
|
|
super(DBAPIResourceDataTest, self).setUp()
|
|
self.ctx = utils.dummy_context()
|
|
self.template = create_raw_template(self.ctx)
|
|
self.user_creds = create_user_creds(self.ctx)
|
|
self.stack = create_stack(self.ctx, self.template, self.user_creds)
|
|
self.resource = create_resource(self.ctx, self.stack)
|
|
self.resource.context = self.ctx
|
|
|
|
def test_resource_data_set_get(self):
|
|
create_resource_data(self.ctx, self.resource)
|
|
val = db_api.resource_data_get(self.resource, 'test_resource_key')
|
|
self.assertEqual('test_value', val)
|
|
|
|
# Updating existing resource data
|
|
create_resource_data(self.ctx, self.resource, value='foo')
|
|
val = db_api.resource_data_get(self.resource, 'test_resource_key')
|
|
self.assertEqual('foo', val)
|
|
|
|
# Testing with encrypted value
|
|
create_resource_data(self.ctx, self.resource,
|
|
key='encryped_resource_key', redact=True)
|
|
val = db_api.resource_data_get(self.resource, 'encryped_resource_key')
|
|
self.assertEqual('test_value', val)
|
|
|
|
# get all by querying for data
|
|
vals = db_api.resource_data_get_all(self.resource)
|
|
self.assertEqual(2, len(vals))
|
|
self.assertEqual('foo', vals.get('test_resource_key'))
|
|
self.assertEqual('test_value', vals.get('encryped_resource_key'))
|
|
|
|
# get all by using associated resource data
|
|
vals = db_api.resource_data_get_all(None, self.resource.data)
|
|
self.assertEqual(2, len(vals))
|
|
self.assertEqual('foo', vals.get('test_resource_key'))
|
|
self.assertEqual('test_value', vals.get('encryped_resource_key'))
|
|
|
|
def test_resource_data_delete(self):
|
|
create_resource_data(self.ctx, self.resource)
|
|
res_data = db_api.resource_data_get_by_key(self.ctx, self.resource.id,
|
|
'test_resource_key')
|
|
self.assertIsNotNone(res_data)
|
|
self.assertEqual('test_value', res_data.value)
|
|
|
|
db_api.resource_data_delete(self.resource, 'test_resource_key')
|
|
self.assertRaises(exception.NotFound, db_api.resource_data_get_by_key,
|
|
self.ctx, self.resource.id, 'test_resource_key')
|
|
self.assertIsNotNone(res_data)
|
|
|
|
|
|
class DBAPIEventTest(common.HeatTestCase):
|
|
def setUp(self):
|
|
super(DBAPIEventTest, self).setUp()
|
|
self.ctx = utils.dummy_context()
|
|
self.template = create_raw_template(self.ctx)
|
|
self.user_creds = create_user_creds(self.ctx)
|
|
|
|
def test_event_create_get(self):
|
|
event = create_event(self.ctx)
|
|
ret_event = db_api.event_get(self.ctx, event.id)
|
|
self.assertIsNotNone(ret_event)
|
|
self.assertEqual('test_stack_id', ret_event.stack_id)
|
|
self.assertEqual('create', ret_event.resource_action)
|
|
self.assertEqual('complete', ret_event.resource_status)
|
|
self.assertEqual('res', ret_event.resource_name)
|
|
self.assertEqual(UUID1, ret_event.physical_resource_id)
|
|
self.assertEqual('create_complete', ret_event.resource_status_reason)
|
|
self.assertEqual({'name': 'foo'}, ret_event.resource_properties)
|
|
|
|
def test_event_get_all(self):
|
|
self.stack1 = create_stack(self.ctx, self.template, self.user_creds,
|
|
tenant='tenant1')
|
|
self.stack2 = create_stack(self.ctx, self.template, self.user_creds,
|
|
tenant='tenant2')
|
|
values = [
|
|
{'stack_id': self.stack1.id, 'resource_name': 'res1'},
|
|
{'stack_id': self.stack1.id, 'resource_name': 'res2'},
|
|
{'stack_id': self.stack2.id, 'resource_name': 'res3'},
|
|
]
|
|
[create_event(self.ctx, **val) for val in values]
|
|
|
|
events = db_api.event_get_all(self.ctx)
|
|
self.assertEqual(3, len(events))
|
|
|
|
stack_ids = [event.stack_id for event in events]
|
|
res_names = [event.resource_name for event in events]
|
|
[(self.assertIn(val['stack_id'], stack_ids),
|
|
self.assertIn(val['resource_name'], res_names)) for val in values]
|
|
|
|
def test_event_get_all_by_tenant(self):
|
|
self.stack1 = create_stack(self.ctx, self.template, self.user_creds,
|
|
tenant='tenant1')
|
|
self.stack2 = create_stack(self.ctx, self.template, self.user_creds,
|
|
tenant='tenant2')
|
|
values = [
|
|
{'stack_id': self.stack1.id, 'resource_name': 'res1'},
|
|
{'stack_id': self.stack1.id, 'resource_name': 'res2'},
|
|
{'stack_id': self.stack2.id, 'resource_name': 'res3'},
|
|
]
|
|
[create_event(self.ctx, **val) for val in values]
|
|
|
|
self.ctx.tenant_id = 'tenant1'
|
|
events = db_api.event_get_all_by_tenant(self.ctx)
|
|
self.assertEqual(2, len(events))
|
|
marker = events[0].uuid
|
|
expected = events[1].uuid
|
|
events = db_api.event_get_all_by_tenant(self.ctx,
|
|
marker=marker)
|
|
self.assertEqual(1, len(events))
|
|
self.assertEqual(expected, events[0].uuid)
|
|
|
|
events = db_api.event_get_all_by_tenant(self.ctx, limit=1)
|
|
self.assertEqual(1, len(events))
|
|
|
|
filters = {'resource_name': 'res2'}
|
|
events = db_api.event_get_all_by_tenant(self.ctx,
|
|
filters=filters)
|
|
self.assertEqual(1, len(events))
|
|
self.assertEqual('res2', events[0].resource_name)
|
|
|
|
sort_keys = 'resource_type'
|
|
events = db_api.event_get_all_by_tenant(self.ctx,
|
|
sort_keys=sort_keys)
|
|
self.assertEqual(2, len(events))
|
|
|
|
self.ctx.tenant_id = 'tenant2'
|
|
events = db_api.event_get_all_by_tenant(self.ctx)
|
|
self.assertEqual(1, len(events))
|
|
|
|
def test_event_get_all_by_stack(self):
|
|
self.stack1 = create_stack(self.ctx, self.template, self.user_creds)
|
|
self.stack2 = create_stack(self.ctx, self.template, self.user_creds)
|
|
values = [
|
|
{'stack_id': self.stack1.id, 'resource_name': 'res1'},
|
|
{'stack_id': self.stack1.id, 'resource_name': 'res2'},
|
|
{'stack_id': self.stack2.id, 'resource_name': 'res3'},
|
|
]
|
|
[create_event(self.ctx, **val) for val in values]
|
|
|
|
self.ctx.tenant_id = 'tenant1'
|
|
events = db_api.event_get_all_by_stack(self.ctx, self.stack1.id)
|
|
self.assertEqual(2, len(events))
|
|
|
|
self.ctx.tenant_id = 'tenant2'
|
|
events = db_api.event_get_all_by_stack(self.ctx, self.stack2.id)
|
|
self.assertEqual(1, len(events))
|
|
|
|
def test_event_count_all_by_stack(self):
|
|
self.stack1 = create_stack(self.ctx, self.template, self.user_creds)
|
|
self.stack2 = create_stack(self.ctx, self.template, self.user_creds)
|
|
values = [
|
|
{'stack_id': self.stack1.id, 'resource_name': 'res1'},
|
|
{'stack_id': self.stack1.id, 'resource_name': 'res2'},
|
|
{'stack_id': self.stack2.id, 'resource_name': 'res3'},
|
|
]
|
|
[create_event(self.ctx, **val) for val in values]
|
|
|
|
self.assertEqual(2, db_api.event_count_all_by_stack(self.ctx,
|
|
self.stack1.id))
|
|
|
|
self.assertEqual(1, db_api.event_count_all_by_stack(self.ctx,
|
|
self.stack2.id))
|
|
|
|
|
|
class DBAPIWatchRuleTest(common.HeatTestCase):
|
|
def setUp(self):
|
|
super(DBAPIWatchRuleTest, self).setUp()
|
|
self.ctx = utils.dummy_context()
|
|
self.template = create_raw_template(self.ctx)
|
|
self.user_creds = create_user_creds(self.ctx)
|
|
self.stack = create_stack(self.ctx, self.template, self.user_creds)
|
|
|
|
def test_watch_rule_create_get(self):
|
|
watch_rule = create_watch_rule(self.ctx, self.stack)
|
|
ret_wr = db_api.watch_rule_get(self.ctx, watch_rule.id)
|
|
self.assertIsNotNone(ret_wr)
|
|
self.assertEqual('test_rule', ret_wr.name)
|
|
self.assertEqual('{"foo": "123"}', json.dumps(ret_wr.rule))
|
|
self.assertEqual('normal', ret_wr.state)
|
|
self.assertEqual(self.stack.id, ret_wr.stack_id)
|
|
|
|
def test_watch_rule_get_by_name(self):
|
|
watch_rule = create_watch_rule(self.ctx, self.stack)
|
|
ret_wr = db_api.watch_rule_get_by_name(self.ctx, watch_rule.name)
|
|
self.assertIsNotNone(ret_wr)
|
|
self.assertEqual('test_rule', ret_wr.name)
|
|
|
|
def test_watch_rule_get_all(self):
|
|
values = [
|
|
{'name': 'rule1'},
|
|
{'name': 'rule2'},
|
|
{'name': 'rule3'},
|
|
]
|
|
[create_watch_rule(self.ctx, self.stack, **val) for val in values]
|
|
|
|
wrs = db_api.watch_rule_get_all(self.ctx)
|
|
self.assertEqual(3, len(wrs))
|
|
|
|
names = [wr.name for wr in wrs]
|
|
[self.assertIn(val['name'], names) for val in values]
|
|
|
|
def test_watch_rule_get_all_by_stack(self):
|
|
self.stack1 = create_stack(self.ctx, self.template, self.user_creds)
|
|
|
|
values = [
|
|
{'name': 'rule1', 'stack_id': self.stack.id},
|
|
{'name': 'rule2', 'stack_id': self.stack1.id},
|
|
{'name': 'rule3', 'stack_id': self.stack1.id},
|
|
]
|
|
[create_watch_rule(self.ctx, self.stack, **val) for val in values]
|
|
|
|
wrs = db_api.watch_rule_get_all_by_stack(self.ctx, self.stack.id)
|
|
self.assertEqual(1, len(wrs))
|
|
wrs = db_api.watch_rule_get_all_by_stack(self.ctx, self.stack1.id)
|
|
self.assertEqual(2, len(wrs))
|
|
|
|
def test_watch_rule_update(self):
|
|
watch_rule = create_watch_rule(self.ctx, self.stack)
|
|
values = {
|
|
'name': 'test_rule_1',
|
|
'rule': json.loads('{"foo": "bar"}'),
|
|
'state': 'nodata',
|
|
}
|
|
db_api.watch_rule_update(self.ctx, watch_rule.id, values)
|
|
watch_rule = db_api.watch_rule_get(self.ctx, watch_rule.id)
|
|
self.assertEqual('test_rule_1', watch_rule.name)
|
|
self.assertEqual('{"foo": "bar"}', json.dumps(watch_rule.rule))
|
|
self.assertEqual('nodata', watch_rule.state)
|
|
|
|
self.assertRaises(exception.NotFound, db_api.watch_rule_update,
|
|
self.ctx, UUID2, values)
|
|
|
|
def test_watch_rule_delete(self):
|
|
watch_rule = create_watch_rule(self.ctx, self.stack)
|
|
create_watch_data(self.ctx, watch_rule)
|
|
db_api.watch_rule_delete(self.ctx, watch_rule.id)
|
|
self.assertIsNone(db_api.watch_rule_get(self.ctx, watch_rule.id))
|
|
self.assertRaises(exception.NotFound, db_api.watch_rule_delete,
|
|
self.ctx, UUID2)
|
|
|
|
# Testing associated watch data deletion
|
|
self.assertEqual([], db_api.watch_data_get_all(self.ctx))
|
|
|
|
|
|
class DBAPIWatchDataTest(common.HeatTestCase):
|
|
def setUp(self):
|
|
super(DBAPIWatchDataTest, self).setUp()
|
|
self.ctx = utils.dummy_context()
|
|
self.template = create_raw_template(self.ctx)
|
|
self.user_creds = create_user_creds(self.ctx)
|
|
self.stack = create_stack(self.ctx, self.template, self.user_creds)
|
|
self.watch_rule = create_watch_rule(self.ctx, self.stack)
|
|
|
|
def test_watch_data_create(self):
|
|
create_watch_data(self.ctx, self.watch_rule)
|
|
ret_data = db_api.watch_data_get_all(self.ctx)
|
|
self.assertEqual(1, len(ret_data))
|
|
|
|
self.assertEqual('{"foo": "bar"}', json.dumps(ret_data[0].data))
|
|
self.assertEqual(self.watch_rule.id, ret_data[0].watch_rule_id)
|
|
|
|
def test_watch_data_get_all(self):
|
|
values = [
|
|
{'data': json.loads('{"foo": "d1"}')},
|
|
{'data': json.loads('{"foo": "d2"}')},
|
|
{'data': json.loads('{"foo": "d3"}')}
|
|
]
|
|
[create_watch_data(self.ctx, self.watch_rule, **val) for val in values]
|
|
watch_data = db_api.watch_data_get_all(self.ctx)
|
|
self.assertEqual(3, len(watch_data))
|
|
|
|
data = [wd.data for wd in watch_data]
|
|
[self.assertIn(val['data'], data) for val in values]
|
|
|
|
|
|
class DBAPIServiceTest(common.HeatTestCase):
|
|
def setUp(self):
|
|
super(DBAPIServiceTest, self).setUp()
|
|
self.ctx = utils.dummy_context()
|
|
|
|
def test_service_create_get(self):
|
|
service = create_service(self.ctx)
|
|
ret_service = db_api.service_get(self.ctx, service.id)
|
|
self.assertIsNotNone(ret_service)
|
|
self.assertEqual(service.id, ret_service.id)
|
|
self.assertEqual(service.hostname, ret_service.hostname)
|
|
self.assertEqual(service.binary, ret_service.binary)
|
|
self.assertEqual(service.host, ret_service.host)
|
|
self.assertEqual(service.topic, ret_service.topic)
|
|
self.assertEqual(service.engine_id, ret_service.engine_id)
|
|
self.assertEqual(service.report_interval, ret_service.report_interval)
|
|
self.assertIsNotNone(service.created_at)
|
|
self.assertIsNone(service.updated_at)
|
|
self.assertIsNone(service.deleted_at)
|
|
|
|
def test_service_get_all_by_args(self):
|
|
# Host-1
|
|
values = [{'id': str(uuid.uuid4()),
|
|
'hostname': 'host-1',
|
|
'host': 'engine-1'}]
|
|
# Host-2
|
|
for i in [0, 1, 2]:
|
|
values.append({'id': str(uuid.uuid4()),
|
|
'hostname': 'host-2',
|
|
'host': 'engine-%s' % i})
|
|
|
|
[create_service(self.ctx, **val) for val in values]
|
|
|
|
services = db_api.service_get_all(self.ctx)
|
|
self.assertEqual(4, len(services))
|
|
|
|
services_by_args = db_api.service_get_all_by_args(self.ctx,
|
|
hostname='host-2',
|
|
binary='heat-engine',
|
|
host='engine-0')
|
|
self.assertEqual(1, len(services_by_args))
|
|
self.assertEqual('host-2', services_by_args[0].hostname)
|
|
self.assertEqual('heat-engine', services_by_args[0].binary)
|
|
self.assertEqual('engine-0', services_by_args[0].host)
|
|
|
|
def test_service_update(self):
|
|
service = create_service(self.ctx)
|
|
values = {'hostname': 'host-updated',
|
|
'host': 'engine-updated',
|
|
'retry_interval': 120}
|
|
service = db_api.service_update(self.ctx, service.id, values)
|
|
self.assertEqual('host-updated', service.hostname)
|
|
self.assertEqual(120, service.retry_interval)
|
|
self.assertEqual('engine-updated', service.host)
|
|
|
|
# simple update, expected the updated_at is updated
|
|
old_updated_date = service.updated_at
|
|
service = db_api.service_update(self.ctx, service.id, dict())
|
|
self.assertGreater(service.updated_at, old_updated_date)
|
|
|
|
def test_service_delete_soft_delete(self):
|
|
service = create_service(self.ctx)
|
|
|
|
# Soft delete
|
|
db_api.service_delete(self.ctx, service.id)
|
|
ret_service = db_api.service_get(self.ctx, service.id)
|
|
self.assertEqual(ret_service.id, service.id)
|
|
|
|
# Delete
|
|
db_api.service_delete(self.ctx, service.id, False)
|
|
self.assertRaises(exception.ServiceNotFound, db_api.service_get,
|
|
self.ctx, service.id)
|
|
|
|
|
|
class DBAPIResourceUpdateTest(common.HeatTestCase):
|
|
def setUp(self):
|
|
super(DBAPIResourceUpdateTest, self).setUp()
|
|
self.ctx = utils.dummy_context()
|
|
template = create_raw_template(self.ctx)
|
|
user_creds = create_user_creds(self.ctx)
|
|
stack = create_stack(self.ctx, template, user_creds)
|
|
self.resource = create_resource(self.ctx, stack,
|
|
atomic_key=0)
|
|
|
|
def test_unlocked_resource_update(self):
|
|
values = {'engine_id': 'engine-1',
|
|
'action': 'CREATE',
|
|
'status': 'IN_PROGRESS'}
|
|
db_res = db_api.resource_get(self.ctx, self.resource.id)
|
|
ret = db_api.resource_update(self.ctx, self.resource.id,
|
|
values, db_res.atomic_key, None)
|
|
self.assertTrue(ret)
|
|
db_res = db_api.resource_get(self.ctx, self.resource.id)
|
|
self.assertEqual('engine-1', db_res.engine_id)
|
|
self.assertEqual('CREATE', db_res.action)
|
|
self.assertEqual('IN_PROGRESS', db_res.status)
|
|
self.assertEqual(1, db_res.atomic_key)
|
|
|
|
def test_locked_resource_update_by_same_engine(self):
|
|
values = {'engine_id': 'engine-1',
|
|
'action': 'CREATE',
|
|
'status': 'IN_PROGRESS'}
|
|
db_res = db_api.resource_get(self.ctx, self.resource.id)
|
|
ret = db_api.resource_update(self.ctx, self.resource.id,
|
|
values, db_res.atomic_key, None)
|
|
self.assertTrue(ret)
|
|
db_res = db_api.resource_get(self.ctx, self.resource.id)
|
|
self.assertEqual('engine-1', db_res.engine_id)
|
|
self.assertEqual(1, db_res.atomic_key)
|
|
values = {'engine_id': 'engine-1',
|
|
'action': 'CREATE',
|
|
'status': 'FAILED'}
|
|
ret = db_api.resource_update(self.ctx, self.resource.id,
|
|
values, db_res.atomic_key, 'engine-1')
|
|
self.assertTrue(ret)
|
|
db_res = db_api.resource_get(self.ctx, self.resource.id)
|
|
self.assertEqual('engine-1', db_res.engine_id)
|
|
self.assertEqual('CREATE', db_res.action)
|
|
self.assertEqual('FAILED', db_res.status)
|
|
self.assertEqual(2, db_res.atomic_key)
|
|
|
|
def test_locked_resource_update_by_other_engine(self):
|
|
values = {'engine_id': 'engine-1',
|
|
'action': 'CREATE',
|
|
'status': 'IN_PROGRESS'}
|
|
db_res = db_api.resource_get(self.ctx, self.resource.id)
|
|
ret = db_api.resource_update(self.ctx, self.resource.id,
|
|
values, db_res.atomic_key, None)
|
|
self.assertTrue(ret)
|
|
db_res = db_api.resource_get(self.ctx, self.resource.id)
|
|
self.assertEqual('engine-1', db_res.engine_id)
|
|
self.assertEqual(1, db_res.atomic_key)
|
|
values = {'engine_id': 'engine-2',
|
|
'action': 'CREATE',
|
|
'status': 'FAILED'}
|
|
ret = db_api.resource_update(self.ctx, self.resource.id,
|
|
values, db_res.atomic_key, 'engine-2')
|
|
self.assertFalse(ret)
|
|
|
|
def test_release_resource_lock(self):
|
|
values = {'engine_id': 'engine-1',
|
|
'action': 'CREATE',
|
|
'status': 'IN_PROGRESS'}
|
|
db_res = db_api.resource_get(self.ctx, self.resource.id)
|
|
ret = db_api.resource_update(self.ctx, self.resource.id,
|
|
values, db_res.atomic_key, None)
|
|
self.assertTrue(ret)
|
|
db_res = db_api.resource_get(self.ctx, self.resource.id)
|
|
self.assertEqual('engine-1', db_res.engine_id)
|
|
self.assertEqual(1, db_res.atomic_key)
|
|
# Set engine id as None to release the lock
|
|
values = {'engine_id': None,
|
|
'action': 'CREATE',
|
|
'status': 'COMPLETE'}
|
|
ret = db_api.resource_update(self.ctx, self.resource.id,
|
|
values, db_res.atomic_key, 'engine-1')
|
|
self.assertTrue(ret)
|
|
db_res = db_api.resource_get(self.ctx, self.resource.id)
|
|
self.assertIsNone(db_res.engine_id)
|
|
self.assertEqual('CREATE', db_res.action)
|
|
self.assertEqual('COMPLETE', db_res.status)
|
|
self.assertEqual(2, db_res.atomic_key)
|
|
|
|
def test_steal_resource_lock(self):
|
|
values = {'engine_id': 'engine-1',
|
|
'action': 'CREATE',
|
|
'status': 'IN_PROGRESS'}
|
|
db_res = db_api.resource_get(self.ctx, self.resource.id)
|
|
ret = db_api.resource_update(self.ctx, self.resource.id,
|
|
values, db_res.atomic_key, None)
|
|
self.assertTrue(ret)
|
|
db_res = db_api.resource_get(self.ctx, self.resource.id)
|
|
self.assertEqual('engine-1', db_res.engine_id)
|
|
self.assertEqual(1, db_res.atomic_key)
|
|
# Set engine id as engine-2 and pass expected engine id as old engine
|
|
# i.e engine-1 in db api steal the lock
|
|
values = {'engine_id': 'engine-2',
|
|
'action': 'DELETE',
|
|
'status': 'IN_PROGRESS'}
|
|
ret = db_api.resource_update(self.ctx, self.resource.id,
|
|
values, db_res.atomic_key, 'engine-1')
|
|
self.assertTrue(ret)
|
|
db_res = db_api.resource_get(self.ctx, self.resource.id)
|
|
self.assertEqual('engine-2', db_res.engine_id)
|
|
self.assertEqual('DELETE', db_res.action)
|
|
self.assertEqual(2, db_res.atomic_key)
|
|
|
|
|
|
class DBAPISyncPointTest(common.HeatTestCase):
|
|
def setUp(self):
|
|
super(DBAPISyncPointTest, self).setUp()
|
|
self.ctx = utils.dummy_context()
|
|
self.template = create_raw_template(self.ctx)
|
|
self.user_creds = create_user_creds(self.ctx)
|
|
self.stack = create_stack(self.ctx, self.template, self.user_creds)
|
|
self.resources = [create_resource(self.ctx, self.stack, name='res1'),
|
|
create_resource(self.ctx, self.stack, name='res2'),
|
|
create_resource(self.ctx, self.stack, name='res3')]
|
|
|
|
def test_sync_point_create_get(self):
|
|
for res in self.resources:
|
|
# create sync_point for resources and verify
|
|
sync_point_rsrc = create_sync_point(
|
|
self.ctx, entity_id=str(res.id), stack_id=self.stack.id,
|
|
traversal_id=self.stack.current_traversal
|
|
)
|
|
|
|
ret_sync_point_rsrc = db_api.sync_point_get(
|
|
self.ctx, sync_point_rsrc.entity_id,
|
|
sync_point_rsrc.traversal_id, sync_point_rsrc.is_update
|
|
)
|
|
|
|
self.assertIsNotNone(ret_sync_point_rsrc)
|
|
self.assertEqual(sync_point_rsrc.entity_id,
|
|
ret_sync_point_rsrc.entity_id)
|
|
self.assertEqual(sync_point_rsrc.traversal_id,
|
|
ret_sync_point_rsrc.traversal_id)
|
|
self.assertEqual(sync_point_rsrc.is_update,
|
|
ret_sync_point_rsrc.is_update)
|
|
self.assertEqual(sync_point_rsrc.atomic_key,
|
|
ret_sync_point_rsrc.atomic_key)
|
|
self.assertEqual(sync_point_rsrc.stack_id,
|
|
ret_sync_point_rsrc.stack_id)
|
|
self.assertEqual(sync_point_rsrc.input_data,
|
|
ret_sync_point_rsrc.input_data)
|
|
|
|
# Finally create sync_point for stack and verify
|
|
sync_point_stack = create_sync_point(
|
|
self.ctx, entity_id=self.stack.id, stack_id=self.stack.id,
|
|
traversal_id=self.stack.current_traversal
|
|
)
|
|
|
|
ret_sync_point_stack = db_api.sync_point_get(
|
|
self.ctx, sync_point_stack.entity_id,
|
|
sync_point_stack.traversal_id, sync_point_stack.is_update
|
|
)
|
|
|
|
self.assertIsNotNone(ret_sync_point_stack)
|
|
self.assertEqual(sync_point_stack.entity_id,
|
|
ret_sync_point_stack.entity_id)
|
|
self.assertEqual(sync_point_stack.traversal_id,
|
|
ret_sync_point_stack.traversal_id)
|
|
self.assertEqual(sync_point_stack.is_update,
|
|
ret_sync_point_stack.is_update)
|
|
self.assertEqual(sync_point_stack.atomic_key,
|
|
ret_sync_point_stack.atomic_key)
|
|
self.assertEqual(sync_point_stack.stack_id,
|
|
ret_sync_point_stack.stack_id)
|
|
self.assertEqual(sync_point_stack.input_data,
|
|
ret_sync_point_stack.input_data)
|
|
|
|
def test_sync_point_update(self):
|
|
sync_point = create_sync_point(
|
|
self.ctx, entity_id=str(self.resources[0].id),
|
|
stack_id=self.stack.id, traversal_id=self.stack.current_traversal
|
|
)
|
|
self.assertEqual({}, sync_point.input_data)
|
|
self.assertEqual(0, sync_point.atomic_key)
|
|
|
|
# first update
|
|
rows_updated = db_api.sync_point_update_input_data(
|
|
self.ctx, sync_point.entity_id, sync_point.traversal_id,
|
|
sync_point.is_update, sync_point.atomic_key,
|
|
{'input_data': '{key: value}'}
|
|
)
|
|
self.assertEqual(1, rows_updated)
|
|
|
|
ret_sync_point = db_api.sync_point_get(self.ctx,
|
|
sync_point.entity_id,
|
|
sync_point.traversal_id,
|
|
sync_point.is_update)
|
|
self.assertIsNotNone(ret_sync_point)
|
|
# check if atomic_key was incremented on write
|
|
self.assertEqual(1, ret_sync_point.atomic_key)
|
|
self.assertEqual({'input_data': '{key: value}'},
|
|
ret_sync_point.input_data)
|
|
|
|
# second update
|
|
rows_updated = db_api.sync_point_update_input_data(
|
|
self.ctx, sync_point.entity_id, sync_point.traversal_id,
|
|
sync_point.is_update, sync_point.atomic_key,
|
|
{'input_data': '{key1: value1}'}
|
|
)
|
|
self.assertEqual(1, rows_updated)
|
|
|
|
ret_sync_point = db_api.sync_point_get(self.ctx,
|
|
sync_point.entity_id,
|
|
sync_point.traversal_id,
|
|
sync_point.is_update)
|
|
self.assertIsNotNone(ret_sync_point)
|
|
# check if atomic_key was incremented on write
|
|
self.assertEqual(2, ret_sync_point.atomic_key)
|
|
self.assertEqual({'input_data': '{key1: value1}'},
|
|
ret_sync_point.input_data)
|
|
|
|
def test_sync_point_concurrent_update(self):
|
|
sync_point = create_sync_point(
|
|
self.ctx, entity_id=str(self.resources[0].id),
|
|
stack_id=self.stack.id, traversal_id=self.stack.current_traversal
|
|
)
|
|
self.assertEqual({}, sync_point.input_data)
|
|
self.assertEqual(0, sync_point.atomic_key)
|
|
|
|
# update where atomic_key is 0 and succeeds.
|
|
rows_updated = db_api.sync_point_update_input_data(
|
|
self.ctx, sync_point.entity_id, sync_point.traversal_id,
|
|
sync_point.is_update, 0, {'input_data': '{key: value}'}
|
|
)
|
|
self.assertEqual(1, rows_updated)
|
|
|
|
# another update where atomic_key is 0 and does not update.
|
|
rows_updated = db_api.sync_point_update_input_data(
|
|
self.ctx, sync_point.entity_id, sync_point.traversal_id,
|
|
sync_point.is_update, 0, {'input_data': '{key: value}'}
|
|
)
|
|
self.assertEqual(0, rows_updated)
|
|
|
|
def test_sync_point_delete(self):
|
|
for res in self.resources:
|
|
sync_point_rsrc = create_sync_point(
|
|
self.ctx, entity_id=str(res.id), stack_id=self.stack.id,
|
|
traversal_id=self.stack.current_traversal
|
|
)
|
|
self.assertIsNotNone(sync_point_rsrc)
|
|
|
|
sync_point_stack = create_sync_point(
|
|
self.ctx, entity_id=self.stack.id,
|
|
stack_id=self.stack.id,
|
|
traversal_id=self.stack.current_traversal
|
|
)
|
|
self.assertIsNotNone(sync_point_stack)
|
|
|
|
rows_deleted = db_api.sync_point_delete_all_by_stack_and_traversal(
|
|
self.ctx, self.stack.id,
|
|
self.stack.current_traversal
|
|
)
|
|
self.assertGreater(rows_deleted, 0)
|
|
self.assertEqual(4, rows_deleted)
|
|
|
|
# Additionally check if sync_point_get returns None.
|
|
for res in self.resources:
|
|
ret_sync_point_rsrc = db_api.sync_point_get(
|
|
self.ctx, str(res.id), self.stack.current_traversal, True
|
|
)
|
|
self.assertEqual(None, ret_sync_point_rsrc)
|
|
|
|
ret_sync_point_stack = db_api.sync_point_get(
|
|
self.ctx, self.stack.id, self.stack.current_traversal, True
|
|
)
|
|
self.assertEqual(None, ret_sync_point_stack)
|