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_config as sc
|
||||||
from heat.engine.resources.software_config import software_deployment as sd
|
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):
|
class StructuredConfig(sc.SoftwareConfig):
|
||||||
'''
|
'''
|
||||||
@ -40,16 +32,26 @@ class StructuredConfig(sc.SoftwareConfig):
|
|||||||
stored and returned by the software_configs API as parsed JSON.
|
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 = {
|
properties_schema = {
|
||||||
sc.SoftwareConfig.GROUP: sc.SoftwareConfig.properties_schema[
|
GROUP: sc.SoftwareConfig.properties_schema[GROUP],
|
||||||
sc.SoftwareConfig.GROUP],
|
OPTIONS: sc.SoftwareConfig.properties_schema[OPTIONS],
|
||||||
sc.SoftwareConfig.OPTIONS: sc.SoftwareConfig.properties_schema[
|
INPUTS: sc.SoftwareConfig.properties_schema[INPUTS],
|
||||||
sc.SoftwareConfig.OPTIONS],
|
OUTPUTS: sc.SoftwareConfig.properties_schema[OUTPUTS],
|
||||||
sc.SoftwareConfig.INPUTS: sc.SoftwareConfig.properties_schema[
|
CONFIG: properties.Schema(
|
||||||
sc.SoftwareConfig.INPUTS],
|
|
||||||
sc.SoftwareConfig.OUTPUTS: sc.SoftwareConfig.properties_schema[
|
|
||||||
sc.SoftwareConfig.OUTPUTS],
|
|
||||||
sc.SoftwareConfig.CONFIG: properties.Schema(
|
|
||||||
properties.Schema.MAP,
|
properties.Schema.MAP,
|
||||||
_('Map representing the configuration data structure which will '
|
_('Map representing the configuration data structure which will '
|
||||||
'be serialized to JSON format.')
|
'be serialized to JSON format.')
|
||||||
@ -73,32 +75,44 @@ class StructuredDeployment(sd.SoftwareDeployment):
|
|||||||
different input_key property value can be specified.
|
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
|
_sd_ps = sd.SoftwareDeployment.properties_schema
|
||||||
|
|
||||||
properties_schema = {
|
properties_schema = {
|
||||||
sd.SoftwareDeployment.CONFIG: _sd_ps[
|
CONFIG: _sd_ps[CONFIG],
|
||||||
sd.SoftwareDeployment.CONFIG],
|
SERVER: _sd_ps[SERVER],
|
||||||
sd.SoftwareDeployment.SERVER: _sd_ps[
|
INPUT_VALUES: _sd_ps[INPUT_VALUES],
|
||||||
sd.SoftwareDeployment.SERVER],
|
DEPLOY_ACTIONS: _sd_ps[DEPLOY_ACTIONS],
|
||||||
sd.SoftwareDeployment.INPUT_VALUES: _sd_ps[
|
SIGNAL_TRANSPORT: _sd_ps[SIGNAL_TRANSPORT],
|
||||||
sd.SoftwareDeployment.INPUT_VALUES],
|
NAME: _sd_ps[NAME],
|
||||||
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],
|
|
||||||
INPUT_KEY: properties.Schema(
|
INPUT_KEY: properties.Schema(
|
||||||
properties.Schema.STRING,
|
properties.Schema.STRING,
|
||||||
_('Name of key to use for substituting inputs during deployment'),
|
_('Name of key to use for substituting inputs during deployment'),
|
||||||
default=DEFAULT_INPUT_KEY,
|
default='get_input',
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
def _build_derived_config(self, action, source,
|
def _build_derived_config(self, action, source,
|
||||||
derived_inputs, derived_options):
|
derived_inputs, derived_options):
|
||||||
cfg = source.get(sc.SoftwareConfig.CONFIG)
|
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)
|
inputs = dict((i['name'], i['value']) for i in derived_inputs)
|
||||||
|
|
||||||
@ -123,8 +137,56 @@ class StructuredDeployment(sd.SoftwareDeployment):
|
|||||||
return snippet
|
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():
|
def resource_mapping():
|
||||||
return {
|
return {
|
||||||
'OS::Heat::StructuredConfig': StructuredConfig,
|
'OS::Heat::StructuredConfig': StructuredConfig,
|
||||||
'OS::Heat::StructuredDeployment': StructuredDeployment,
|
'OS::Heat::StructuredDeployment': StructuredDeployment,
|
||||||
|
'OS::Heat::StructuredDeployments': StructuredDeployments,
|
||||||
}
|
}
|
||||||
|
@ -50,11 +50,13 @@ class StructuredConfigTestJSON(HeatTestCase):
|
|||||||
|
|
||||||
def test_resource_mapping(self):
|
def test_resource_mapping(self):
|
||||||
mapping = sc.resource_mapping()
|
mapping = sc.resource_mapping()
|
||||||
self.assertEqual(2, len(mapping))
|
self.assertEqual(3, len(mapping))
|
||||||
self.assertEqual(sc.StructuredConfig,
|
self.assertEqual(sc.StructuredConfig,
|
||||||
mapping['OS::Heat::StructuredConfig'])
|
mapping['OS::Heat::StructuredConfig'])
|
||||||
self.assertEqual(sc.StructuredDeployment,
|
self.assertEqual(sc.StructuredDeployment,
|
||||||
mapping['OS::Heat::StructuredDeployment'])
|
mapping['OS::Heat::StructuredDeployment'])
|
||||||
|
self.assertEqual(sc.StructuredDeployments,
|
||||||
|
mapping['OS::Heat::StructuredDeployments'])
|
||||||
self.assertIsInstance(self.config, sc.StructuredConfig)
|
self.assertIsInstance(self.config, sc.StructuredConfig)
|
||||||
|
|
||||||
def test_handle_create(self):
|
def test_handle_create(self):
|
||||||
@ -193,3 +195,99 @@ class StructuredDeploymentParseTest(HeatTestCase):
|
|||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
self.result,
|
self.result,
|
||||||
parse(self.inputs, self.input_key, self.config))
|
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