Merge "Database model for software config/deployment"

This commit is contained in:
Jenkins 2014-01-24 10:28:24 +00:00 committed by Gerrit Code Review
commit cb8404910b
5 changed files with 378 additions and 1 deletions

View File

@ -232,6 +232,38 @@ def watch_data_get_all(context):
return IMPL.watch_data_get_all(context)
def software_config_create(context, values):
return IMPL.software_config_create(context, values)
def software_config_get(context, config_id):
return IMPL.software_config_get(context, config_id)
def software_config_delete(context, config_id):
return IMPL.software_config_delete(context, config_id)
def software_deployment_create(context, values):
return IMPL.software_deployment_create(context, values)
def software_deployment_get(context, deployment_id):
return IMPL.software_deployment_get(context, deployment_id)
def software_deployment_get_all(context, server_id=None):
return IMPL.software_deployment_get_all(context, server_id)
def software_deployment_update(context, deployment_id, values):
return IMPL.software_deployment_update(context, deployment_id, values)
def software_deployment_delete(context, deployment_id):
return IMPL.software_deployment_delete(context, deployment_id)
def db_sync(version=None):
"""Migrate the database to `version` or the most recent version."""
return IMPL.db_sync(version=version)

View File

@ -312,7 +312,6 @@ def _paginate_query(context, query, model, limit=None, sort_keys=None,
model_marker = None
if marker:
model_marker = model_query(context, model).get(marker)
try:
query = utils.paginate_query(query, model, limit, sort_keys,
model_marker, sort_dir)
@ -617,6 +616,85 @@ def watch_data_get_all(context):
return results
def software_config_create(context, values):
obj_ref = models.SoftwareConfig()
obj_ref.update(values)
obj_ref.save(_session(context))
return obj_ref
def software_config_get(context, config_id):
result = model_query(context, models.SoftwareConfig).get(config_id)
if (result is not None and context is not None and
result.tenant != context.tenant_id):
return None
return result
def software_config_delete(context, config_id):
config = software_config_get(context, config_id)
if not config:
raise exception.NotFound(
_('Attempt to delete software config with '
'%(id)s %(msg)s') % {'id': config_id,
'msg': 'that does not exist'})
session = Session.object_session(config)
session.delete(config)
session.flush()
def software_deployment_create(context, values):
obj_ref = models.SoftwareDeployment()
obj_ref.update(values)
obj_ref.save(_session(context))
return obj_ref
def software_deployment_get(context, deployment_id):
result = model_query(context, models.SoftwareDeployment).get(deployment_id)
if (result is not None and context is not None and
result.tenant != context.tenant_id):
return None
return result
def software_deployment_get_all(context, server_id=None):
query = model_query(context, models.SoftwareDeployment).\
filter_by(tenant=context.tenant_id).\
order_by(models.SoftwareDeployment.created_at)
if server_id:
query = query.filter_by(server_id=server_id)
return query.all()
def software_deployment_update(context, deployment_id, values):
deployment = software_deployment_get(context, deployment_id)
if not deployment:
raise exception.NotFound(
_('Attempt to update sofware deployment with '
'id: %(id)s %(msg)s') % {'id': deployment_id,
'msg': 'that does not exist'})
deployment.update(values)
deployment.save(_session(context))
return deployment
def software_deployment_delete(context, deployment_id):
deployment = software_deployment_get(context, deployment_id)
if not deployment:
raise exception.NotFound(
_('Attempt to delete software deployment '
'with %(id)s %(msg)s') % {'id': deployment_id,
'msg': 'that does not exist'})
session = Session.object_session(deployment)
session.delete(deployment)
session.flush()
def purge_deleted(age, granularity='days'):
try:
age = int(age)

View File

@ -0,0 +1,87 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import sqlalchemy
from sqlalchemy.dialects import mysql
def upgrade(migrate_engine):
meta = sqlalchemy.MetaData()
meta.bind = migrate_engine
if migrate_engine.name == 'mysql':
long_text = mysql.LONGTEXT()
else:
long_text = sqlalchemy.Text
software_config = sqlalchemy.Table(
'software_config', meta,
sqlalchemy.Column('id', sqlalchemy.String(36),
primary_key=True,
nullable=False),
sqlalchemy.Column('created_at', sqlalchemy.DateTime),
sqlalchemy.Column('updated_at', sqlalchemy.DateTime),
sqlalchemy.Column('name', sqlalchemy.String(255),
nullable=True),
sqlalchemy.Column('group', sqlalchemy.String(255)),
sqlalchemy.Column('config', long_text),
sqlalchemy.Column('io', long_text),
sqlalchemy.Column('tenant', sqlalchemy.String(256),
nullable=False,
index=True),
mysql_engine='InnoDB',
mysql_charset='utf8'
)
software_config.create()
software_deployment = sqlalchemy.Table(
'software_deployment', meta,
sqlalchemy.Column('id', sqlalchemy.String(36),
primary_key=True,
nullable=False),
sqlalchemy.Column('created_at', sqlalchemy.DateTime,
index=True),
sqlalchemy.Column('updated_at', sqlalchemy.DateTime),
sqlalchemy.Column('server_id', sqlalchemy.String(36),
nullable=False,
index=True),
sqlalchemy.Column('config_id',
sqlalchemy.String(36),
sqlalchemy.ForeignKey('software_config.id'),
nullable=False),
sqlalchemy.Column('input_values', long_text),
sqlalchemy.Column('output_values', long_text),
sqlalchemy.Column('signal_id', sqlalchemy.String(1024)),
sqlalchemy.Column('action', sqlalchemy.String(255)),
sqlalchemy.Column('status', sqlalchemy.String(255)),
sqlalchemy.Column('status_reason', sqlalchemy.String(255)),
sqlalchemy.Column('tenant', sqlalchemy.String(256),
nullable=False,
index=True),
mysql_engine='InnoDB',
mysql_charset='utf8'
)
software_deployment.create()
def downgrade(migrate_engine):
meta = sqlalchemy.MetaData()
meta.bind = migrate_engine
software_deployment = sqlalchemy.Table(
'software_deployment', meta, autoload=True)
software_deployment.drop()
software_config = sqlalchemy.Table(
'software_config', meta, autoload=True)
software_config.drop()

View File

@ -243,3 +243,50 @@ class WatchData(BASE, HeatBase):
sqlalchemy.ForeignKey('watch_rule.id'),
nullable=False)
watch_rule = relationship(WatchRule, backref=backref('watch_data'))
class SoftwareConfig(BASE, HeatBase):
"""
Represents a software configuration resource to be applied to
one or more servers.
"""
__tablename__ = 'software_config'
id = sqlalchemy.Column('id', sqlalchemy.String(36), primary_key=True,
default=lambda: str(uuid.uuid4()))
name = sqlalchemy.Column('name', sqlalchemy.String(255),
nullable=True)
group = sqlalchemy.Column('group', sqlalchemy.String(255))
config = sqlalchemy.Column('config', sqlalchemy.Text)
io = sqlalchemy.Column('io', Json)
tenant = sqlalchemy.Column(
'tenant', sqlalchemy.String(256), nullable=False)
class SoftwareDeployment(BASE, HeatBase):
"""
Represents applying a software configuration resource to a
single server resource.
"""
__tablename__ = 'software_deployment'
id = sqlalchemy.Column('id', sqlalchemy.String(36), primary_key=True,
default=lambda: str(uuid.uuid4()))
config_id = sqlalchemy.Column(
'config_id',
sqlalchemy.String(36),
sqlalchemy.ForeignKey('software_config.id'),
nullable=False)
config = relationship(SoftwareConfig, backref=backref('deployments'))
server_id = sqlalchemy.Column('server_id', sqlalchemy.String(36),
nullable=False)
input_values = sqlalchemy.Column('input_values', Json)
output_values = sqlalchemy.Column('output_values', Json)
signal_id = sqlalchemy.Column(sqlalchemy.String(1024))
tenant = sqlalchemy.Column(
'tenant', sqlalchemy.String(256), nullable=False)
action = sqlalchemy.Column('action', sqlalchemy.String(255))
status = sqlalchemy.Column('status', sqlalchemy.String(255))
status_reason = sqlalchemy.Column('status_reason', sqlalchemy.String(255))

View File

@ -617,6 +617,139 @@ class SqlAlchemyTest(HeatTestCase):
self.assertIsNone(load_creds.get('password'))
self.assertIsNone(load_creds.get('trust_id'))
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.assertIsNone(
db_api.software_config_get(self.ctx, str(uuid.uuid4())))
io = {'inputs': [{'name': 'foo'}, {'name': 'bar'}],
'outputs': [{'name': 'result'}]}
tenant_id = self.ctx.tenant_id
conf = ('#!/bin/bash\n'
'echo "$bar and $foo"\n')
values = {'name': 'config_mysql',
'tenant': tenant_id,
'group': 'Heat::Shell',
'config': conf,
'io': io}
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)
self.assertEqual(io, config.io)
self.ctx.tenant_id = None
config = db_api.software_config_get(self.ctx, config_id)
self.assertIsNone(config)
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)
config = db_api.software_config_get(self.ctx, config_id)
self.assertIsNone(config)
err = self.assertRaises(
exception.NotFound, db_api.software_config_delete,
self.ctx, config_id)
self.assertIn(config_id, str(err))
def _deployment_values(self):
tenant_id = self.ctx.tenant_id
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,
'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.assertIsNone(
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.ctx.tenant_id = None
deployment = db_api.software_deployment_get(self.ctx, deployment_id)
self.assertIsNone(deployment)
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, str(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, str(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)
deployment = db_api.software_deployment_get(self.ctx, deployment_id)
self.assertIsNone(deployment)
def create_raw_template(context, **kwargs):
t = template_format.parse(wp_template)