Merge "Improve OS::Trove::Instance resource"
This commit is contained in:
commit
755bdb379b
@ -11,6 +11,8 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from troveclient.openstack.common.apiclient import exceptions as troveexc
|
||||
|
||||
from heat.common import exception
|
||||
from heat.engine import attributes
|
||||
from heat.engine.clients import troveclient
|
||||
@ -29,6 +31,14 @@ class OSDBInstance(resource.Resource):
|
||||
OpenStack cloud database instance resource.
|
||||
'''
|
||||
|
||||
TROVE_STATUS = (
|
||||
ERROR, FAILED, ACTIVE,
|
||||
) = (
|
||||
'ERROR', 'FAILED', 'ACTIVE',
|
||||
)
|
||||
|
||||
BAD_STATUSES = (ERROR, FAILED)
|
||||
|
||||
PROPERTIES = (
|
||||
NAME, FLAVOR, SIZE, DATABASES, USERS, AVAILABILITY_ZONE,
|
||||
RESTORE_POINT,
|
||||
@ -59,7 +69,6 @@ class OSDBInstance(resource.Resource):
|
||||
NAME: properties.Schema(
|
||||
properties.Schema.STRING,
|
||||
_('Name of the DB instance to create.'),
|
||||
required=True,
|
||||
constraints=[
|
||||
constraints.Length(max=255),
|
||||
]
|
||||
@ -153,7 +162,10 @@ class OSDBInstance(resource.Resource):
|
||||
schema=properties.Schema(
|
||||
properties.Schema.STRING,
|
||||
),
|
||||
required=True
|
||||
required=True,
|
||||
constraints=[
|
||||
constraints.Length(min=1),
|
||||
]
|
||||
),
|
||||
},
|
||||
)
|
||||
@ -190,18 +202,17 @@ class OSDBInstance(resource.Resource):
|
||||
|
||||
return self._dbinstance
|
||||
|
||||
def physical_resource_name(self):
|
||||
def _dbinstance_name(self):
|
||||
name = self.properties.get(self.NAME)
|
||||
if name:
|
||||
return name
|
||||
|
||||
return super(OSDBInstance, self).physical_resource_name()
|
||||
return self.physical_resource_name()
|
||||
|
||||
def handle_create(self):
|
||||
'''
|
||||
Create cloud database instance.
|
||||
'''
|
||||
self.dbinstancename = self.physical_resource_name()
|
||||
self.flavor = nova_utils.get_flavor_id(self.trove(),
|
||||
self.properties[self.FLAVOR])
|
||||
self.volume = {'size': self.properties[self.SIZE]}
|
||||
@ -218,7 +229,7 @@ class OSDBInstance(resource.Resource):
|
||||
|
||||
# create db instance
|
||||
instance = self.trove().instances.create(
|
||||
self.dbinstancename,
|
||||
self._dbinstance_name(),
|
||||
self.flavor,
|
||||
volume=self.volume,
|
||||
databases=self.databases,
|
||||
@ -243,17 +254,16 @@ class OSDBInstance(resource.Resource):
|
||||
'''
|
||||
Check if cloud DB instance creation is complete.
|
||||
'''
|
||||
self._refresh_instance(instance)
|
||||
|
||||
if instance.status == 'ERROR':
|
||||
self._refresh_instance(instance) # get updated attributes
|
||||
if instance.status in self.BAD_STATUSES:
|
||||
raise exception.Error(_("Database instance creation failed."))
|
||||
|
||||
if instance.status != 'ACTIVE':
|
||||
if instance.status != self.ACTIVE:
|
||||
return False
|
||||
|
||||
msg = _("Database instance %(database)s created (flavor:%(flavor)s, "
|
||||
"volume:%(volume)s)")
|
||||
LOG.info(msg % ({'database': self.dbinstancename,
|
||||
LOG.info(msg % ({'database': self._dbinstance_name(),
|
||||
'flavor': self.flavor,
|
||||
'volume': self.volume}))
|
||||
return True
|
||||
@ -268,7 +278,7 @@ class OSDBInstance(resource.Resource):
|
||||
instance = None
|
||||
try:
|
||||
instance = self.trove().instances.get(self.resource_id)
|
||||
except troveclient.exceptions.NotFound:
|
||||
except troveexc.NotFound:
|
||||
LOG.debug("Database instance %s not found." % self.resource_id)
|
||||
self.resource_id_set(None)
|
||||
else:
|
||||
@ -277,14 +287,15 @@ class OSDBInstance(resource.Resource):
|
||||
|
||||
def check_delete_complete(self, instance):
|
||||
'''
|
||||
Check for completion of cloud DB instance delettion
|
||||
Check for completion of cloud DB instance deletion
|
||||
'''
|
||||
if not instance:
|
||||
return True
|
||||
|
||||
try:
|
||||
# For some time trove instance may continue to live
|
||||
self._refresh_instance(instance)
|
||||
except troveclient.exceptions.NotFound:
|
||||
except troveexc.NotFound:
|
||||
self.resource_id_set(None)
|
||||
return True
|
||||
|
||||
@ -305,23 +316,19 @@ class OSDBInstance(resource.Resource):
|
||||
|
||||
databases = self.properties.get(self.DATABASES)
|
||||
if not databases:
|
||||
msg = _('Databases property is required if users property'
|
||||
' is provided')
|
||||
msg = _('Databases property is required if users property '
|
||||
'is provided for resource %s.') % self.name
|
||||
raise exception.StackValidationFailed(message=msg)
|
||||
|
||||
db_names = set([db[self.DATABASE_NAME] for db in databases])
|
||||
for user in users:
|
||||
if not user.get(self.USER_DATABASES, []):
|
||||
msg = _('Must provide access to at least one database for '
|
||||
'user %s') % user[self.USER_NAME]
|
||||
raise exception.StackValidationFailed(message=msg)
|
||||
|
||||
missing_db = [db_name for db_name in user[self.USER_DATABASES]
|
||||
if db_name not in db_names]
|
||||
|
||||
if missing_db:
|
||||
msg = _('Database %s specified for user does not exist in '
|
||||
'databases.') % missing_db
|
||||
msg = (_('Database %(dbs)s specified for user does '
|
||||
'not exist in databases for resource %(name)s.')
|
||||
% {'dbs': missing_db, 'name': self.name})
|
||||
raise exception.StackValidationFailed(message=msg)
|
||||
|
||||
def href(self):
|
||||
|
@ -16,7 +16,6 @@ import uuid
|
||||
from heat.common import exception
|
||||
from heat.common import template_format
|
||||
from heat.engine.clients import troveclient
|
||||
from heat.engine import environment
|
||||
from heat.engine import parser
|
||||
from heat.engine.resources import os_database
|
||||
from heat.engine import scheduler
|
||||
@ -24,27 +23,10 @@ from heat.tests.common import HeatTestCase
|
||||
from heat.tests import utils
|
||||
|
||||
|
||||
wp_template = '''
|
||||
db_template = '''
|
||||
{
|
||||
"AWSTemplateFormatVersion" : "2010-09-09",
|
||||
"Description" : "MySQL instance running on openstack DBaaS cloud",
|
||||
"Parameters" : {
|
||||
"flavor": {
|
||||
"Description" : "Flavor reference",
|
||||
"Type": "String",
|
||||
"Default": '1GB'
|
||||
},
|
||||
"size": {
|
||||
"Description" : "The volume size",
|
||||
"Type": "Number",
|
||||
"Default": '30'
|
||||
},
|
||||
"name": {
|
||||
"Description" : "The database instance name",
|
||||
"Type": "String",
|
||||
"Default": "OpenstackDbaas"
|
||||
}
|
||||
},
|
||||
"Resources" : {
|
||||
"MySqlCloudDB": {
|
||||
"Type": "OS::Trove::Instance",
|
||||
@ -91,14 +73,12 @@ class OSDBInstanceTest(HeatTestCase):
|
||||
super(OSDBInstanceTest, self).setUp()
|
||||
self.fc = self.m.CreateMockAnything()
|
||||
|
||||
def _setup_test_clouddbinstance(self, name, parsed_t):
|
||||
def _setup_test_clouddbinstance(self, name, t):
|
||||
stack_name = '%s_stack' % name
|
||||
t = parsed_t
|
||||
template = parser.Template(t)
|
||||
stack = parser.Stack(utils.dummy_context(),
|
||||
stack_name,
|
||||
template,
|
||||
environment.Environment({'name': 'test'}),
|
||||
stack_id=str(uuid.uuid4()))
|
||||
|
||||
instance = os_database.OSDBInstance(
|
||||
@ -131,7 +111,7 @@ class OSDBInstanceTest(HeatTestCase):
|
||||
|
||||
def test_osdatabase_create(self):
|
||||
fake_dbinstance = FakeDBInstance()
|
||||
t = template_format.parse(wp_template)
|
||||
t = template_format.parse(db_template)
|
||||
instance = self._setup_test_clouddbinstance('dbinstance_create', t)
|
||||
self._stubout_create(instance, fake_dbinstance)
|
||||
scheduler.TaskRunner(instance.create)()
|
||||
@ -140,7 +120,7 @@ class OSDBInstanceTest(HeatTestCase):
|
||||
|
||||
def test_osdatabase_create_overlimit(self):
|
||||
fake_dbinstance = FakeDBInstance()
|
||||
t = template_format.parse(wp_template)
|
||||
t = template_format.parse(db_template)
|
||||
instance = self._setup_test_clouddbinstance('dbinstance_create', t)
|
||||
|
||||
self._stubout_create(instance, fake_dbinstance)
|
||||
@ -159,7 +139,7 @@ class OSDBInstanceTest(HeatTestCase):
|
||||
def test_osdatabase_create_fails(self):
|
||||
fake_dbinstance = FakeDBInstance()
|
||||
fake_dbinstance.status = 'ERROR'
|
||||
t = template_format.parse(wp_template)
|
||||
t = template_format.parse(db_template)
|
||||
instance = self._setup_test_clouddbinstance('dbinstance_create', t)
|
||||
self._stubout_create(instance, fake_dbinstance)
|
||||
self.assertRaises(exception.ResourceFailure,
|
||||
@ -168,7 +148,7 @@ class OSDBInstanceTest(HeatTestCase):
|
||||
|
||||
def test_osdatabase_delete(self):
|
||||
fake_dbinstance = FakeDBInstance()
|
||||
t = template_format.parse(wp_template)
|
||||
t = template_format.parse(db_template)
|
||||
instance = self._setup_test_clouddbinstance('dbinstance_del', t)
|
||||
self._stubout_create(instance, fake_dbinstance)
|
||||
scheduler.TaskRunner(instance.create)()
|
||||
@ -187,7 +167,7 @@ class OSDBInstanceTest(HeatTestCase):
|
||||
|
||||
def test_osdatabase_delete_overlimit(self):
|
||||
fake_dbinstance = FakeDBInstance()
|
||||
t = template_format.parse(wp_template)
|
||||
t = template_format.parse(db_template)
|
||||
instance = self._setup_test_clouddbinstance('dbinstance_del', t)
|
||||
self._stubout_create(instance, fake_dbinstance)
|
||||
scheduler.TaskRunner(instance.create)()
|
||||
@ -210,7 +190,7 @@ class OSDBInstanceTest(HeatTestCase):
|
||||
|
||||
def test_osdatabase_delete_resource_none(self):
|
||||
fake_dbinstance = FakeDBInstance()
|
||||
t = template_format.parse(wp_template)
|
||||
t = template_format.parse(db_template)
|
||||
instance = self._setup_test_clouddbinstance('dbinstance_del', t)
|
||||
self._stubout_create(instance, fake_dbinstance)
|
||||
scheduler.TaskRunner(instance.create)()
|
||||
@ -223,7 +203,7 @@ class OSDBInstanceTest(HeatTestCase):
|
||||
|
||||
def test_osdatabase_resource_not_found(self):
|
||||
fake_dbinstance = FakeDBInstance()
|
||||
t = template_format.parse(wp_template)
|
||||
t = template_format.parse(db_template)
|
||||
instance = self._setup_test_clouddbinstance('dbinstance_del', t)
|
||||
self._stubout_create(instance, fake_dbinstance)
|
||||
scheduler.TaskRunner(instance.create)()
|
||||
@ -237,7 +217,7 @@ class OSDBInstanceTest(HeatTestCase):
|
||||
self.m.VerifyAll()
|
||||
|
||||
def test_osdatabase_invalid_attribute(self):
|
||||
t = template_format.parse(wp_template)
|
||||
t = template_format.parse(db_template)
|
||||
instance = self._setup_test_clouddbinstance("db_invalid_attrib", t)
|
||||
attrib = instance._resolve_attribute("invalid_attrib")
|
||||
self.assertIsNone(attrib)
|
||||
@ -245,7 +225,7 @@ class OSDBInstanceTest(HeatTestCase):
|
||||
|
||||
def test_osdatabase_get_hostname(self):
|
||||
fake_dbinstance = FakeDBInstance()
|
||||
t = template_format.parse(wp_template)
|
||||
t = template_format.parse(db_template)
|
||||
instance = self._setup_test_clouddbinstance('dbinstance_test', t)
|
||||
instance.resource_id = 12345
|
||||
self.m.StubOutWithMock(instance, 'trove')
|
||||
@ -260,7 +240,7 @@ class OSDBInstanceTest(HeatTestCase):
|
||||
|
||||
def test_osdatabase_get_href(self):
|
||||
fake_dbinstance = FakeDBInstance()
|
||||
t = template_format.parse(wp_template)
|
||||
t = template_format.parse(db_template)
|
||||
instance = self._setup_test_clouddbinstance('dbinstance_test', t)
|
||||
instance.resource_id = 12345
|
||||
self.m.StubOutWithMock(instance, 'trove')
|
||||
@ -271,11 +251,12 @@ class OSDBInstanceTest(HeatTestCase):
|
||||
self.m.ReplayAll()
|
||||
attrib = instance._resolve_attribute('href')
|
||||
self.assertEqual(fake_dbinstance.links[0]['href'], attrib)
|
||||
self.m.VerifyAll()
|
||||
|
||||
def test_osdatabase_get_href_links_none(self):
|
||||
fake_dbinstance = FakeDBInstance()
|
||||
fake_dbinstance.links = None
|
||||
t = template_format.parse(wp_template)
|
||||
t = template_format.parse(db_template)
|
||||
instance = self._setup_test_clouddbinstance('dbinstance_test', t)
|
||||
instance.resource_id = 12345
|
||||
self.m.StubOutWithMock(instance, 'trove')
|
||||
@ -286,15 +267,17 @@ class OSDBInstanceTest(HeatTestCase):
|
||||
self.m.ReplayAll()
|
||||
attrib = instance._resolve_attribute('href')
|
||||
self.assertIsNone(attrib)
|
||||
self.m.VerifyAll()
|
||||
|
||||
def test_osdatabase_prop_validation_success(self):
|
||||
t = template_format.parse(wp_template)
|
||||
t = template_format.parse(db_template)
|
||||
instance = self._setup_test_clouddbinstance('dbinstance_test', t)
|
||||
ret = instance.validate()
|
||||
self.assertIsNone(ret)
|
||||
self.m.VerifyAll()
|
||||
|
||||
def test_osdatabase_prop_validation_invaliddb(self):
|
||||
t = template_format.parse(wp_template)
|
||||
t = template_format.parse(db_template)
|
||||
t['Resources']['MySqlCloudDB']['Properties']['databases'] = [
|
||||
{"name": "onedb"}]
|
||||
t['Resources']['MySqlCloudDB']['Properties']['users'] = [
|
||||
@ -303,16 +286,18 @@ class OSDBInstanceTest(HeatTestCase):
|
||||
"databases": ["invaliddb"]}]
|
||||
instance = self._setup_test_clouddbinstance('dbinstance_test', t)
|
||||
self.assertRaises(exception.StackValidationFailed, instance.validate)
|
||||
self.m.VerifyAll()
|
||||
|
||||
def test_osdatabase_prop_validation_users_none(self):
|
||||
t = template_format.parse(wp_template)
|
||||
t = template_format.parse(db_template)
|
||||
t['Resources']['MySqlCloudDB']['Properties']['users'] = []
|
||||
instance = self._setup_test_clouddbinstance('dbinstance_test', t)
|
||||
ret = instance.validate()
|
||||
self.assertIsNone(ret)
|
||||
self.m.VerifyAll()
|
||||
|
||||
def test_osdatabase_prop_validation_databases_none(self):
|
||||
t = template_format.parse(wp_template)
|
||||
t = template_format.parse(db_template)
|
||||
t['Resources']['MySqlCloudDB']['Properties']['databases'] = []
|
||||
t['Resources']['MySqlCloudDB']['Properties']['users'] = [
|
||||
{"name": "testuser",
|
||||
@ -320,9 +305,10 @@ class OSDBInstanceTest(HeatTestCase):
|
||||
"databases": ["invaliddb"]}]
|
||||
instance = self._setup_test_clouddbinstance('dbinstance_test', t)
|
||||
self.assertRaises(exception.StackValidationFailed, instance.validate)
|
||||
self.m.VerifyAll()
|
||||
|
||||
def test_osdatabase_prop_validation_user_no_db(self):
|
||||
t = template_format.parse(wp_template)
|
||||
t = template_format.parse(db_template)
|
||||
t['Resources']['MySqlCloudDB']['Properties']['databases'] = [
|
||||
{"name": "validdb"}]
|
||||
t['Resources']['MySqlCloudDB']['Properties']['users'] = [
|
||||
@ -330,3 +316,4 @@ class OSDBInstanceTest(HeatTestCase):
|
||||
|
||||
instance = self._setup_test_clouddbinstance('dbinstance_test', t)
|
||||
self.assertRaises(exception.StackValidationFailed, instance.validate)
|
||||
self.m.VerifyAll()
|
||||
|
Loading…
Reference in New Issue
Block a user