RPC service for software config/deployment

These RPC service methods are wrappers over the DB API.

Implements: blueprint hot-software-config-rest
Change-Id: I2c2e53f633cca30533b9190ebccc0d6eddcfb21f
This commit is contained in:
Steve Baker 2013-11-19 08:58:29 +13:00 committed by JUN JIE NAN
parent 6cef9c42e9
commit d5cb8b461c
7 changed files with 494 additions and 0 deletions

View File

@ -280,3 +280,41 @@ def format_validate_parameter(param):
res[api.PARAM_ALLOWED_PATTERN] = c.pattern
return res
def format_software_config(sc):
if sc is None:
return
result = {
api.SOFTWARE_CONFIG_ID: sc.id,
api.SOFTWARE_CONFIG_NAME: sc.name,
api.SOFTWARE_CONFIG_GROUP: sc.group,
api.SOFTWARE_CONFIG_CONFIG: sc.config,
api.SOFTWARE_CONFIG_INPUTS: sc.io['inputs'],
api.SOFTWARE_CONFIG_OUTPUTS: sc.io['outputs'],
api.SOFTWARE_CONFIG_OPTIONS: sc.io['options']
}
return result
def format_software_deployment(sd):
if sd is None:
return
result = {
api.SOFTWARE_DEPLOYMENT_ID: sd.id,
api.SOFTWARE_DEPLOYMENT_SERVER_ID: sd.server_id,
api.SOFTWARE_DEPLOYMENT_INPUT_VALUES: sd.input_values,
api.SOFTWARE_DEPLOYMENT_OUTPUT_VALUES: sd.output_values,
api.SOFTWARE_DEPLOYMENT_ACTION: sd.action,
api.SOFTWARE_DEPLOYMENT_STATUS: sd.status,
api.SOFTWARE_DEPLOYMENT_STATUS_REASON: sd.status_reason,
api.SOFTWARE_DEPLOYMENT_SIGNAL_ID: sd.signal_id,
api.SOFTWARE_DEPLOYMENT_CONFIG_ID: sd.config.id,
api.SOFTWARE_CONFIG_CONFIG: sd.config.config,
api.SOFTWARE_CONFIG_NAME: sd.config.name,
api.SOFTWARE_CONFIG_GROUP: sd.config.group,
api.SOFTWARE_CONFIG_INPUTS: sd.config.io['inputs'],
api.SOFTWARE_CONFIG_OUTPUTS: sd.config.io['outputs'],
api.SOFTWARE_CONFIG_OPTIONS: sd.config.io['options']
}
return result

View File

@ -967,3 +967,78 @@ class EngineService(service.Service):
result = api.format_watch(wr)
result[rpc_api.WATCH_STATE_VALUE] = state
return result
@request_context
def show_software_config(self, cnxt, config_id):
sc = db_api.software_config_get(cnxt, config_id)
return api.format_software_config(sc)
@request_context
def create_software_config(self, cnxt, group, name, config,
inputs, outputs, options):
sc = db_api.software_config_create(cnxt, {
'group': group,
'name': name,
'config': config,
'io': {
'inputs': inputs,
'outputs': outputs,
'options': options
},
'tenant': cnxt.tenant_id})
return api.format_software_config(sc)
@request_context
def delete_software_config(self, cnxt, config_id):
db_api.software_config_delete(cnxt, config_id)
@request_context
def list_software_deployments(self, cnxt, server_id):
all_sd = db_api.software_deployment_get_all(cnxt, server_id)
result = [api.format_software_deployment(sd) for sd in all_sd]
return result
@request_context
def show_software_deployment(self, cnxt, deployment_id):
sd = db_api.software_deployment_get(cnxt, deployment_id)
return api.format_software_deployment(sd)
@request_context
def create_software_deployment(self, cnxt, server_id, config_id,
input_values, signal_id, action, status,
status_reason):
sd = db_api.software_deployment_create(cnxt, {
'config_id': config_id,
'server_id': server_id,
'input_values': input_values,
'signal_id': signal_id,
'tenant': cnxt.tenant_id,
'action': action,
'status': status,
'status_reason': status_reason})
return api.format_software_deployment(sd)
@request_context
def update_software_deployment(self, cnxt, deployment_id, config_id,
input_values, output_values, action,
status, status_reason):
update_data = {}
if config_id:
update_data['config_id'] = config_id
if input_values:
update_data['input_values'] = input_values
if output_values:
update_data['output_values'] = output_values
if action:
update_data['action'] = action
if status:
update_data['status'] = status
if status_reason:
update_data['status_reason'] = status_reason
sd = db_api.software_deployment_update(cnxt,
deployment_id, update_data)
return api.format_software_deployment(sd)
@request_context
def delete_software_deployment(self, cnxt, deployment_id):
db_api.software_deployment_delete(cnxt, deployment_id)

View File

@ -179,3 +179,45 @@ VALIDATE_PARAM_TYPES = (
'String', 'Number', 'CommaDelimitedList',
'Json'
)
SOFTWARE_CONFIG_KEYS = (
SOFTWARE_CONFIG_ID,
SOFTWARE_CONFIG_NAME,
SOFTWARE_CONFIG_GROUP,
SOFTWARE_CONFIG_CONFIG,
SOFTWARE_CONFIG_INPUTS,
SOFTWARE_CONFIG_OUTPUTS,
SOFTWARE_CONFIG_OPTIONS,
) = (
'id',
'name',
'group',
'config',
'inputs',
'outputs',
'options',
)
SOFTWARE_DEPLOYMENT_KEYS = (
SOFTWARE_DEPLOYMENT_ID,
SOFTWARE_DEPLOYMENT_CONFIG,
SOFTWARE_DEPLOYMENT_CONFIG_ID,
SOFTWARE_DEPLOYMENT_SERVER_ID,
SOFTWARE_DEPLOYMENT_INPUT_VALUES,
SOFTWARE_DEPLOYMENT_OUTPUT_VALUES,
SOFTWARE_DEPLOYMENT_SIGNAL_ID,
SOFTWARE_DEPLOYMENT_ACTION,
SOFTWARE_DEPLOYMENT_STATUS,
SOFTWARE_DEPLOYMENT_STATUS_REASON
) = (
'id',
'config',
'config_id',
'server_id',
'input_values',
'output_values',
'signal_id',
'action',
'status',
'status_reason'
)

View File

@ -350,3 +350,59 @@ class EngineClient(heat.openstack.common.rpc.proxy.RpcProxy):
def get_revision(self, ctxt):
return self.call(ctxt, self.make_msg('get_revision'))
def show_software_config(self, cnxt, config_id):
return self.call(cnxt, self.make_msg('show_software_config',
config_id=config_id))
def create_software_config(self, cnxt, group, name, config,
inputs=[], outputs=[], options={}):
return self.call(cnxt, self.make_msg('create_software_config',
group=group,
name=name,
config=config,
inputs=inputs,
outputs=outputs,
options=options))
def delete_software_config(self, cnxt, config_id):
return self.call(cnxt, self.make_msg('delete_software_config',
config_id=config_id))
def list_software_deployments(self, cnxt, server_id=None):
return self.call(cnxt, self.make_msg('list_software_deployments',
server_id=server_id))
def show_software_deployment(self, cnxt, deployment_id):
return self.call(cnxt, self.make_msg('show_software_deployment',
deployment_id=deployment_id))
def create_software_deployment(self, cnxt, server_id, config_id=None,
input_values={}, signal_id=None,
action='INIT', status='COMPLETE',
status_reason=''):
return self.call(cnxt, self.make_msg('create_software_deployment',
server_id=server_id,
config_id=config_id,
input_values=input_values,
signal_id=signal_id,
action=action,
status=status,
status_reason=status_reason))
def update_software_deployment(self, cnxt, deployment_id,
config_id=None, input_values=None,
output_values=None, action=None,
status=None, status_reason=None):
return self.call(cnxt, self.make_msg('update_software_deployment',
deployment_id=deployment_id,
config_id=config_id,
input_values=input_values,
output_values=output_values,
action=action,
status=status,
status_reason=status_reason))
def delete_software_deployment(self, cnxt, deployment_id):
return self.call(cnxt, self.make_msg('delete_software_deployment',
deployment_id=deployment_id))

View File

@ -14,6 +14,8 @@
import uuid
import mock
import heat.engine.api as api
from heat.common import template_format
@ -633,3 +635,50 @@ class FormatValidateParameterTest(HeatTestCase):
param = tmpl_params.params[self.param_name]
param_formated = api.format_validate_parameter(param)
self.assertEqual(self.expected, param_formated)
def _dummy_software_config(self):
config = mock.Mock()
config.name = 'config_mysql'
config.group = 'Heat::Shell'
config.config = '#!/bin/bash\n'
config.id = str(uuid.uuid4())
config.io = {
'inputs': [{'name': 'bar'}],
'outputs': [{'name': 'result'}],
'options': {}
}
return config
def _dummy_software_deployment(self):
config = self._dummy_software_config()
deployment = mock.Mock()
deployment.config = config
deployment.id = str(uuid.uuid4())
deployment.server_id = str(uuid.uuid4())
deployment.input_values = {'bar': 'baaaaa'}
deployment.output_values = {'result': '0'}
deployment.action = 'INIT'
deployment.status = 'COMPLETE'
deployment.status_reason = None
deployment.signal_id = None
return deployment
def test_format_software_config(self):
config = self._dummy_software_config()
result = api.format_software_config(config)
self.assertIsNotNone(result)
self.assertEqual([{'name': 'bar'}], result['inputs'])
self.assertEqual([{'name': 'result'}], result['outputs'])
self.assertEqual({}, result['options'])
def test_format_software_deployment(self):
deployment = self._dummy_software_deployment()
result = api.format_software_deployment(deployment)
self.assertIsNotNone(result)
self.assertEqual(deployment.config.id, result['config_id'])
self.assertEqual(
deployment.config.io['inputs'], result['inputs'])
self.assertEqual(
deployment.config.io['outputs'], result['outputs'])
self.assertEqual(
deployment.config.io['options'], result['options'])

View File

@ -17,6 +17,7 @@ import functools
from eventlet import greenpool
import json
import sys
import uuid
import mock
import mox
@ -2321,3 +2322,182 @@ class StackServiceTest(HeatTestCase):
stack_dependencies = stack.dependencies
self.assertIsInstance(stack_dependencies, dependencies.Dependencies)
self.assertEqual(2, len(stack_dependencies.graph()))
class SoftwareConfigServiceTest(HeatTestCase):
def setUp(self):
super(SoftwareConfigServiceTest, self).setUp()
self.ctx = utils.dummy_context()
self.m.StubOutWithMock(service.EngineListener, 'start')
service.EngineListener.start().AndReturn(None)
self.m.ReplayAll()
self.engine = service.EngineService('a-host', 'a-topic')
utils.setup_dummy_db()
def _create_software_config(
self, group='Heat::Shell', name='config_mysql', config=None,
inputs=[], outputs=[], options={}):
return self.engine.create_software_config(
self.ctx, group, name, config, inputs, outputs, options)
def test_show_software_config(self):
config_id = str(uuid.uuid4())
self.assertIsNone(
self.engine.show_software_config(self.ctx, config_id))
config = self._create_software_config()
config_id = config['id']
self.assertEqual(
config, self.engine.show_software_config(self.ctx, config_id))
def test_create_software_config(self):
config = self._create_software_config()
self.assertIsNotNone(config)
config_id = config['id']
config = self._create_software_config()
self.assertNotEqual(config_id, config['id'])
kwargs = {
'group': 'Heat::Chef',
'name': 'config_heat',
'config': '...',
'inputs': [{'name': 'mode'}],
'outputs': [{'name': 'endpoint'}],
'options': {}
}
config = self._create_software_config(**kwargs)
config_id = config['id']
config = self.engine.show_software_config(self.ctx, config_id)
self.assertEqual(kwargs['group'], config['group'])
self.assertEqual(kwargs['name'], config['name'])
self.assertEqual(kwargs['config'], config['config'])
self.assertEqual(kwargs['inputs'], config['inputs'])
self.assertEqual(kwargs['outputs'], config['outputs'])
self.assertEqual(kwargs['options'], config['options'])
def test_delete_software_config(self):
config = self._create_software_config()
self.assertIsNotNone(config)
config_id = config['id']
self.engine.delete_software_config(self.ctx, config_id)
config = self.engine.show_software_config(self.ctx, config_id)
self.assertIsNone(config)
def _create_software_deployment(self, config_id=None, input_values={},
signal_id=None, action='INIT',
status='COMPLETE', status_reason=''):
if config_id is None:
config = self._create_software_config()
config_id = config['id']
return self.engine.create_software_deployment(
self.ctx, str(uuid.uuid4()), config_id, input_values, signal_id,
action, status, status_reason)
def test_list_software_deployments(self):
deployment = self._create_software_deployment()
deployment_id = deployment['id']
self.assertIsNotNone(deployment)
deployments = self.engine.list_software_deployments(
self.ctx, server_id=None)
self.assertIsNotNone(deployments)
deployment_ids = [x['id'] for x in deployments]
self.assertIn(deployment_id, deployment_ids)
self.assertIn(deployment, deployments)
deployments = self.engine.list_software_deployments(
self.ctx, server_id=str(uuid.uuid4()))
self.assertEqual([], deployments)
def test_show_software_deployment(self):
deployment_id = str(uuid.uuid4())
self.assertIsNone(
self.engine.show_software_deployment(self.ctx, deployment_id))
deployment = self._create_software_deployment()
self.assertIsNotNone(deployment)
deployment_id = deployment['id']
self.assertEqual(
deployment,
self.engine.show_software_deployment(self.ctx, deployment_id))
def test_create_software_deployment(self):
kwargs = {
'group': 'Heat::Chef',
'name': 'config_heat',
'config': '...',
'inputs': [{'name': 'mode'}],
'outputs': [{'name': 'endpoint'}],
'options': {}
}
config = self._create_software_config(**kwargs)
config_id = config['id']
kwargs = {
'config_id': config_id,
'input_values': {'mode': 'standalone'},
'signal_id': None,
'action': 'INIT',
'status': 'COMPLETE',
'status_reason': ''
}
deployment = self._create_software_deployment(**kwargs)
deployment_id = deployment['id']
deployment = self.engine.show_software_deployment(
self.ctx, deployment_id)
self.assertEqual(deployment_id, deployment['id'])
self.assertEqual(config['inputs'], deployment['inputs'])
self.assertEqual(kwargs['input_values'], deployment['input_values'])
def test_update_software_deployment(self):
deployment = self._create_software_deployment()
self.assertIsNotNone(deployment)
deployment_id = deployment['id']
deployment_action = deployment['action']
self.assertEqual('INIT', deployment_action)
config_id = deployment['config_id']
self.assertIsNotNone(config_id)
updated = self.engine.update_software_deployment(
self.ctx, deployment_id=deployment_id, config_id=config_id,
input_values={}, output_values={}, action='DEPLOY',
status='WAITING', status_reason='')
self.assertIsNotNone(updated)
self.assertEqual(config_id, updated['config_id'])
self.assertEqual('DEPLOY', updated['action'])
self.assertEqual('WAITING', updated['status'])
def check_software_deployment_updated(**kwargs):
values = {
'config_id': None,
'input_values': {},
'output_values': {},
'action': {},
'status': 'WAITING',
'status_reason': ''
}
values.update(kwargs)
updated = self.engine.update_software_deployment(
self.ctx, deployment_id, **values)
for key, value in kwargs.iteritems():
self.assertEqual(value, updated[key])
check_software_deployment_updated(config_id=config_id)
check_software_deployment_updated(input_values={'foo': 'fooooo'})
check_software_deployment_updated(output_values={'bar': 'baaaaa'})
check_software_deployment_updated(action='DEPLOY')
check_software_deployment_updated(status='COMPLETE')
check_software_deployment_updated(status_reason='Done!')
def test_delete_software_deployment(self):
deployment_id = str(uuid.uuid4())
self.assertRaises(exception.NotFound,
self.engine.delete_software_deployment,
self.ctx, deployment_id)
deployment = self._create_software_deployment()
self.assertIsNotNone(deployment)
deployment_id = deployment['id']
deployments = self.engine.list_software_deployments(
self.ctx, server_id=None)
deployment_ids = [x['id'] for x in deployments]
self.assertIn(deployment_id, deployment_ids)
self.engine.delete_software_deployment(self.ctx, deployment_id)
deployments = self.engine.list_software_deployments(
self.ctx, server_id=None)
deployment_ids = [x['id'] for x in deployments]
self.assertNotIn(deployment_id, deployment_ids)

View File

@ -198,3 +198,57 @@ class EngineRpcAPITestCase(testtools.TestCase):
def test_set_watch_state(self):
self._test_engine_api('set_watch_state', 'call',
watch_name='watch1', state="xyz")
def test_show_software_config(self):
self._test_engine_api('show_software_config', 'call',
config_id='cda89008-6ea6-4057-b83d-ccde8f0b48c9')
def test_create_software_config(self):
self._test_engine_api('create_software_config', 'call',
group='Heat::Shell',
name='config_mysql',
config='#!/bin/bash',
inputs=[],
outputs=[],
options={})
def test_delete_software_config(self):
self._test_engine_api('delete_software_config', 'call',
config_id='cda89008-6ea6-4057-b83d-ccde8f0b48c9')
def test_list_software_deployments(self):
self._test_engine_api('list_software_deployments', 'call',
server_id=None)
self._test_engine_api('list_software_deployments', 'call',
server_id='9dc13236-d342-451f-a885-1c82420ba5ed')
def test_show_software_deployment(self):
deployment_id = '86729f02-4648-44d8-af44-d0ec65b6abc9'
self._test_engine_api('show_software_deployment', 'call',
deployment_id=deployment_id)
def test_create_software_deployment(self):
self._test_engine_api('create_software_deployment', 'call',
server_id='9f1f0e00-05d2-4ca5-8602-95021f19c9d0',
config_id='48e8ade1-9196-42d5-89a2-f709fde42632',
input_values={},
signal_id=None,
action='INIT',
status='COMPLETE',
status_reason=None)
def test_update_software_deployment(self):
deployment_id = '86729f02-4648-44d8-af44-d0ec65b6abc9'
self._test_engine_api('update_software_deployment', 'call',
deployment_id=deployment_id,
config_id='48e8ade1-9196-42d5-89a2-f709fde42632',
input_values={},
output_values={},
action='DEPLOYED',
status='COMPLETE',
status_reason=None)
def test_delete_software_deployment(self):
deployment_id = '86729f02-4648-44d8-af44-d0ec65b6abc9'
self._test_engine_api('delete_software_deployment', 'call',
deployment_id=deployment_id)