Implement OS::Heat::StructuredDeployments
This is a resource which subclasses SoftwareDeployments to deploy a group of OS::Heat::StructuredDeployment resources Change-Id: I5f9603c68bb7cd81ef60a6b2ba965e5b8e93887a Implements-Blueprint: deployment-multiple-servers
This commit is contained in:
parent
0f1e84ae9f
commit
727ec1ac64
@ -21,14 +21,6 @@ from heat.engine import properties
|
||||
from heat.engine.resources.software_config import software_config as sc
|
||||
from heat.engine.resources.software_config import software_deployment as sd
|
||||
|
||||
PROPERTIES = (
|
||||
INPUT_KEY
|
||||
) = (
|
||||
'input_key'
|
||||
)
|
||||
|
||||
DEFAULT_INPUT_KEY = 'get_input'
|
||||
|
||||
|
||||
class StructuredConfig(sc.SoftwareConfig):
|
||||
'''
|
||||
@ -40,16 +32,26 @@ class StructuredConfig(sc.SoftwareConfig):
|
||||
stored and returned by the software_configs API as parsed JSON.
|
||||
'''
|
||||
|
||||
PROPERTIES = (
|
||||
GROUP,
|
||||
CONFIG,
|
||||
OPTIONS,
|
||||
INPUTS,
|
||||
OUTPUTS
|
||||
) = (
|
||||
sc.SoftwareConfig.GROUP,
|
||||
sc.SoftwareConfig.CONFIG,
|
||||
sc.SoftwareConfig.OPTIONS,
|
||||
sc.SoftwareConfig.INPUTS,
|
||||
sc.SoftwareConfig.OUTPUTS
|
||||
)
|
||||
|
||||
properties_schema = {
|
||||
sc.SoftwareConfig.GROUP: sc.SoftwareConfig.properties_schema[
|
||||
sc.SoftwareConfig.GROUP],
|
||||
sc.SoftwareConfig.OPTIONS: sc.SoftwareConfig.properties_schema[
|
||||
sc.SoftwareConfig.OPTIONS],
|
||||
sc.SoftwareConfig.INPUTS: sc.SoftwareConfig.properties_schema[
|
||||
sc.SoftwareConfig.INPUTS],
|
||||
sc.SoftwareConfig.OUTPUTS: sc.SoftwareConfig.properties_schema[
|
||||
sc.SoftwareConfig.OUTPUTS],
|
||||
sc.SoftwareConfig.CONFIG: properties.Schema(
|
||||
GROUP: sc.SoftwareConfig.properties_schema[GROUP],
|
||||
OPTIONS: sc.SoftwareConfig.properties_schema[OPTIONS],
|
||||
INPUTS: sc.SoftwareConfig.properties_schema[INPUTS],
|
||||
OUTPUTS: sc.SoftwareConfig.properties_schema[OUTPUTS],
|
||||
CONFIG: properties.Schema(
|
||||
properties.Schema.MAP,
|
||||
_('Map representing the configuration data structure which will '
|
||||
'be serialized to JSON format.')
|
||||
@ -73,32 +75,44 @@ class StructuredDeployment(sd.SoftwareDeployment):
|
||||
different input_key property value can be specified.
|
||||
'''
|
||||
|
||||
PROPERTIES = (
|
||||
CONFIG,
|
||||
SERVER,
|
||||
INPUT_VALUES,
|
||||
DEPLOY_ACTIONS,
|
||||
NAME,
|
||||
SIGNAL_TRANSPORT,
|
||||
INPUT_KEY
|
||||
) = (
|
||||
sd.SoftwareDeployment.CONFIG,
|
||||
sd.SoftwareDeployment.SERVER,
|
||||
sd.SoftwareDeployment.INPUT_VALUES,
|
||||
sd.SoftwareDeployment.DEPLOY_ACTIONS,
|
||||
sd.SoftwareDeployment.NAME,
|
||||
sd.SoftwareDeployment.SIGNAL_TRANSPORT,
|
||||
'input_key'
|
||||
)
|
||||
|
||||
_sd_ps = sd.SoftwareDeployment.properties_schema
|
||||
|
||||
properties_schema = {
|
||||
sd.SoftwareDeployment.CONFIG: _sd_ps[
|
||||
sd.SoftwareDeployment.CONFIG],
|
||||
sd.SoftwareDeployment.SERVER: _sd_ps[
|
||||
sd.SoftwareDeployment.SERVER],
|
||||
sd.SoftwareDeployment.INPUT_VALUES: _sd_ps[
|
||||
sd.SoftwareDeployment.INPUT_VALUES],
|
||||
sd.SoftwareDeployment.DEPLOY_ACTIONS: _sd_ps[
|
||||
sd.SoftwareDeployment.DEPLOY_ACTIONS],
|
||||
sd.SoftwareDeployment.SIGNAL_TRANSPORT: _sd_ps[
|
||||
sd.SoftwareDeployment.SIGNAL_TRANSPORT],
|
||||
sd.SoftwareDeployment.NAME: _sd_ps[
|
||||
sd.SoftwareDeployment.NAME],
|
||||
CONFIG: _sd_ps[CONFIG],
|
||||
SERVER: _sd_ps[SERVER],
|
||||
INPUT_VALUES: _sd_ps[INPUT_VALUES],
|
||||
DEPLOY_ACTIONS: _sd_ps[DEPLOY_ACTIONS],
|
||||
SIGNAL_TRANSPORT: _sd_ps[SIGNAL_TRANSPORT],
|
||||
NAME: _sd_ps[NAME],
|
||||
INPUT_KEY: properties.Schema(
|
||||
properties.Schema.STRING,
|
||||
_('Name of key to use for substituting inputs during deployment'),
|
||||
default=DEFAULT_INPUT_KEY,
|
||||
default='get_input',
|
||||
)
|
||||
}
|
||||
|
||||
def _build_derived_config(self, action, source,
|
||||
derived_inputs, derived_options):
|
||||
cfg = source.get(sc.SoftwareConfig.CONFIG)
|
||||
input_key = self.properties.get(INPUT_KEY)
|
||||
input_key = self.properties.get(self.INPUT_KEY)
|
||||
|
||||
inputs = dict((i['name'], i['value']) for i in derived_inputs)
|
||||
|
||||
@ -123,8 +137,56 @@ class StructuredDeployment(sd.SoftwareDeployment):
|
||||
return snippet
|
||||
|
||||
|
||||
class StructuredDeployments(sd.SoftwareDeployments):
|
||||
|
||||
PROPERTIES = (
|
||||
SERVERS,
|
||||
CONFIG,
|
||||
INPUT_VALUES,
|
||||
DEPLOY_ACTIONS,
|
||||
NAME,
|
||||
SIGNAL_TRANSPORT,
|
||||
INPUT_KEY,
|
||||
) = (
|
||||
sd.SoftwareDeployments.SERVERS,
|
||||
sd.SoftwareDeployments.CONFIG,
|
||||
sd.SoftwareDeployments.INPUT_VALUES,
|
||||
sd.SoftwareDeployments.DEPLOY_ACTIONS,
|
||||
sd.SoftwareDeployments.NAME,
|
||||
sd.SoftwareDeployments.SIGNAL_TRANSPORT,
|
||||
StructuredDeployment.INPUT_KEY
|
||||
)
|
||||
|
||||
_sds_ps = sd.SoftwareDeployments.properties_schema
|
||||
|
||||
properties_schema = {
|
||||
SERVERS: _sds_ps[SERVERS],
|
||||
CONFIG: _sds_ps[CONFIG],
|
||||
INPUT_VALUES: _sds_ps[INPUT_VALUES],
|
||||
DEPLOY_ACTIONS: _sds_ps[DEPLOY_ACTIONS],
|
||||
SIGNAL_TRANSPORT: _sds_ps[SIGNAL_TRANSPORT],
|
||||
NAME: _sds_ps[NAME],
|
||||
INPUT_KEY: StructuredDeployment.properties_schema[INPUT_KEY],
|
||||
}
|
||||
|
||||
def _build_resource_definition(self, include_all=False):
|
||||
p = self.properties
|
||||
return {
|
||||
self.RESOURCE_DEF_TYPE: 'OS::Heat::StructuredDeployment',
|
||||
self.RESOURCE_DEF_PROPERTIES: {
|
||||
self.CONFIG: p[self.CONFIG],
|
||||
self.INPUT_VALUES: p[self.INPUT_VALUES],
|
||||
self.DEPLOY_ACTIONS: p[self.DEPLOY_ACTIONS],
|
||||
self.SIGNAL_TRANSPORT: p[self.SIGNAL_TRANSPORT],
|
||||
self.NAME: p[self.NAME],
|
||||
self.INPUT_KEY: p[self.INPUT_KEY],
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def resource_mapping():
|
||||
return {
|
||||
'OS::Heat::StructuredConfig': StructuredConfig,
|
||||
'OS::Heat::StructuredDeployment': StructuredDeployment,
|
||||
'OS::Heat::StructuredDeployments': StructuredDeployments,
|
||||
}
|
||||
|
@ -50,11 +50,13 @@ class StructuredConfigTestJSON(HeatTestCase):
|
||||
|
||||
def test_resource_mapping(self):
|
||||
mapping = sc.resource_mapping()
|
||||
self.assertEqual(2, len(mapping))
|
||||
self.assertEqual(3, len(mapping))
|
||||
self.assertEqual(sc.StructuredConfig,
|
||||
mapping['OS::Heat::StructuredConfig'])
|
||||
self.assertEqual(sc.StructuredDeployment,
|
||||
mapping['OS::Heat::StructuredDeployment'])
|
||||
self.assertEqual(sc.StructuredDeployments,
|
||||
mapping['OS::Heat::StructuredDeployments'])
|
||||
self.assertIsInstance(self.config, sc.StructuredConfig)
|
||||
|
||||
def test_handle_create(self):
|
||||
@ -193,3 +195,99 @@ class StructuredDeploymentParseTest(HeatTestCase):
|
||||
self.assertEqual(
|
||||
self.result,
|
||||
parse(self.inputs, self.input_key, self.config))
|
||||
|
||||
|
||||
class StructuredDeploymentsTest(HeatTestCase):
|
||||
|
||||
template = {
|
||||
'heat_template_version': '2013-05-23',
|
||||
'resources': {
|
||||
'deploy_mysql': {
|
||||
'type': 'OS::Heat::StructuredDeployments',
|
||||
'properties': {
|
||||
'config': 'config_uuid',
|
||||
'servers': {'server1': 'uuid1', 'server2': 'uuid2'},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
def setUp(self):
|
||||
HeatTestCase.setUp(self)
|
||||
heat = mock.MagicMock()
|
||||
self.deployments = heat.return_value.software_deployments
|
||||
|
||||
def test_build_resource_definition(self):
|
||||
stack = utils.parse_stack(self.template)
|
||||
snip = stack.t.resource_definitions(stack)['deploy_mysql']
|
||||
resg = sc.StructuredDeployments('test', snip, stack)
|
||||
expect = {
|
||||
'type': 'OS::Heat::StructuredDeployment',
|
||||
'properties': {
|
||||
'actions': ['CREATE', 'UPDATE'],
|
||||
'config': 'config_uuid',
|
||||
'input_key': 'get_input',
|
||||
'input_values': None,
|
||||
'name': None,
|
||||
'signal_transport': 'CFN_SIGNAL'
|
||||
}
|
||||
}
|
||||
self.assertEqual(
|
||||
expect, resg._build_resource_definition())
|
||||
self.assertEqual(
|
||||
expect, resg._build_resource_definition(include_all=True))
|
||||
|
||||
def test_resource_names(self):
|
||||
stack = utils.parse_stack(self.template)
|
||||
snip = stack.t.resource_definitions(stack)['deploy_mysql']
|
||||
resg = sc.StructuredDeployments('test', snip, stack)
|
||||
self.assertEqual(
|
||||
set(('server1', 'server2')),
|
||||
set(resg._resource_names())
|
||||
)
|
||||
|
||||
self.assertEqual(
|
||||
set(('s1', 's2', 's3')),
|
||||
set(resg._resource_names({
|
||||
'servers': {'s1': 'u1', 's2': 'u2', 's3': 'u3'}}))
|
||||
)
|
||||
|
||||
def test_assemble_nested(self):
|
||||
"""
|
||||
Tests that the nested stack that implements the group is created
|
||||
appropriately based on properties.
|
||||
"""
|
||||
stack = utils.parse_stack(self.template)
|
||||
snip = stack.t.resource_definitions(stack)['deploy_mysql']
|
||||
resg = sc.StructuredDeployments('test', snip, stack)
|
||||
templ = {
|
||||
"heat_template_version": "2013-05-23",
|
||||
"resources": {
|
||||
"server1": {
|
||||
'type': 'OS::Heat::StructuredDeployment',
|
||||
'properties': {
|
||||
'server': 'uuid1',
|
||||
'actions': ['CREATE', 'UPDATE'],
|
||||
'config': 'config_uuid',
|
||||
'input_key': 'get_input',
|
||||
'input_values': None,
|
||||
'name': None,
|
||||
'signal_transport': 'CFN_SIGNAL'
|
||||
}
|
||||
},
|
||||
"server2": {
|
||||
'type': 'OS::Heat::StructuredDeployment',
|
||||
'properties': {
|
||||
'server': 'uuid2',
|
||||
'actions': ['CREATE', 'UPDATE'],
|
||||
'config': 'config_uuid',
|
||||
'input_key': 'get_input',
|
||||
'input_values': None,
|
||||
'name': None,
|
||||
'signal_transport': 'CFN_SIGNAL'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.assertEqual(templ, resg._assemble_nested(['server1', 'server2']))
|
||||
|
Loading…
Reference in New Issue
Block a user