nova-less-deploy: implement deploy_roles workflow
This workflow allows to deploy a given number of nodes from each role. It includes generating a suitable environment to use with deployed-server. Change-Id: I62673f5abda74beab4c1848b96f1ea4746ac3b6d Implements: blueprint nova-less-deploy
This commit is contained in:
parent
122b9ff3e0
commit
3f83b61611
@ -83,6 +83,8 @@ mistral.actions =
|
||||
tripleo.baremetal.probe_node = tripleo_common.actions.baremetal:ProbeNode
|
||||
tripleo.baremetal_deploy.check_existing_instances = tripleo_common.actions.baremetal_deploy:CheckExistingInstancesAction
|
||||
tripleo.baremetal_deploy.deploy_node = tripleo_common.actions.baremetal_deploy:DeployNodeAction
|
||||
tripleo.baremetal_deploy.expand_roles = tripleo_common.actions.baremetal_deploy:ExpandRolesAction
|
||||
tripleo.baremetal_deploy.populate_environment = tripleo_common.actions.baremetal_deploy:PopulateEnvironmentAction
|
||||
tripleo.baremetal_deploy.reserve_nodes = tripleo_common.actions.baremetal_deploy:ReserveNodesAction
|
||||
tripleo.baremetal_deploy.undeploy_instance = tripleo_common.actions.baremetal_deploy:UndeployInstanceAction
|
||||
tripleo.baremetal_deploy.wait_for_deploy = tripleo_common.actions.baremetal_deploy:WaitForDeploymentAction
|
||||
|
@ -12,6 +12,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
import copy
|
||||
import logging
|
||||
|
||||
import jsonschema
|
||||
@ -32,42 +33,62 @@ def _provisioner(context):
|
||||
return metalsmith.Provisioner(session=session)
|
||||
|
||||
|
||||
_INSTANCE_SCHEMA = {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'capabilities': {'type': 'object'},
|
||||
'hostname': {'type': 'string',
|
||||
'minLength': 2,
|
||||
'maxLength': 255},
|
||||
'image': {'type': 'string'},
|
||||
'image_checksum': {'type': 'string'},
|
||||
'image_kernel': {'type': 'string'},
|
||||
'image_ramdisk': {'type': 'string'},
|
||||
'name': {'type': 'string'},
|
||||
'nics': {'type': 'array',
|
||||
'items': {'type': 'object',
|
||||
'properties': {
|
||||
'network': {'type': 'string'},
|
||||
'port': {'type': 'string'},
|
||||
'fixed_ip': {'type': 'string'},
|
||||
'subnet': {'type': 'string'},
|
||||
},
|
||||
'additionalProperties': False}},
|
||||
'profile': {'type': 'string'},
|
||||
'resource_class': {'type': 'string'},
|
||||
'root_size_gb': {'type': 'integer', 'minimum': 4},
|
||||
'swap_size_mb': {'type': 'integer', 'minimum': 64},
|
||||
'traits': {'type': 'array',
|
||||
'items': {'type': 'string'}},
|
||||
},
|
||||
'additionalProperties': False,
|
||||
}
|
||||
|
||||
|
||||
_INSTANCES_INPUT_SCHEMA = {
|
||||
'type': 'array',
|
||||
'items': _INSTANCE_SCHEMA
|
||||
}
|
||||
"""JSON schema of the instances list."""
|
||||
|
||||
|
||||
_ROLES_INPUT_SCHEMA = {
|
||||
'type': 'array',
|
||||
'items': {
|
||||
'type': 'object',
|
||||
'properties': {
|
||||
'capabilities': {'type': 'object'},
|
||||
'hostname': {'type': 'string',
|
||||
'minLength': 2,
|
||||
'maxLength': 255},
|
||||
'image': {'type': 'string'},
|
||||
'image_checksum': {'type': 'string'},
|
||||
'image_kernel': {'type': 'string'},
|
||||
'image_ramdisk': {'type': 'string'},
|
||||
'name': {'type': 'string'},
|
||||
'nics': {'type': 'array',
|
||||
'items': {'type': 'object',
|
||||
'properties': {
|
||||
'network': {'type': 'string'},
|
||||
'port': {'type': 'string'},
|
||||
'fixed_ip': {'type': 'string'},
|
||||
'subnet': {'type': 'string'},
|
||||
},
|
||||
'additionalProperties': False}},
|
||||
'count': {'type': 'integer', 'minimum': 0},
|
||||
'profile': {'type': 'string'},
|
||||
'resource_class': {'type': 'string'},
|
||||
'root_size_gb': {'type': 'integer', 'minimum': 4},
|
||||
'swap_size_mb': {'type': 'integer', 'minimum': 64},
|
||||
'traits': {'type': 'array',
|
||||
'items': {'type': 'string'}},
|
||||
'hostname_format': {'type': 'string'},
|
||||
'instances': {'type': 'array',
|
||||
'items': _INSTANCE_SCHEMA},
|
||||
},
|
||||
'additionalProperties': False,
|
||||
# Host name is required, but defaults to name in _validate_instances
|
||||
'required': ['hostname'],
|
||||
'required': ['name'],
|
||||
}
|
||||
}
|
||||
"""JSON schema of the input for these actions."""
|
||||
"""JSON schema of the roles list."""
|
||||
|
||||
|
||||
class CheckExistingInstancesAction(base.TripleOAction):
|
||||
@ -113,7 +134,8 @@ class CheckExistingInstancesAction(base.TripleOAction):
|
||||
"hostname") % (request['hostname'], instance.uuid)
|
||||
return actions.Result(error=error)
|
||||
|
||||
found.append(instance.to_dict())
|
||||
found.append(_instance_to_dict(provisioner.connection,
|
||||
instance))
|
||||
|
||||
if found:
|
||||
LOG.info('Found existing instances: %s',
|
||||
@ -241,7 +263,7 @@ class DeployNodeAction(base.TripleOAction):
|
||||
|
||||
LOG.info('Started provisioning of %s on node %s',
|
||||
self.instance, self.node)
|
||||
return instance.to_dict()
|
||||
return _instance_to_dict(provisioner.connection, instance)
|
||||
|
||||
|
||||
class WaitForDeploymentAction(base.TripleOAction):
|
||||
@ -269,7 +291,7 @@ class WaitForDeploymentAction(base.TripleOAction):
|
||||
)
|
||||
LOG.info('Successfully provisioned instance %s',
|
||||
self.instance['hostname'])
|
||||
return instance.to_dict()
|
||||
return _instance_to_dict(provisioner.connection, instance)
|
||||
|
||||
|
||||
class UndeployInstanceAction(base.TripleOAction):
|
||||
@ -295,11 +317,101 @@ class UndeployInstanceAction(base.TripleOAction):
|
||||
LOG.info('Successfully unprovisioned %s', instance.hostname)
|
||||
|
||||
|
||||
class ExpandRolesAction(base.TripleOAction):
|
||||
"""Convert a baremetal_deployment file to list of instances."""
|
||||
|
||||
def __init__(self, roles, stackname='overcloud'):
|
||||
super(ExpandRolesAction, self).__init__()
|
||||
self.roles = roles
|
||||
self.stackname = stackname
|
||||
|
||||
def run(self, context):
|
||||
try:
|
||||
_validate_roles(self.roles, stackname=self.stackname)
|
||||
except Exception as exc:
|
||||
LOG.error('Failed to validate the request. %s', exc)
|
||||
return actions.Result(error=six.text_type(exc))
|
||||
|
||||
instances = []
|
||||
parameter_defaults = {'HostnameMap': {}}
|
||||
for role in self.roles:
|
||||
name = role['name']
|
||||
hostname_format = role.get('hostname_format')
|
||||
if not hostname_format:
|
||||
hostname_format = '%stackname%-{}-%index%'.format(
|
||||
'novacompute' if name == 'Compute' else name.lower())
|
||||
# NOTE(dtantsur): our hostname format may differ from THT defaults,
|
||||
# so override it in the resulting environment
|
||||
parameter_defaults['%sDeployedServerHostnameFormat' % name] = (
|
||||
hostname_format)
|
||||
|
||||
if 'instances' in role:
|
||||
parameter_defaults['%sDeployedServerCount' % name] = len(
|
||||
role['instances'])
|
||||
# TODO(dtantsur): ordering-dependent logic here, can we do
|
||||
# better?
|
||||
for index, instance in enumerate(role['instances']):
|
||||
# _validate_instances ensures that either of these is
|
||||
# not empty
|
||||
hostname = instance.get('hostname') or instance.get('name')
|
||||
gen_name = (hostname_format.replace('%index%', str(index))
|
||||
.replace('%stackname%', self.stackname))
|
||||
parameter_defaults['HostnameMap'][gen_name] = hostname
|
||||
instances.append(instance)
|
||||
else:
|
||||
count = role.get('count', 1)
|
||||
parameter_defaults['%sDeployedServerCount' % name] = count
|
||||
if not count:
|
||||
continue
|
||||
|
||||
for index in range(count):
|
||||
hostname = (hostname_format.replace('%index%', str(index))
|
||||
.replace('%stackname%', self.stackname))
|
||||
inst = {'hostname': hostname}
|
||||
if 'profile' in role:
|
||||
inst['profile'] = role['profile']
|
||||
instances.append(inst)
|
||||
parameter_defaults['HostnameMap'][hostname] = hostname
|
||||
|
||||
return {'instances': instances,
|
||||
'environment': {'parameter_defaults': parameter_defaults}}
|
||||
|
||||
|
||||
class PopulateEnvironmentAction(base.TripleOAction):
|
||||
"""Populate the resulting environment file.
|
||||
|
||||
Fills in DeployedServerPortMap with the IP addresses of the nodes.
|
||||
"""
|
||||
|
||||
def __init__(self, environment, port_map, ctlplane_network='ctlplane'):
|
||||
super(PopulateEnvironmentAction, self).__init__()
|
||||
self.environment = environment
|
||||
self.port_map = port_map
|
||||
self.ctlplane_network = ctlplane_network
|
||||
|
||||
def run(self, context):
|
||||
port_map = (self.environment.setdefault('parameter_defaults', {})
|
||||
.setdefault('DeployedServerPortMap', {}))
|
||||
for hostname, nets in self.port_map.items():
|
||||
ctlplane = nets.get(self.ctlplane_network)
|
||||
if not ctlplane:
|
||||
LOG.warning('No ctlplane ports information for %s', hostname)
|
||||
continue
|
||||
|
||||
port_map['%s-%s' % (hostname, self.ctlplane_network)] = ctlplane
|
||||
|
||||
return self.environment
|
||||
|
||||
|
||||
def _validate_instances(instances, default_image='overcloud-full'):
|
||||
for inst in instances:
|
||||
if inst.get('name') and not inst.get('hostname'):
|
||||
inst['hostname'] = inst['name']
|
||||
|
||||
if not inst.get('hostname'):
|
||||
raise ValueError('Either hostname or name is required in %s'
|
||||
% inst)
|
||||
|
||||
# Set the default image so that the source validation can succeed.
|
||||
inst.setdefault('image', default_image)
|
||||
|
||||
@ -323,6 +435,23 @@ def _validate_instances(instances, default_image='overcloud-full'):
|
||||
names.add(inst['name'])
|
||||
|
||||
|
||||
def _validate_roles(roles, stackname='overcloud'):
|
||||
jsonschema.validate(roles, _ROLES_INPUT_SCHEMA)
|
||||
|
||||
for item in roles:
|
||||
if 'count' in item and 'instances' in item:
|
||||
raise ValueError("Count and instances cannot be provided together")
|
||||
|
||||
if 'instances' in item:
|
||||
for index, inst in enumerate(item['instances']):
|
||||
if 'profile' not in inst and 'profile' in item:
|
||||
inst['profile'] = item['profile']
|
||||
|
||||
# NOTE(dtantsur): make a copy since _validate_instances modifies
|
||||
# the original, and we don't need it at this stage.
|
||||
_validate_instances(copy.deepcopy(item['instances']))
|
||||
|
||||
|
||||
def _release_nodes(provisioner, nodes):
|
||||
for node in nodes:
|
||||
LOG.debug('Removing reservation from node %s', node)
|
||||
@ -339,3 +468,19 @@ def _get_source(instance):
|
||||
kernel=instance.get('image_kernel'),
|
||||
ramdisk=instance.get('image_ramdisk'),
|
||||
checksum=instance.get('image_checksum'))
|
||||
|
||||
|
||||
def _instance_to_dict(connection, instance):
|
||||
"""Convert an instance to a dict, adding ports information."""
|
||||
result = instance.to_dict()
|
||||
result['port_map'] = {}
|
||||
for nic in instance.nics():
|
||||
for ip in nic.fixed_ips:
|
||||
net_name = getattr(nic.network, 'name', None) or nic.network.id
|
||||
subnet = connection.network.get_subnet(ip['subnet_id'])
|
||||
net_info = result['port_map'].setdefault(
|
||||
net_name, {'network': nic.network.to_dict(),
|
||||
'fixed_ips': [], 'subnets': []})
|
||||
net_info['fixed_ips'].append({'ip_address': ip['ip_address']})
|
||||
net_info['subnets'].append(subnet.to_dict())
|
||||
return result
|
||||
|
@ -56,7 +56,7 @@ class TestReserveNodes(base.TestCase):
|
||||
action = baremetal_deploy.ReserveNodesAction(instances)
|
||||
result = action.run(mock.Mock())
|
||||
|
||||
self.assertIn("'hostname' is a required property", result.error)
|
||||
self.assertIn("hostname or name is required", result.error)
|
||||
self.assertFalse(mock_pr.return_value.reserve_node.called)
|
||||
self.assertFalse(mock_pr.return_value.unprovision_node.called)
|
||||
|
||||
@ -421,7 +421,7 @@ class TestCheckExistingInstances(base.TestCase):
|
||||
action = baremetal_deploy.CheckExistingInstancesAction(instances)
|
||||
result = action.run(mock.Mock())
|
||||
|
||||
self.assertIn("'hostname' is a required property", result.error)
|
||||
self.assertIn("hostname or name is required", result.error)
|
||||
self.assertFalse(mock_pr.return_value.show_instance.called)
|
||||
|
||||
def test_hostname_mismatch(self, mock_pr):
|
||||
@ -453,14 +453,50 @@ class TestWaitForDeployment(base.TestCase):
|
||||
|
||||
def test_success(self, mock_pr):
|
||||
pr = mock_pr.return_value
|
||||
inst = pr.wait_for_provisioning.return_value[0]
|
||||
inst.to_dict.return_value = {'hostname': 'compute.cloud'}
|
||||
|
||||
action = baremetal_deploy.WaitForDeploymentAction(
|
||||
{'hostname': 'compute.cloud', 'uuid': 'uuid1'})
|
||||
result = action.run(mock.Mock())
|
||||
|
||||
pr.wait_for_provisioning.assert_called_once_with(['uuid1'],
|
||||
timeout=3600)
|
||||
inst = pr.wait_for_provisioning.return_value[0]
|
||||
self.assertIs(result, inst.to_dict.return_value)
|
||||
self.assertEqual({}, result['port_map'])
|
||||
|
||||
def test_with_nics(self, mock_pr):
|
||||
pr = mock_pr.return_value
|
||||
net_mock = mock.Mock()
|
||||
net_mock.name = 'ctlplane'
|
||||
net_mock.to_dict.return_value = {'tags': ['foo']}
|
||||
inst = pr.wait_for_provisioning.return_value[0]
|
||||
inst.nics.return_value = [
|
||||
mock.Mock(fixed_ips=[{'ip_address': '1.2.3.5',
|
||||
'subnet_id': 'abcd'}],
|
||||
network=net_mock)
|
||||
]
|
||||
pr.connection.network.get_subnet.return_value.to_dict.return_value = {
|
||||
'cidr': '1.2.3.0/24'
|
||||
}
|
||||
inst.to_dict.return_value = {'hostname': 'compute.cloud'}
|
||||
|
||||
action = baremetal_deploy.WaitForDeploymentAction(
|
||||
{'hostname': 'compute.cloud', 'uuid': 'uuid1'})
|
||||
result = action.run(mock.Mock())
|
||||
|
||||
pr.wait_for_provisioning.assert_called_once_with(['uuid1'],
|
||||
timeout=3600)
|
||||
self.assertIs(result, inst.to_dict.return_value)
|
||||
self.assertEqual(
|
||||
{
|
||||
'ctlplane': {
|
||||
'network': {'tags': ['foo']},
|
||||
'fixed_ips': [{'ip_address': '1.2.3.5'}],
|
||||
'subnets': [{'cidr': '1.2.3.0/24'}],
|
||||
}
|
||||
},
|
||||
result['port_map'])
|
||||
|
||||
def test_failure(self, mock_pr):
|
||||
pr = mock_pr.return_value
|
||||
@ -497,3 +533,200 @@ class TestUndeployInstance(base.TestCase):
|
||||
|
||||
pr.show_instance.assert_called_once_with('inst1')
|
||||
self.assertFalse(pr.unprovision_node.called)
|
||||
|
||||
|
||||
class TestExpandRoles(base.TestCase):
|
||||
|
||||
def test_simple(self):
|
||||
roles = [
|
||||
{'name': 'Compute'},
|
||||
{'name': 'Controller'},
|
||||
]
|
||||
action = baremetal_deploy.ExpandRolesAction(roles)
|
||||
result = action.run(mock.Mock())
|
||||
self.assertEqual(
|
||||
[
|
||||
{'hostname': 'overcloud-novacompute-0'},
|
||||
{'hostname': 'overcloud-controller-0'},
|
||||
],
|
||||
result['instances'])
|
||||
self.assertEqual(
|
||||
{
|
||||
'ComputeDeployedServerHostnameFormat':
|
||||
'%stackname%-novacompute-%index%',
|
||||
'ComputeDeployedServerCount': 1,
|
||||
'ControllerDeployedServerHostnameFormat':
|
||||
'%stackname%-controller-%index%',
|
||||
'ControllerDeployedServerCount': 1,
|
||||
'HostnameMap': {
|
||||
'overcloud-novacompute-0': 'overcloud-novacompute-0',
|
||||
'overcloud-controller-0': 'overcloud-controller-0'
|
||||
}
|
||||
},
|
||||
result['environment']['parameter_defaults'])
|
||||
|
||||
def test_with_parameters(self):
|
||||
roles = [
|
||||
{'name': 'Compute', 'count': 2, 'profile': 'compute',
|
||||
'hostname_format': 'compute-%index%.example.com'},
|
||||
{'name': 'Controller', 'count': 3, 'profile': 'control',
|
||||
'hostname_format': 'controller-%index%.example.com'},
|
||||
]
|
||||
action = baremetal_deploy.ExpandRolesAction(roles)
|
||||
result = action.run(mock.Mock())
|
||||
self.assertEqual(
|
||||
[
|
||||
{'hostname': 'compute-0.example.com', 'profile': 'compute'},
|
||||
{'hostname': 'compute-1.example.com', 'profile': 'compute'},
|
||||
{'hostname': 'controller-0.example.com', 'profile': 'control'},
|
||||
{'hostname': 'controller-1.example.com', 'profile': 'control'},
|
||||
{'hostname': 'controller-2.example.com', 'profile': 'control'},
|
||||
],
|
||||
result['instances'])
|
||||
self.assertEqual(
|
||||
{
|
||||
'ComputeDeployedServerHostnameFormat':
|
||||
'compute-%index%.example.com',
|
||||
'ComputeDeployedServerCount': 2,
|
||||
'ControllerDeployedServerHostnameFormat':
|
||||
'controller-%index%.example.com',
|
||||
'ControllerDeployedServerCount': 3,
|
||||
'HostnameMap': {
|
||||
'compute-0.example.com': 'compute-0.example.com',
|
||||
'compute-1.example.com': 'compute-1.example.com',
|
||||
'controller-0.example.com': 'controller-0.example.com',
|
||||
'controller-1.example.com': 'controller-1.example.com',
|
||||
'controller-2.example.com': 'controller-2.example.com',
|
||||
}
|
||||
},
|
||||
result['environment']['parameter_defaults'])
|
||||
|
||||
def test_explicit_instances(self):
|
||||
roles = [
|
||||
{'name': 'Compute', 'count': 2, 'profile': 'compute',
|
||||
'hostname_format': 'compute-%index%.example.com'},
|
||||
{'name': 'Controller',
|
||||
'profile': 'control',
|
||||
'instances': [
|
||||
{'hostname': 'controller-X.example.com',
|
||||
'profile': 'control-X'},
|
||||
{'name': 'node-0', 'traits': ['CUSTOM_FOO'],
|
||||
'nics': [{'subnet': 'leaf-2'}]},
|
||||
]},
|
||||
]
|
||||
action = baremetal_deploy.ExpandRolesAction(roles)
|
||||
result = action.run(mock.Mock())
|
||||
self.assertEqual(
|
||||
[
|
||||
{'hostname': 'compute-0.example.com', 'profile': 'compute'},
|
||||
{'hostname': 'compute-1.example.com', 'profile': 'compute'},
|
||||
{'hostname': 'controller-X.example.com',
|
||||
'profile': 'control-X'},
|
||||
# Name provides the default for hostname later on.
|
||||
{'name': 'node-0', 'profile': 'control',
|
||||
'traits': ['CUSTOM_FOO'], 'nics': [{'subnet': 'leaf-2'}]},
|
||||
],
|
||||
result['instances'])
|
||||
self.assertEqual(
|
||||
{
|
||||
'ComputeDeployedServerHostnameFormat':
|
||||
'compute-%index%.example.com',
|
||||
'ComputeDeployedServerCount': 2,
|
||||
'ControllerDeployedServerHostnameFormat':
|
||||
'%stackname%-controller-%index%',
|
||||
'ControllerDeployedServerCount': 2,
|
||||
'HostnameMap': {
|
||||
'compute-0.example.com': 'compute-0.example.com',
|
||||
'compute-1.example.com': 'compute-1.example.com',
|
||||
'overcloud-controller-0': 'controller-X.example.com',
|
||||
'overcloud-controller-1': 'node-0',
|
||||
}
|
||||
},
|
||||
result['environment']['parameter_defaults'])
|
||||
|
||||
def test_count_with_instances(self):
|
||||
roles = [
|
||||
{'name': 'Compute', 'count': 2, 'profile': 'compute',
|
||||
'hostname_format': 'compute-%index%.example.com'},
|
||||
{'name': 'Controller',
|
||||
'profile': 'control',
|
||||
# Count makes no sense with instances and thus is disallowed.
|
||||
'count': 3,
|
||||
'instances': [
|
||||
{'hostname': 'controller-X.example.com',
|
||||
'profile': 'control-X'},
|
||||
{'name': 'node-0', 'traits': ['CUSTOM_FOO'],
|
||||
'nics': [{'subnet': 'leaf-2'}]},
|
||||
]},
|
||||
]
|
||||
action = baremetal_deploy.ExpandRolesAction(roles)
|
||||
result = action.run(mock.Mock())
|
||||
self.assertIn("Count and instances cannot be provided together",
|
||||
result.error)
|
||||
|
||||
def test_instances_without_hostname(self):
|
||||
roles = [
|
||||
{'name': 'Compute', 'count': 2, 'profile': 'compute',
|
||||
'hostname_format': 'compute-%index%.example.com'},
|
||||
{'name': 'Controller',
|
||||
'profile': 'control',
|
||||
'instances': [
|
||||
{'profile': 'control-X'}, # missing hostname here
|
||||
{'name': 'node-0', 'traits': ['CUSTOM_FOO'],
|
||||
'nics': [{'subnet': 'leaf-2'}]},
|
||||
]},
|
||||
]
|
||||
action = baremetal_deploy.ExpandRolesAction(roles)
|
||||
result = action.run(mock.Mock())
|
||||
self.assertIn("Either hostname or name is required", result.error)
|
||||
|
||||
|
||||
class TestPopulateEnvironment(base.TestCase):
|
||||
|
||||
def test_success(self):
|
||||
port_map = {
|
||||
'compute-0': {
|
||||
'ctlplane': {
|
||||
'network': {'tags': ['foo']},
|
||||
'fixed_ips': [{'ip_address': '1.2.3.5'}],
|
||||
'subnets': [{'cidr': '1.2.3.0/24'}],
|
||||
},
|
||||
'foobar': {
|
||||
'network': {},
|
||||
'fixed_ips': [{'ip_address': '1.2.4.5'}],
|
||||
'subnets': [{'cidr': '1.2.4.0/24'}],
|
||||
},
|
||||
},
|
||||
'controller-0': {
|
||||
'ctlplane': {
|
||||
'network': {'tags': ['foo']},
|
||||
'fixed_ips': [{'ip_address': '1.2.3.4'}],
|
||||
'subnets': [{'cidr': '1.2.3.0/24'}],
|
||||
},
|
||||
'foobar': {
|
||||
'network': {},
|
||||
'fixed_ips': [{'ip_address': '1.2.4.4'}],
|
||||
'subnets': [{'cidr': '1.2.4.0/24'}],
|
||||
},
|
||||
},
|
||||
}
|
||||
action = baremetal_deploy.PopulateEnvironmentAction({}, port_map)
|
||||
result = action.run(mock.Mock())
|
||||
self.assertEqual(
|
||||
{
|
||||
'parameter_defaults': {
|
||||
'DeployedServerPortMap': {
|
||||
'compute-0-ctlplane': {
|
||||
'fixed_ips': [{'ip_address': '1.2.3.5'}],
|
||||
'subnets': [{'cidr': '1.2.3.0/24'}],
|
||||
'network': {'tags': ['foo']},
|
||||
},
|
||||
'controller-0-ctlplane': {
|
||||
'fixed_ips': [{'ip_address': '1.2.3.4'}],
|
||||
'subnets': [{'cidr': '1.2.3.0/24'}],
|
||||
'network': {'tags': ['foo']},
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
result)
|
||||
|
@ -133,6 +133,7 @@ workflows:
|
||||
publish:
|
||||
ctlplane_ips: <% $.all_instances.toDict($.hostname, $.ip_addresses.ctlplane[0]) %>
|
||||
instances: <% $.all_instances.toDict($.hostname, $) %>
|
||||
port_map: <% $.all_instances.toDict($.hostname, $.port_map) %>
|
||||
on-complete: send_message
|
||||
|
||||
send_message:
|
||||
@ -146,12 +147,14 @@ workflows:
|
||||
payload:
|
||||
ctlplane_ips: <% $.get('ctlplane_ips', {}) %>
|
||||
instances: <% $.get('instances', {}) %>
|
||||
port_map: <% $.get('port_map', {}) %>
|
||||
|
||||
output:
|
||||
ctlplane_ips: <% $.ctlplane_ips %>
|
||||
existing_instances: <% $.existing_instances.toDict($.hostname, $) %>
|
||||
instances: <% $.instances %>
|
||||
new_instances: <% $.new_instances.toDict($.hostname, $) %>
|
||||
port_map: <% $.port_map %>
|
||||
|
||||
|
||||
undeploy_instances:
|
||||
@ -188,3 +191,89 @@ workflows:
|
||||
status: <% $.get('status', 'SUCCESS') %>
|
||||
message: <% $.get('message', '') %>
|
||||
execution: <% execution() %>
|
||||
|
||||
|
||||
deploy_roles:
|
||||
description: Deploy roles on bare metal nodes.
|
||||
|
||||
input:
|
||||
- roles
|
||||
- plan: overcloud
|
||||
- ctlplane_network: ctlplane
|
||||
- ssh_keys: []
|
||||
- ssh_user_name: heat-admin
|
||||
- timeout: 3600
|
||||
- concurrency: 20
|
||||
- queue_name: tripleo
|
||||
|
||||
tags:
|
||||
- tripleo-common-managed
|
||||
|
||||
tasks:
|
||||
|
||||
expand_roles:
|
||||
action: tripleo.baremetal_deploy.expand_roles
|
||||
input:
|
||||
roles: <% $.roles %>
|
||||
stackname: <% $.plan %>
|
||||
publish:
|
||||
input_instances: <% task().result.instances %>
|
||||
environment: <% task().result.environment %>
|
||||
publish-on-error:
|
||||
status: FAILED
|
||||
message: <% task().result %>
|
||||
on-success: deploy_instances
|
||||
on-error: send_message
|
||||
|
||||
deploy_instances:
|
||||
workflow: tripleo.baremetal_deploy.v1.deploy_instances
|
||||
input:
|
||||
instances: <% $.input_instances %>
|
||||
ssh_keys: <% $.ssh_keys %>
|
||||
ssh_user_name: <% $.ssh_user_name %>
|
||||
timeout: <% $.timeout %>
|
||||
queue_name: <% $.queue_name %>
|
||||
publish:
|
||||
ctlplane_ips: <% task().result.ctlplane_ips %>
|
||||
instances: <% task().result.instances %>
|
||||
new_instances: <% task().result.new_instances %>
|
||||
existing_instances: <% task().result.existing_instances %>
|
||||
port_map: <% task().result.port_map %>
|
||||
publish-on-error:
|
||||
status: FAILED
|
||||
message: <% task().result %>
|
||||
on-success: populate_environment
|
||||
on-error: send_message
|
||||
|
||||
populate_environment:
|
||||
action: tripleo.baremetal_deploy.populate_environment
|
||||
input:
|
||||
ctlplane_network: <% $.ctlplane_network %>
|
||||
environment: <% $.environment %>
|
||||
port_map: <% $.port_map %>
|
||||
publish:
|
||||
environment: <% task().result %>
|
||||
publish-on-error:
|
||||
status: FAILED
|
||||
message: <% task().result %>
|
||||
on-complete: send_message
|
||||
|
||||
send_message:
|
||||
workflow: tripleo.messaging.v1.send
|
||||
input:
|
||||
queue_name: <% $.queue_name %>
|
||||
type: <% execution().name %>
|
||||
status: <% $.get('status', 'SUCCESS') %>
|
||||
message: <% $.get('message', '') %>
|
||||
execution: <% execution() %>
|
||||
payload:
|
||||
environment: <% $.get('environment', {}) %>
|
||||
instances: <% $.get('instances', {}) %>
|
||||
|
||||
output:
|
||||
ctlplane_ips: <% $.ctlplane_ips %>
|
||||
environment: <% $.environment %>
|
||||
existing_instances: <% $.existing_instances %>
|
||||
instances: <% $.instances %>
|
||||
new_instances: <% $.new_instances %>
|
||||
port_map: <% $.port_map %>
|
||||
|
Loading…
x
Reference in New Issue
Block a user