diff --git a/doc/source/index.rst b/doc/source/index.rst index cadffe55b..0d25943fe 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -18,7 +18,6 @@ Contents: tripleo-mistral contributing uploads - reference/index Indices and tables ================== diff --git a/doc/source/reference/index.rst b/doc/source/reference/index.rst deleted file mode 100644 index 67a1a2742..000000000 --- a/doc/source/reference/index.rst +++ /dev/null @@ -1,14 +0,0 @@ -=========================== -API Reference Documentation -=========================== - - -Workbooks -========= - -.. toctree:: - :maxdepth: 2 - :glob: - :titlesonly: - - workbooks/* diff --git a/doc/source/reference/workbooks/.gitignore b/doc/source/reference/workbooks/.gitignore deleted file mode 100644 index 30d85567b..000000000 --- a/doc/source/reference/workbooks/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.rst diff --git a/setup.cfg b/setup.cfg index 348b0f3fb..9ad5a80a2 100644 --- a/setup.cfg +++ b/setup.cfg @@ -40,46 +40,7 @@ data_files = share/tripleo-common = sudoers share/tripleo-common/container-images = container-images/* share/tripleo-common/image-yaml = image-yaml/* - share/tripleo-common/workbooks = workbooks/* share/tripleo-common/healthcheck = healthcheck/* - share/ansible/roles/ = roles/* - share/ansible/plugins/ = ansible_plugins/* - -[entry_points] -mistral.actions = - tripleo.baremetal.configure_boot = tripleo_common.actions.baremetal:ConfigureBootAction - tripleo.baremetal.configure_root_device = tripleo_common.actions.baremetal:ConfigureRootDeviceAction - tripleo.baremetal.get_node_hint = tripleo_common.actions.baremetal:GetNodeHintAction - tripleo.baremetal.get_profile = tripleo_common.actions.baremetal:GetProfileAction - tripleo.baremetal.update_node_capability = tripleo_common.actions.baremetal:UpdateNodeCapability - tripleo.baremetal.cell_v2_discover_hosts = tripleo_common.actions.baremetal:CellV2DiscoverHostsAction - tripleo.baremetal.validate_nodes = tripleo_common.actions.baremetal:ValidateNodes - tripleo.deployment.get_deployment_failures = tripleo_common.actions.deployment:DeploymentFailuresAction - tripleo.derive_params.convert_number_to_range_list = tripleo_common.actions.derive_params:ConvertNumberToRangeListAction - tripleo.derive_params.convert_range_to_number_list = tripleo_common.actions.derive_params:ConvertRangeToNumberListAction - tripleo.derive_params.get_dpdk_nics_numa_info = tripleo_common.actions.derive_params:GetDpdkNicsNumaInfoAction - tripleo.derive_params.get_dpdk_core_list = tripleo_common.actions.derive_params:GetDpdkCoreListAction - tripleo.derive_params.get_dpdk_socket_memory = tripleo_common.actions.derive_params:GetDpdkSocketMemoryAction - tripleo.derive_params.get_host_cpus_list = tripleo_common.actions.derive_params:GetHostCpusListAction - tripleo.parameters.get_flatten = tripleo_common.actions.parameters:GetFlattenedParametersAction - tripleo.parameters.get_network_config = tripleo_common.actions.parameters:GetNetworkConfigAction - tripleo.parameters.reset = tripleo_common.actions.parameters:ResetParametersAction - tripleo.parameters.update = tripleo_common.actions.parameters:UpdateParametersAction - tripleo.parameters.update_role = tripleo_common.actions.parameters:UpdateRoleParametersAction - tripleo.parameters.get_profile_of_flavor = tripleo_common.actions.parameters:GetProfileOfFlavorAction - tripleo.plan.delete = tripleo_common.actions.plan:DeletePlanAction - tripleo.plan.list = tripleo_common.actions.plan:ListPlansAction - tripleo.plan.export = tripleo_common.actions.plan:ExportPlanAction - tripleo.plan.update_roles = tripleo_common.actions.plan:UpdateRolesAction - tripleo.plan.validate_roles = tripleo_common.actions.plan:ValidateRolesDataAction - tripleo.plan.remove_noop_deploystep = tripleo_common.actions.plan:RemoveNoopDeployStepAction - tripleo.validations.get_pubkey = tripleo_common.actions.validations:GetPubkeyAction - tripleo.validations.get_privkey = tripleo_common.actions.validations:GetPrivkeyAction - tripleo.validations.enabled = tripleo_common.actions.validations:Enabled - # deprecated for pike release, will be removed in queens - tripleo.ansible-playbook = tripleo_common.actions.ansible:AnsiblePlaybookAction - # deprecated for rocky release, will be removed in the "S" cycle - tripleo.role.list = tripleo_common.actions.plan:ListRolesAction [tool:pytest] norecursedirs = .eggs .git .tox dist diff --git a/tripleo_common/actions/baremetal.py b/tripleo_common/actions/baremetal.py index da70251dd..5e9ac841e 100644 --- a/tripleo_common/actions/baremetal.py +++ b/tripleo_common/actions/baremetal.py @@ -299,90 +299,6 @@ class ConfigureRootDeviceAction(base.TripleOAction): {'node': node.uuid, 'dev': root_device, 'local_gb': new_size}) -class UpdateNodeCapability(base.TripleOAction): - """Update a node's capability - - Set the node's capability to the specified value. - - :param node_uuid: The UUID of the node - :param capability: The name of the capability to update - :param value: The value to update token - :return: Result of updating the node - """ - - def __init__(self, node_uuid, capability, value): - super(UpdateNodeCapability, self).__init__() - self.node_uuid = node_uuid - self.capability = capability - self.value = value - - def run(self, context): - baremetal_client = self.get_baremetal_client(context) - - try: - return nodes.update_node_capability( - self.node_uuid, - self.capability, - self.value, - baremetal_client - ) - except Exception as err: - LOG.exception("Error updating node capability in ironic.") - return actions.Result( - error="%s: %s" % (type(err).__name__, str(err)) - ) - - -class CellV2DiscoverHostsAction(base.TripleOAction): - """Run cell_v2 host discovery - - Runs cell_v2 host discovery to map any newly available ironic nodes. - - """ - - def run(self, context): - try: - result = nodes.run_nova_cell_v2_discovery() - LOG.info( - 'Successfully ran cell_v2 discover_hosts\n' - 'stdout: %(stdout)r\n', - {"stdout": result[0]} - ) - except Exception as err: - LOG.exception("Error running cell_v2 discover_hosts") - return actions.Result( - error="%s: %s" % (type(err).__name__, str(err)) - ) - - -class GetProfileAction(base.TripleOAction): - """Return the profile associated with the given node """ - - def __init__(self, node): - super(GetProfileAction, self).__init__() - self.node = node - - def run(self, context): - result = {} - result['profile'] = nodes.get_node_profile(self.node) - result['uuid'] = self.node.get('uuid') - return result - - -class GetNodeHintAction(base.TripleOAction): - """Return the scheduler hint associated with the given node """ - - def __init__(self, node): - super(GetNodeHintAction, self).__init__() - self.node = node - - def run(self, context): - result = {} - result['hint'] = nodes.get_node_hint(self.node) - result['uuid'] = self.node.get('uuid') - return result - - class GetCandidateNodes(base.TripleOAction): """Given IPs, ports and credentials, return potential new nodes.""" diff --git a/tripleo_common/actions/derive_params.py b/tripleo_common/actions/derive_params.py deleted file mode 100644 index b8830ac79..000000000 --- a/tripleo_common/actions/derive_params.py +++ /dev/null @@ -1,465 +0,0 @@ -# Copyright 2017 Red Hat, Inc. -# All Rights Reserved. -# -# 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 logging -import math -import re - -from mistral_lib import actions - -from tripleo_common.actions import base -from tripleo_common import exception - -LOG = logging.getLogger(__name__) - - -class GetDpdkNicsNumaInfoAction(base.TripleOAction): - """Gets the DPDK NICs with MTU for NUMA nodes. - - Find the DPDK interface names from the network config and - translate it to phsical interface names using the introspection - data. And then find the NUMA node associated with the DPDK - interface and the MTU value. - - :param network_configs: network config list - :param inspect_data: introspection data - :param mtu_default: mtu default value for NICs - - :return: DPDK NICs NUMA nodes info - """ - - def __init__(self, network_configs, inspect_data, mtu_default=1500): - super(GetDpdkNicsNumaInfoAction, self).__init__() - self.network_configs = network_configs - self.inspect_data = inspect_data - self.mtu_default = mtu_default - - # TODO(jpalanis): Expose this utility from os-net-config to sort - # active nics - def _natural_sort_key(self, s): - nsre = re.compile('([0-9]+)') - return [int(text) if text.isdigit() else text - for text in re.split(nsre, s)] - - # TODO(jpalanis): Expose this utility from os-net-config to sort - # active nics - def _is_embedded_nic(self, nic): - if (nic.startswith('em') or nic.startswith('eth') or - nic.startswith('eno')): - return True - return False - - # TODO(jpalanis): Expose this utility from os-net-config to sort - # active nics - def _ordered_nics(self, interfaces): - embedded_nics = [] - nics = [] - for iface in interfaces: - nic = iface.get('name', '') - if self._is_embedded_nic(nic): - embedded_nics.append(nic) - else: - nics.append(nic) - active_nics = (sorted( - embedded_nics, key=self._natural_sort_key) + - sorted(nics, key=self._natural_sort_key)) - return active_nics - - # Gets numa node id for physical NIC name - def find_numa_node_id(self, numa_nics, nic_name): - for nic_info in numa_nics: - if nic_info.get('name', '') == nic_name: - return nic_info.get('numa_node', None) - return None - - # Get physical interface name for NIC name - def get_physical_iface_name(self, ordered_nics, nic_name): - if nic_name.startswith('nic'): - # Nic numbering, find the actual interface name - nic_number = int(nic_name.replace('nic', '')) - if nic_number > 0: - iface_name = ordered_nics[nic_number - 1] - return iface_name - return nic_name - - # Gets dpdk interfaces and mtu info for dpdk config - # Default mtu(recommended 1500) is used if no MTU is set for DPDK NIC - def get_dpdk_interfaces(self, dpdk_objs): - mtu = self.mtu_default - dpdk_ifaces = [] - for dpdk_obj in dpdk_objs: - obj_type = dpdk_obj.get('type') - mtu = dpdk_obj.get('mtu', self.mtu_default) - if obj_type == 'ovs_dpdk_port': - # Member interfaces of ovs_dpdk_port - dpdk_ifaces.extend(dpdk_obj.get('members', [])) - elif obj_type == 'ovs_dpdk_bond': - # ovs_dpdk_bond will have multiple ovs_dpdk_ports - for bond_member in dpdk_obj.get('members', []): - if bond_member.get('type') == 'ovs_dpdk_port': - dpdk_ifaces.extend(bond_member.get('members', [])) - return (dpdk_ifaces, mtu) - - def run(self, context): - interfaces = self.inspect_data.get('inventory', - {}).get('interfaces', []) - # Checks whether inventory interfaces information is not available - # in introspection data. - if not interfaces: - msg = 'Introspection data does not have inventory.interfaces' - return actions.Result(error=msg) - - numa_nics = self.inspect_data.get('numa_topology', - {}).get('nics', []) - # Checks whether numa topology nics information is not available - # in introspection data. - if not numa_nics: - msg = 'Introspection data does not have numa_topology.nics' - return actions.Result(error=msg) - - active_interfaces = [iface for iface in interfaces - if iface.get('has_carrier', False)] - # Checks whether active interfaces are not available - if not active_interfaces: - msg = 'Unable to determine active interfaces (has_carrier)' - return actions.Result(error=msg) - - dpdk_nics_numa_info = [] - ordered_nics = self._ordered_nics(active_interfaces) - # Gets DPDK network config and parses to get DPDK NICs - # with mtu and numa node id - for config in self.network_configs: - if config.get('type', '') == 'ovs_user_bridge': - bridge_name = config.get('name', '') - addresses = config.get('addresses', []) - members = config.get('members', []) - dpdk_ifaces, mtu = self.get_dpdk_interfaces(members) - for dpdk_iface in dpdk_ifaces: - type = dpdk_iface.get('type', '') - if type == 'sriov_vf': - name = dpdk_iface.get('device', '') - else: - name = dpdk_iface.get('name', '') - phy_name = self.get_physical_iface_name( - ordered_nics, name) - node = self.find_numa_node_id(numa_nics, phy_name) - if node is None: - msg = ('Unable to determine NUMA node for ' - 'DPDK NIC: %s' % phy_name) - return actions.Result(error=msg) - - dpdk_nic_info = {'name': phy_name, - 'numa_node': node, - 'mtu': mtu, - 'bridge_name': bridge_name, - 'addresses': addresses} - dpdk_nics_numa_info.append(dpdk_nic_info) - return dpdk_nics_numa_info - - -class GetDpdkCoreListAction(base.TripleOAction): - """Gets the DPDK PMD Core List. - - With input as the number of physical cores for each NUMA node, - find the right logical CPUs to be allocated along with its - siblings for the PMD core list. - - :param inspect_data: introspection data - :param numa_nodes_cores_count: physical cores count for each NUMA - - :return: DPDK Core List - """ - - def __init__(self, inspect_data, numa_nodes_cores_count): - super(GetDpdkCoreListAction, self).__init__() - self.inspect_data = inspect_data - self.numa_nodes_cores_count = numa_nodes_cores_count - - def run(self, context): - dpdk_core_list = [] - numa_cpus_info = self.inspect_data.get('numa_topology', - {}).get('cpus', []) - - # Checks whether numa topology cpus information is not available - # in introspection data. - if not numa_cpus_info: - msg = 'Introspection data does not have numa_topology.cpus' - return actions.Result(error=msg) - - # Checks whether CPU physical cores count for each NUMA nodes is - # not available - if not self.numa_nodes_cores_count: - msg = ('CPU physical cores count for each NUMA nodes ' - 'is not available') - return actions.Result(error=msg) - - numa_nodes_threads = {} - # Creates list for all available threads in each NUMA node - for cpu in numa_cpus_info: - if not cpu['numa_node'] in numa_nodes_threads: - numa_nodes_threads[cpu['numa_node']] = [] - numa_nodes_threads[cpu['numa_node']].extend(cpu['thread_siblings']) - - for node, node_cores_count in enumerate(self.numa_nodes_cores_count): - # Gets least thread in NUMA node - numa_node_min = min(numa_nodes_threads[node]) - cores_count = node_cores_count - for cpu in numa_cpus_info: - if cpu['numa_node'] == node: - # Adds threads from core which is not having least thread - if numa_node_min not in cpu['thread_siblings']: - dpdk_core_list.extend(cpu['thread_siblings']) - cores_count -= 1 - if cores_count == 0: - break - return ','.join([str(thread) for thread in dpdk_core_list]) - - -class GetHostCpusListAction(base.TripleOAction): - """Gets the Host CPUs List. - - CPU threads from first physical core is allocated for host processes - on each NUMA nodes. - - :param inspect_data: introspection data - - :return: Host CPUs List - """ - - def __init__(self, inspect_data): - super(GetHostCpusListAction, self).__init__() - self.inspect_data = inspect_data - - def run(self, context): - host_cpus_list = [] - numa_cpus_info = self.inspect_data.get('numa_topology', - {}).get('cpus', []) - - # Checks whether numa topology cpus information is not available - # in introspection data. - if not numa_cpus_info: - msg = 'Introspection data does not have numa_topology.cpus' - return actions.Result(error=msg) - - numa_nodes_threads = {} - # Creates a list for all available threads in each NUMA nodes - for cpu in numa_cpus_info: - if not cpu['numa_node'] in numa_nodes_threads: - numa_nodes_threads[cpu['numa_node']] = [] - numa_nodes_threads[cpu['numa_node']].extend( - cpu['thread_siblings']) - - for numa_node in sorted(numa_nodes_threads.keys()): - node = int(numa_node) - # Gets least thread in NUMA node - numa_node_min = min(numa_nodes_threads[numa_node]) - for cpu in numa_cpus_info: - if cpu['numa_node'] == node: - # Adds threads from core which is having least thread - if numa_node_min in cpu['thread_siblings']: - host_cpus_list.extend(cpu['thread_siblings']) - break - - return ','.join([str(thread) for thread in host_cpus_list]) - - -class GetDpdkSocketMemoryAction(base.TripleOAction): - """Gets the DPDK Socket Memory List. - - For NUMA node with DPDK nic, socket memory is calculated - based on MTU, Overhead and Packet size in buffer. - - For NUMA node without DPDK nic, minimum socket memory is - assigned (recommended 1GB) - - :param dpdk_nics_numa_info: DPDK nics numa info - :param numa_nodes: list of numa nodes - :param overhead: overhead value - :param packet_size_in_buffer: packet size in buffer - :param minimum_socket_memory: minimum socket memory - - :return: DPDK Socket Memory List - """ - def __init__(self, dpdk_nics_numa_info, numa_nodes, - overhead, packet_size_in_buffer, - minimum_socket_memory=1024): - super(GetDpdkSocketMemoryAction, self).__init__() - self.dpdk_nics_numa_info = dpdk_nics_numa_info - self.numa_nodes = numa_nodes - self.overhead = overhead - self.packet_size_in_buffer = packet_size_in_buffer - self.minimum_socket_memory = minimum_socket_memory - - # Computes round off MTU value in bytes - # example: MTU value 9000 into 9216 bytes - def roundup_mtu_bytes(self, mtu): - max_div_val = int(math.ceil(float(mtu) / float(1024))) - return (max_div_val * 1024) - - # Calculates socket memory for a NUMA node - def calculate_node_socket_memory( - self, numa_node, dpdk_nics_numa_info, overhead, - packet_size_in_buffer, minimum_socket_memory): - distinct_mtu_per_node = [] - socket_memory = 0 - - # For DPDK numa node - for nics_info in dpdk_nics_numa_info: - if (numa_node == nics_info['numa_node'] and - not nics_info['mtu'] in distinct_mtu_per_node): - distinct_mtu_per_node.append(nics_info['mtu']) - roundup_mtu = self.roundup_mtu_bytes(nics_info['mtu']) - socket_memory += (((roundup_mtu + overhead) * - packet_size_in_buffer) / - (1024 * 1024)) - - # For Non DPDK numa node - if socket_memory == 0: - socket_memory = minimum_socket_memory - # For DPDK numa node - else: - socket_memory += 512 - - socket_memory_in_gb = int(socket_memory / 1024) - if socket_memory % 1024 > 0: - socket_memory_in_gb += 1 - return (socket_memory_in_gb * 1024) - - def run(self, context): - dpdk_socket_memory_list = [] - for node in self.numa_nodes: - socket_mem = self.calculate_node_socket_memory( - node, self.dpdk_nics_numa_info, self.overhead, - self.packet_size_in_buffer, - self.minimum_socket_memory) - dpdk_socket_memory_list.append(socket_mem) - - return ','.join([str(sm) for sm in dpdk_socket_memory_list]) - - -class ConvertNumberToRangeListAction(base.TripleOAction): - """Converts number list into range list - - :param num_list: comma delimited number list as string - - :return: comma delimited range list as string - """ - - def __init__(self, num_list): - super(ConvertNumberToRangeListAction, self).__init__() - self.num_list = num_list - - # converts number list into range list. - # here input parameter and return value as list - # example: [12, 13, 14, 17] into ["12-14", "17"] - def convert_number_to_range_list(self, num_list): - num_list.sort() - range_list = [] - range_min = num_list[0] - for num in num_list: - next_val = num + 1 - if next_val not in num_list: - if range_min != num: - range_list.append(str(range_min) + '-' + str(num)) - else: - range_list.append(str(range_min)) - next_index = num_list.index(num) + 1 - if next_index < len(num_list): - range_min = num_list[next_index] - - # here, range_list is a list of strings - return range_list - - def run(self, context): - try: - if not self.num_list: - err_msg = ("Input param 'num_list' is blank.") - raise exception.DeriveParamsError(err_msg) - - try: - # splitting a string (comma delimited list) into - # list of numbers - # example: "12,13,14,17" string into [12,13,14,17] - num_list = [int(num.strip(' ')) - for num in self.num_list.split(",")] - except ValueError as exc: - err_msg = ("Invalid number in input param " - "'num_list': %s" % exc) - raise exception.DeriveParamsError(err_msg) - - range_list = self.convert_number_to_range_list(num_list) - except exception.DeriveParamsError as err: - LOG.error('Derive Params Error: %s', err) - return actions.Result(error=str(err)) - - # converts into comma delimited range list as string - return ','.join(range_list) - - -class ConvertRangeToNumberListAction(base.TripleOAction): - """Converts range list to integer list - - :param range_list: comma delimited range list as string / list - - :return: comma delimited number list as string - """ - - def __init__(self, range_list): - super(ConvertRangeToNumberListAction, self).__init__() - self.range_list = range_list - - # converts range list into number list - # here input parameter and return value as list - # example: ["12-14", "^13", "17"] into [12, 14, 17] - def convert_range_to_number_list(self, range_list): - num_list = [] - exclude_num_list = [] - try: - for val in range_list: - val = val.strip(' ') - if '^' in val: - exclude_num_list.append(int(val[1:])) - elif '-' in val: - split_list = val.split("-") - range_min = int(split_list[0]) - range_max = int(split_list[1]) - num_list.extend(range(range_min, (range_max + 1))) - else: - num_list.append(int(val)) - except ValueError as exc: - err_msg = ("Invalid number in input param " - "'range_list': %s" % exc) - raise exception.DeriveParamsError(err_msg) - - # here, num_list is a list of integers - return [num for num in num_list if num not in exclude_num_list] - - def run(self, context): - try: - if not self.range_list: - err_msg = ("Input param 'range_list' is blank.") - raise exception.DeriveParamsError(err_msg) - range_list = self.range_list - # converts into python list if range_list is not list type - if not isinstance(range_list, list): - range_list = self.range_list.split(",") - - num_list = self.convert_range_to_number_list(range_list) - except exception.DeriveParamsError as err: - LOG.error('Derive Params Error: %s', err) - return actions.Result(error=str(err)) - - # converts into comma delimited number list as string - return ','.join([str(num) for num in num_list]) diff --git a/tripleo_common/actions/parameters.py b/tripleo_common/actions/parameters.py deleted file mode 100644 index e47ed6e8e..000000000 --- a/tripleo_common/actions/parameters.py +++ /dev/null @@ -1,163 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# All Rights Reserved. -# -# 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 logging - -from mistral_lib import actions -import six - -from tripleo_common.actions import base -from tripleo_common import constants -from tripleo_common import exception -from tripleo_common.utils import parameters as parameter_utils -from tripleo_common.utils import stack_parameters as stack_param_utils - -LOG = logging.getLogger(__name__) - - -class ResetParametersAction(base.TripleOAction): - """Provides method to delete user set parameters.""" - - def __init__(self, container=constants.DEFAULT_CONTAINER_NAME, - key=constants.DEFAULT_PLAN_ENV_KEY): - super(ResetParametersAction, self).__init__() - self.container = container - self.key = key - - def run(self, context): - swift = self.get_object_client(context) - - try: - return stack_param_utils.reset_parameters( - swift, self.container, self.key) - except Exception as err: - LOG.exception(six.text_type(err)) - return actions.Result(six.text_type(err)) - - -class UpdateParametersAction(base.TripleOAction): - """Updates plan environment with parameters.""" - - def __init__(self, parameters, - container=constants.DEFAULT_CONTAINER_NAME, - key=constants.DEFAULT_PLAN_ENV_KEY, - validate=True): - super(UpdateParametersAction, self).__init__() - self.container = container - self.parameters = parameters - self.key = key - self.validate = validate - - def run(self, context): - swift = self.get_object_client(context) - heat = self.get_orchestration_client(context) - - try: - return stack_param_utils.update_parameters( - swift, heat, self.parameters, - self.container, self.key, - self.validate) - except Exception as err: - LOG.exception(six.text_type(err)) - return actions.Result(six.text_type(err)) - - -class UpdateRoleParametersAction(base.TripleOAction): - """Updates role related parameters in plan environment .""" - - def __init__(self, role, container=constants.DEFAULT_CONTAINER_NAME): - super(UpdateRoleParametersAction, self).__init__() - self.role = role - self.container = container - - def run(self, context): - swift = self.get_object_client(context) - heat = self.get_orchestration_client(context) - ironic = self.get_baremetal_client(context) - nova = self.get_compute_client(context) - try: - return stack_param_utils.update_role_parameters( - swift, heat, ironic, nova, self.role, self.container) - except Exception as err: - LOG.exception(six.text_type(err)) - return actions.Result(six.text_type(err)) - - -class GetFlattenedParametersAction(base.TripleOAction): - """Get the heat stack tree and parameters in flattened structure. - - This method validates the stack of the container and returns the - parameters and the heat stack tree. The heat stack tree is flattened - for easy consumption. - """ - - def __init__(self, container=constants.DEFAULT_CONTAINER_NAME): - super(GetFlattenedParametersAction, self).__init__() - self.container = container - - def run(self, context): - heat = self.get_orchestration_client(context) - swift = self.get_object_client(context) - try: - return stack_param_utils.get_flattened_parameters( - swift, heat, self.container) - except Exception as err: - LOG.exception(six.text_type(err)) - return actions.Result(six.text_type(err)) - - -class GetProfileOfFlavorAction(base.TripleOAction): - """Gets the profile name for a given flavor name. - - Need flavor object to get profile name since get_keys method is - not available for external access. so we have created an action - to get profile name from flavor name. - - :param flavor_name: Flavor name - - :return: profile name - """ - - def __init__(self, flavor_name): - super(GetProfileOfFlavorAction, self).__init__() - self.flavor_name = flavor_name - - def run(self, context): - compute_client = self.get_compute_client(context) - try: - return parameter_utils.get_profile_of_flavor(self.flavor_name, - compute_client) - except exception.DeriveParamsError as err: - LOG.error('Derive Params Error: %s', err) - return actions.Result(error=str(err)) - - -class GetNetworkConfigAction(base.TripleOAction): - """Gets network configuration details from available heat parameters.""" - - def __init__(self, role_name, container=constants.DEFAULT_CONTAINER_NAME): - super(GetNetworkConfigAction, self).__init__() - self.container = container - self.role_name = role_name - - def run(self, context): - try: - return stack_param_utils.get_network_configs( - self.get_baremetal_client(context), - self.get_compute_client(context), - self.container, self.role_name) - except Exception as err: - LOG.exception(six.text_type(err)) - return actions.Result(six.text_type(err)) diff --git a/tripleo_common/actions/plan.py b/tripleo_common/actions/plan.py deleted file mode 100644 index a54bdb622..000000000 --- a/tripleo_common/actions/plan.py +++ /dev/null @@ -1,304 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# All Rights Reserved. -# -# 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 logging -from operator import itemgetter -import shutil -import tempfile -import yaml - -from heatclient import exc as heatexceptions -from mistral_lib import actions -from oslo_concurrency import processutils -import six -from swiftclient import exceptions as swiftexceptions - -from tripleo_common.actions import base -from tripleo_common import constants -from tripleo_common import exception -from tripleo_common.utils import plan as plan_utils -from tripleo_common.utils import roles as roles_utils -from tripleo_common.utils import swift as swiftutils - - -LOG = logging.getLogger(__name__) - - -class ListPlansAction(base.TripleOAction): - """Lists deployment plans - - This action lists all deployment plans residing in the undercloud. A - deployment plan consists of a container marked with metadata - 'x-container-meta-usage-tripleo'. - """ - - def run(self, context): - # Plans consist of a container object marked with metadata to ensure it - # isn't confused with another container - plan_list = [] - oc = self.get_object_client(context) - - for item in oc.get_account()[1]: - container = oc.get_container(item['name'])[0] - if constants.TRIPLEO_META_USAGE_KEY in container.keys(): - plan_list.append(item['name']) - return list(set(plan_list)) - - -class DeletePlanAction(base.TripleOAction): - """Deletes a plan and associated files - - Deletes a plan by deleting the container matching plan_name. It - will not delete the plan if a stack exists with the same name. - - Raises StackInUseError if a stack with the same name as plan_name - exists. - """ - - def __init__(self, container): - super(DeletePlanAction, self).__init__() - self.container = container - - def run(self, context): - error_text = None - # heat throws HTTPNotFound if the stack is not found - try: - stack = self.get_orchestration_client(context).stacks.get( - self.container, resolve_outputs=False) - except heatexceptions.HTTPNotFound: - pass - else: - if stack is not None: - raise exception.StackInUseError(name=self.container) - - try: - swift = self.get_object_client(context) - swiftutils.delete_container(swift, self.container) - swiftutils.delete_container(swift, - "%s-swift-rings" % self.container) - swiftutils.delete_container(swift, - "%s-messages" % self.container) - except swiftexceptions.ClientException as ce: - LOG.exception("Swift error deleting plan.") - error_text = ce.msg - except Exception as err: - LOG.exception("Error deleting plan.") - error_text = six.text_type(err) - - if error_text: - return actions.Result(error=error_text) - - -class ListRolesAction(base.TripleOAction): - """Returns a deployment plan's roles - - DEPRECATED - - Parses roles_data.yaml and returns the names of all available roles. - - :param container: name of the Swift container / plan name - :param detail: if false(default), displays role names only. if true, - returns all roles data - :return: list of roles in the container's deployment plan - """ - - def __init__(self, container=constants.DEFAULT_CONTAINER_NAME, - role_file_name=constants.OVERCLOUD_J2_ROLES_NAME, - detail=False): - super(ListRolesAction, self).__init__() - self.container = container - self.role_file_name = role_file_name - self.detail = detail - - def run(self, context): - try: - swift = self.get_object_client(context) - return roles_utils.get_roles_from_plan( - swift, container=self.container, - role_file_name=self.role_file_name, - detail=self.detail) - except Exception as err: - return actions.Result(error=six.text_type(err)) - - -class ExportPlanAction(base.TripleOAction): - """Exports a deployment plan - - This action exports a deployment plan with a given name. The plan - templates are downloaded from the Swift container, packaged up in a tarball - and uploaded to Swift. - """ - - def __init__(self, plan, delete_after, exports_container): - super(ExportPlanAction, self).__init__() - self.plan = plan - self.delete_after = delete_after - self.exports_container = exports_container - - def run(self, context): - swift = self.get_object_client(context) - swift_service = self.get_object_service(context) - - tmp_dir = tempfile.mkdtemp() - tarball_name = '%s.tar.gz' % self.plan - - try: - swiftutils.download_container(swift, self.plan, tmp_dir) - swiftutils.create_and_upload_tarball( - swift_service, tmp_dir, self.exports_container, tarball_name, - delete_after=self.delete_after) - except swiftexceptions.ClientException as err: - msg = "Error attempting an operation on container: %s" % err - return actions.Result(error=msg) - except (OSError, IOError) as err: - msg = "Error while writing file: %s" % err - return actions.Result(error=msg) - except processutils.ProcessExecutionError as err: - msg = "Error while creating a tarball: %s" % err - return actions.Result(error=msg) - except Exception as err: - msg = "Error exporting plan: %s" % err - return actions.Result(error=msg) - finally: - shutil.rmtree(tmp_dir) - - -class ValidateRolesDataAction(base.TripleOAction): - """Validates Roles Data - - Validates the format of input (verify that each role in input has the - required attributes set. see README in roles directory in t-h-t), - validates that roles in input exist in roles directory in deployment plan - """ - - def __init__(self, roles, available_roles, - container=constants.DEFAULT_CONTAINER_NAME): - super(ValidateRolesDataAction, self).__init__() - self.container = container - self.roles = roles - self.available_roles = available_roles - - def run(self, context): - err_msg = "" - # validate roles in input exist in roles directory in t-h-t - try: - roles_utils.check_role_exists( - [role['name'] for role in self.available_roles], - [role['name'] for role in self.roles]) - except Exception as chk_err: - err_msg = str(chk_err) - - # validate role yaml - for role in self.roles: - try: - roles_utils.validate_role_yaml(yaml.safe_dump([role])) - except exception.RoleMetadataError as rme: - if 'name' in role: - err_msg += "\n%s for %s" % (str(rme), role['name']) - else: - err_msg += "\n%s" % str(rme) - - if err_msg: - return actions.Result(error=err_msg) - return actions.Result(data=True) - - -class UpdateRolesAction(base.TripleOAction): - """Updates roles_data.yaml object in plan with given roles. - - :param roles: role input data (json) - :param current_roles: data from roles_data.yaml file in plan (json) - :param replace_all: boolean value indicating if input roles should merge - with or replace data from roles_data.yaml. Defaults to False (merge) - :param container: name of the Swift container / plan name - """ - - def __init__(self, roles, current_roles, replace_all=False, - container=constants.DEFAULT_CONTAINER_NAME): - super(UpdateRolesAction, self).__init__() - self.container = container - self.roles = roles - self.current_roles = current_roles - self.replace_all = replace_all - - def run(self, context): - role_data_to_save = self.roles - - # if replace_all flag is true, discard current roles and save input - # if replace_all flag is false, merge input into current roles - if not self.replace_all: - # merge the roles_data and the role_input into roles to be saved - role_data_to_save = [role for role in { - x['name']: x for x in - self.current_roles + self.roles - }.values()] - - # ensure required primary tag exists in roles to be saved - primary = [role for role in role_data_to_save if - 'tags' in role and 'primary' in role['tags']] - if len(primary) < 1: - # throw error - raise exception.RoleMetadataError("At least one role must contain" - " a 'primary' tag.") - - # sort the data to have a predictable result - save_roles = sorted(role_data_to_save, key=itemgetter('name'), - reverse=True) - return actions.Result(data={'roles': save_roles}) - - -class RemoveNoopDeployStepAction(base.TripleOAction): - """Remove all the pre, post and deploy step in the plan-environment. - - :param container: name of the Swift container / plan name - """ - - def __init__(self, container=constants.DEFAULT_CONTAINER_NAME): - super(RemoveNoopDeployStepAction, self).__init__() - self.container = container - - def run(self, context): - # get the stack. Error if doesn't exist - heat = self.get_orchestration_client(context) - try: - stack = heat.stacks.get(self.container) - except heatexceptions.HTTPNotFound: - msg = "Error retrieving stack: %s" % self.container - LOG.exception(msg) - return actions.Result(error=msg) - - swift = self.get_object_client(context) - - # Get output and check if DeployStep are None - removals = ['OS::TripleO::DeploymentSteps'] - for output in stack.to_dict().get('outputs', {}): - if output['output_key'] == 'RoleData': - for role in output['output_value']: - removals.append("OS::TripleO::Tasks::%sPreConfig" % role) - removals.append("OS::TripleO::Tasks::%sPostConfig" % role) - - plan_env = plan_utils.get_env(swift, self.container) - self.remove_noops_from_env(removals, plan_env) - plan_utils.put_env(swift, plan_env) - - user_env = plan_utils.get_user_env(swift, self.container) - self.remove_noops_from_env(removals, user_env) - plan_utils.put_user_env(swift, self.container, user_env) - - def remove_noops_from_env(self, removals, env): - # Remove noop Steps - for rm in removals: - if rm in env.get('resource_registry', {}): - if env['resource_registry'][rm] == 'OS::Heat::None': - env['resource_registry'].pop(rm) diff --git a/tripleo_common/actions/scale.py b/tripleo_common/actions/scale.py deleted file mode 100644 index a6bda0eb7..000000000 --- a/tripleo_common/actions/scale.py +++ /dev/null @@ -1,176 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# All Rights Reserved. -# -# 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 collections -import logging - -from mistral_lib import actions - -from tripleo_common.actions import base -from tripleo_common.actions import parameters as parameters_actions -from tripleo_common import constants -from tripleo_common import update -from tripleo_common.utils import template as template_utils - -LOG = logging.getLogger(__name__) - - -def get_group_resources_after_delete(groupname, res_to_delete, resources): - group = next(res for res in resources if - res.resource_name == groupname and - res.resource_type == constants.RESOURCE_GROUP_TYPE) - members = [] - for res in resources: - stack_name, stack_id = next( - x['href'] for x in res.links if - x['rel'] == 'stack').rsplit('/', 2)[1:] - # desired new count of nodes after delete operation should be - # count of all existing nodes in ResourceGroup which are not - # in set of nodes being deleted. Also nodes in any delete state - # from a previous failed update operation are not included in - # overall count (if such nodes exist) - if (stack_id == group.physical_resource_id and - res not in res_to_delete and - not res.resource_status.startswith('DELETE')): - - members.append(res) - - return members - - -class ScaleDownAction(base.TripleOAction): - """Deletes overcloud nodes - - Before calling this method, ensure you have updated the plan - with any templates or environment files as needed. - """ - - def __init__(self, timeout, nodes=[], - container=constants.DEFAULT_CONTAINER_NAME): - self.container = container - self.nodes = nodes - self.timeout_mins = timeout - super(ScaleDownAction, self).__init__() - - def _update_stack(self, parameters={}, - timeout_mins=constants.STACK_TIMEOUT_DEFAULT, - context=None): - heat = self.get_orchestration_client(context) - swift = self.get_object_client(context) - # TODO(rbrady): migrate _update_stack to it's own action and update - # the workflow for scale down - - # update the plan parameters with the scaled down parameters - update_params_action = parameters_actions.UpdateParametersAction( - parameters, self.container) - updated_plan = update_params_action.run(context) - if isinstance(updated_plan, actions.Result): - return updated_plan - - processed_data = template_utils.process_templates( - swift, heat, container=self.container - ) - update.add_breakpoints_cleanup_into_env(processed_data['environment']) - - fields = processed_data.copy() - fields['timeout_mins'] = timeout_mins - fields['existing'] = True - # As we do a PATCH update when deleting nodes, parameters set for a - # stack before upgrade to newton (ex. ComputeRemovalPolicies), - # would still take precedence over the ones set in parameter_defaults - # after upgrade. Clear these parameters for backward compatibility. - fields['clear_parameters'] = list(parameters.keys()) - - LOG.debug('stack update params: %s', fields) - heat.stacks.update(self.container, **fields) - - def _get_removal_params_from_heat(self, resources_by_role, resources): - stack_params = {} - for role, role_resources in resources_by_role.items(): - param_name = "{0}Count".format(role) - - # get real count of nodes for each role. *Count stack parameters - # can not be used because stack parameters return parameters - # passed by user no matter if previous update operation succeeded - # or not - group_members = get_group_resources_after_delete( - role, role_resources, resources) - stack_params[param_name] = str(len(group_members)) - - # add instance resource names into removal_policies - # so heat knows which instances should be removed - removal_param = "{0}RemovalPolicies".format(role) - stack_params[removal_param] = [{ - 'resource_list': [r.resource_name for r in role_resources] - }] - - # force reset the removal_policies_mode to 'append' - # as 'update' can lead to deletion of unintended nodes. - removal_mode = "{0}RemovalPoliciesMode".format(role) - stack_params[removal_mode] = 'append' - - return stack_params - - def _match_hostname(self, heatclient, instance_list, res, stack_name): - type_patterns = ['DeployedServer', 'Server'] - if any(res.resource_type.endswith(x) for x in type_patterns): - res_details = heatclient.resources.get( - stack_name, res.resource_name) - if 'name' in res_details.attributes: - try: - instance_list.remove(res_details.attributes['name']) - return True - except ValueError: - return False - return False - - def run(self, context): - heatclient = self.get_orchestration_client(context) - resources = heatclient.resources.list(self.container, nested_depth=5) - resources_by_role = collections.defaultdict(list) - instance_list = list(self.nodes) - - for res in resources: - stack_name, stack_id = next( - x['href'] for x in res.links if - x['rel'] == 'stack').rsplit('/', 2)[1:] - - try: - instance_list.remove(res.physical_resource_id) - except ValueError: - if not self._match_hostname( - heatclient, instance_list, res, stack_name): - continue - - # get resource to remove from resource group (it's parent resource - # of nova server) - role_resource = next(x for x in resources if - x.physical_resource_id == stack_id) - # get the role name which is parent resource name in Heat - role = role_resource.parent_resource - resources_by_role[role].append(role_resource) - - resources_by_role = dict(resources_by_role) - - if instance_list: - raise ValueError( - "Couldn't find following instances in stack %s: %s" % - (self.container, ','.join(instance_list))) - - # decrease count for each role (or resource group) and set removal - # policy for each resource group - stack_params = self._get_removal_params_from_heat( - resources_by_role, resources) - - return self._update_stack(parameters=stack_params, context=context) diff --git a/tripleo_common/actions/validations.py b/tripleo_common/actions/validations.py deleted file mode 100644 index e6351a734..000000000 --- a/tripleo_common/actions/validations.py +++ /dev/null @@ -1,77 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# All Rights Reserved. -# -# 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. - -from mistral_lib import actions - -from tripleo_common.actions import base -from tripleo_common.utils import passwords as password_utils - - -class GetSshKeyAction(base.TripleOAction): - - def run(self, context): - mc = self.get_workflow_client(context) - try: - env = mc.environments.get('ssh_keys') - p_key = env.variables[self.key_type] - except Exception: - ssh_key = password_utils.create_ssh_keypair() - p_key = ssh_key[self.key_type] - - workflow_env = { - 'name': 'ssh_keys', - 'description': 'SSH keys for TripleO validations', - 'variables': ssh_key - } - mc.environments.create(**workflow_env) - - return p_key - - -class GetPubkeyAction(GetSshKeyAction): - - key_type = 'public_key' - - -class GetPrivkeyAction(GetSshKeyAction): - - key_type = 'private_key' - - -class Enabled(base.TripleOAction): - """Indicate whether the validations have been enabled.""" - - def _validations_enabled(self, context): - """Detect whether the validations are enabled on the undercloud.""" - mistral = self.get_workflow_client(context) - try: - # NOTE: the `ssh_keys` environment is created by - # instack-undercloud only when the validations are enabled on the - # undercloud (or when they're installed manually). Therefore, we - # can check for its presence here: - mistral.environments.get('ssh_keys') - return True - except Exception: - return False - - def run(self, context): - return_value = {'stderr': ''} - if self._validations_enabled(context): - return_value['stdout'] = 'Validations are enabled' - mistral_result = {"data": return_value} - else: - return_value['stdout'] = 'Validations are disabled' - mistral_result = {"error": return_value} - return actions.Result(**mistral_result) diff --git a/tripleo_common/filters/__init__.py b/tripleo_common/filters/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/tripleo_common/filters/capabilities_filter.py b/tripleo_common/filters/capabilities_filter.py deleted file mode 100644 index edbd745dc..000000000 --- a/tripleo_common/filters/capabilities_filter.py +++ /dev/null @@ -1,46 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# 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. - -from nova.scheduler import filters -from oslo_log import log as logging - - -LOG = logging.getLogger(__name__) - - -class TripleOCapabilitiesFilter(filters.BaseHostFilter): - """Filter hosts based on capabilities in boot request - - The standard Nova ComputeCapabilitiesFilter does not respect capabilities - requested in the scheduler_hints field, so we need a custom one in order - to be able to do predictable placement of nodes. - """ - - # list of hosts doesn't change within a request - run_filter_once_per_request = True - - def host_passes(self, host_state, spec_obj): - host_node = host_state.stats.get('node') - instance_node = spec_obj.scheduler_hints.get('capabilities:node') - # The instance didn't request a specific node - if not instance_node: - LOG.debug('No specific node requested') - return True - if host_node == instance_node[0]: - LOG.debug('Node tagged %s matches requested node %s', host_node, - instance_node[0]) - return True - LOG.debug('Node tagged %s does not match requested node %s', - host_node, instance_node[0]) - return False diff --git a/tripleo_common/filters/list.py b/tripleo_common/filters/list.py deleted file mode 100644 index d125c92ca..000000000 --- a/tripleo_common/filters/list.py +++ /dev/null @@ -1,27 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# 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 nova - -from tripleo_common.filters import capabilities_filter - - -def tripleo_filters(): - """Return a list of filter classes for TripleO - - This is a wrapper around the Nova all_filters function so we can add our - filters to the resulting list. - """ - nova_filters = nova.scheduler.filters.all_filters() - return (nova_filters + [capabilities_filter.TripleOCapabilitiesFilter]) diff --git a/tripleo_common/tests/actions/test_baremetal.py b/tripleo_common/tests/actions/test_baremetal.py index e5ee124a4..0243208f0 100644 --- a/tripleo_common/tests/actions/test_baremetal.py +++ b/tripleo_common/tests/actions/test_baremetal.py @@ -387,66 +387,6 @@ class TestConfigureRootDeviceAction(base.TestCase): self.assertEqual(self.ironic.node.update.call_count, 0) -class TestCellV2DiscoverHostsAction(base.TestCase): - - @mock.patch('tripleo_common.utils.nodes.run_nova_cell_v2_discovery') - def test_run(self, mock_command): - action = baremetal.CellV2DiscoverHostsAction() - action.run(mock.MagicMock()) - mock_command.assert_called_once() - - @mock.patch('tripleo_common.utils.nodes.run_nova_cell_v2_discovery') - def test_failure(self, mock_command): - mock_command.side_effect = processutils.ProcessExecutionError( - exit_code=1, - stdout='captured stdout', - stderr='captured stderr', - cmd='command' - ) - action = baremetal.CellV2DiscoverHostsAction() - result = action.run(mock.MagicMock()) - self.assertTrue(result.is_error()) - mock_command.assert_called_once() - - -class TestGetProfileAction(base.TestCase): - - def test_run(self): - mock_ctx = mock.MagicMock() - node = { - 'uuid': 'abcd1', - 'properties': { - 'capabilities': 'profile:compute' - } - } - action = baremetal.GetProfileAction(node=node) - result = action.run(mock_ctx) - expected_result = { - 'uuid': 'abcd1', - 'profile': 'compute' - } - self.assertEqual(expected_result, result) - - -class TestGetNodeHintAction(base.TestCase): - - def test_run(self): - mock_ctx = mock.MagicMock() - node = { - 'uuid': 'abcd1', - 'properties': { - 'capabilities': 'profile:compute,node:compute-0' - } - } - action = baremetal.GetNodeHintAction(node=node) - result = action.run(mock_ctx) - expected_result = { - 'uuid': 'abcd1', - 'hint': 'compute-0' - } - self.assertEqual(expected_result, result) - - @mock.patch.object(baremetal.socket, 'gethostbyname', lambda x: x) class TestGetCandidateNodes(base.TestCase): def setUp(self): diff --git a/tripleo_common/tests/actions/test_derive_params.py b/tripleo_common/tests/actions/test_derive_params.py deleted file mode 100644 index 08c40e10f..000000000 --- a/tripleo_common/tests/actions/test_derive_params.py +++ /dev/null @@ -1,561 +0,0 @@ -# Copyright 2017 Red Hat, Inc. -# All Rights Reserved. -# -# 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. - -from unittest import mock - -from mistral_lib import actions - -from tripleo_common.actions import derive_params -from tripleo_common.tests import base - - -class GetDpdkNicsNumaInfoActionTest(base.TestCase): - - def test_run_dpdk_port(self): - network_configs = [{ - "members": [{ - "members": [{"name": "nic5", "type": "interface"}], - "name": "dpdk0", - "type": "ovs_dpdk_port", - "mtu": 8192, - "rx_queue": 4}], - "name": "br-link", - "type": "ovs_user_bridge", - "addresses": [{"ip_netmask": ""}]}] - - inspect_data = { - "numa_topology": { - "nics": [{"name": "ens802f1", "numa_node": 1}, - {"name": "ens802f0", "numa_node": 1}, - {"name": "eno1", "numa_node": 0}, - {"name": "eno2", "numa_node": 0}, - {"name": "enp12s0f1", "numa_node": 0}, - {"name": "enp12s0f0", "numa_node": 0}, - {"name": "enp13s0f0", "numa_node": 0}, - {"name": "enp13s0f1", "numa_node": 0}] - }, - "inventory": { - "interfaces": [{"has_carrier": True, - "name": "ens802f1"}, - {"has_carrier": True, - "name": "ens802f0"}, - {"has_carrier": True, - "name": "eno1"}, - {"has_carrier": True, - "name": "eno2"}, - {"has_carrier": True, - "name": "enp12s0f0"}, - {"has_carrier": False, - "name": "enp13s0f0"}, - {"has_carrier": False, - "name": "enp13s0f1"}] - } - } - - expected_result = [{'bridge_name': 'br-link', 'name': 'ens802f1', - 'mtu': 8192, 'numa_node': 1, - 'addresses': [{'ip_netmask': ''}]}] - - mock_ctx = mock.MagicMock() - action = derive_params.GetDpdkNicsNumaInfoAction(network_configs, - inspect_data) - result = action.run(mock_ctx) - self.assertEqual(result, expected_result) - - def test_run_dpdk_bond(self): - network_configs = [{ - "members": [{"type": "ovs_dpdk_bond", "name": "dpdkbond0", - "mtu": 9000, "rx_queue": 4, - "members": [{"type": "ovs_dpdk_port", - "name": "dpdk0", - "members": [{"type": "interface", - "name": "nic4"}]}, - {"type": "ovs_dpdk_port", - "name": "dpdk1", - "members": [{"type": "interface", - "name": "nic5"}]}]}], - "name": "br-link", - "type": "ovs_user_bridge", - "addresses": [{"ip_netmask": "172.16.10.0/24"}]}] - inspect_data = { - "numa_topology": { - "nics": [{"name": "ens802f1", "numa_node": 1}, - {"name": "ens802f0", "numa_node": 1}, - {"name": "eno1", "numa_node": 0}, - {"name": "eno2", "numa_node": 0}, - {"name": "enp12s0f1", "numa_node": 0}, - {"name": "enp12s0f0", "numa_node": 0}, - {"name": "enp13s0f0", "numa_node": 0}, - {"name": "enp13s0f1", "numa_node": 0}] - }, - "inventory": { - "interfaces": [{"has_carrier": True, - "name": "ens802f1"}, - {"has_carrier": True, - "name": "ens802f0"}, - {"has_carrier": True, - "name": "eno1"}, - {"has_carrier": True, - "name": "eno2"}, - {"has_carrier": True, - "name": "enp12s0f0"}, - {"has_carrier": False, - "name": "enp13s0f0"}, - {"has_carrier": False, - "name": "enp13s0f1"}] - } - } - expected_result = [{'bridge_name': 'br-link', 'mtu': 9000, - 'numa_node': 1, 'name': 'ens802f0', - 'addresses': [{'ip_netmask': '172.16.10.0/24'}]}, - {'bridge_name': 'br-link', 'mtu': 9000, - 'numa_node': 1, 'name': 'ens802f1', - 'addresses': [{'ip_netmask': '172.16.10.0/24'}]}] - - mock_ctx = mock.MagicMock() - action = derive_params.GetDpdkNicsNumaInfoAction(network_configs, - inspect_data) - result = action.run(mock_ctx) - self.assertEqual(result, expected_result) - - @mock.patch.object(actions, 'Result', autospec=True) - def test_run_no_inspect_nics(self, mock_actions): - - network_configs = [{ - "members": [{ - "members": [{"name": "nic5", "type": "interface"}], - "name": "dpdk0", - "type": "ovs_dpdk_port", - "mtu": 8192, - "rx_queue": 4}], - "name": "br-link", - "type": "ovs_user_bridge"}] - - inspect_data = { - "numa_topology": { - "nics": [] - }, - "inventory": { - "interfaces": [{"has_carrier": True, - "name": "ens802f1"}, - {"has_carrier": True, - "name": "ens802f0"}, - {"has_carrier": True, - "name": "eno1"}, - {"has_carrier": True, - "name": "eno2"}, - {"has_carrier": True, - "name": "enp12s0f0"}, - {"has_carrier": False, - "name": "enp13s0f0"}, - {"has_carrier": False, - "name": "enp13s0f1"}] - } - } - - mock_ctx = mock.MagicMock() - action = derive_params.GetDpdkNicsNumaInfoAction(network_configs, - inspect_data) - action.run(mock_ctx) - msg = 'Introspection data does not have numa_topology.nics' - mock_actions.assert_called_once_with(error=msg) - - @mock.patch.object(actions, 'Result', autospec=True) - def test_run_no_inspect_interfaces(self, mock_actions): - - network_configs = [{ - "members": [{ - "members": [{"name": "nic5", "type": "interface"}], - "name": "dpdk0", - "type": "ovs_dpdk_port", - "mtu": 8192, - "rx_queue": 4}], - "name": "br-link", - "type": "ovs_user_bridge"}] - - inspect_data = { - "numa_topology": { - "nics": [] - }, - "inventory": { - "interfaces": [] - } - } - - mock_ctx = mock.MagicMock() - action = derive_params.GetDpdkNicsNumaInfoAction(network_configs, - inspect_data) - action.run(mock_ctx) - msg = 'Introspection data does not have inventory.interfaces' - mock_actions.assert_called_once_with(error=msg) - - @mock.patch.object(actions, 'Result', autospec=True) - def test_run_no_inspect_active_interfaces(self, mock_actions): - - network_configs = [{ - "members": [{ - "members": [{"name": "nic5", "type": "interface"}], - "name": "dpdk0", - "type": "ovs_dpdk_port", - "mtu": 8192, - "rx_queue": 4}], - "name": "br-link", - "type": "ovs_user_bridge"}] - - inspect_data = { - "numa_topology": { - "nics": [{"name": "ens802f1", "numa_node": 1}, - {"name": "ens802f0", "numa_node": 1}, - {"name": "eno1", "numa_node": 0}, - {"name": "eno2", "numa_node": 0}, - {"name": "enp12s0f1", "numa_node": 0}, - {"name": "enp12s0f0", "numa_node": 0}, - {"name": "enp13s0f0", "numa_node": 0}, - {"name": "enp13s0f1", "numa_node": 0}] - }, - "inventory": { - "interfaces": [{"has_carrier": False, - "name": "enp13s0f0"}, - {"has_carrier": False, - "name": "enp13s0f1"}] - } - } - - mock_ctx = mock.MagicMock() - action = derive_params.GetDpdkNicsNumaInfoAction(network_configs, - inspect_data) - action.run(mock_ctx) - msg = 'Unable to determine active interfaces (has_carrier)' - mock_actions.assert_called_once_with(error=msg) - - @mock.patch.object(actions, 'Result', autospec=True) - def test_run_no_numa_node(self, mock_actions): - network_configs = [{ - "members": [{ - "members": [{"name": "nic5", "type": "interface"}], - "name": "dpdk0", - "type": "ovs_dpdk_port", - "mtu": 8192, - "rx_queue": 4}], - "name": "br-link", - "type": "ovs_user_bridge"}] - - inspect_data = { - "numa_topology": { - "nics": [{"name": "ens802f1"}, - {"name": "ens802f0", "numa_node": 1}, - {"name": "eno1", "numa_node": 0}, - {"name": "eno2", "numa_node": 0}, - {"name": "enp12s0f1", "numa_node": 0}, - {"name": "enp12s0f0", "numa_node": 0}, - {"name": "enp13s0f0", "numa_node": 0}, - {"name": "enp13s0f1", "numa_node": 0}] - }, - "inventory": { - "interfaces": [{"has_carrier": True, - "name": "ens802f1"}, - {"has_carrier": True, - "name": "ens802f0"}, - {"has_carrier": True, - "name": "eno1"}, - {"has_carrier": True, - "name": "eno2"}, - {"has_carrier": True, - "name": "enp12s0f0"}, - {"has_carrier": False, - "name": "enp13s0f0"}, - {"has_carrier": False, - "name": "enp13s0f1"}] - } - } - - mock_ctx = mock.MagicMock() - action = derive_params.GetDpdkNicsNumaInfoAction(network_configs, - inspect_data) - action.run(mock_ctx) - msg = 'Unable to determine NUMA node for DPDK NIC: ens802f1' - mock_actions.assert_called_once_with(error=msg) - - -class GetDpdkCoreListActionTest(base.TestCase): - - def test_run(self): - inspect_data = { - "numa_topology": { - "cpus": [{"cpu": 21, "numa_node": 1, - "thread_siblings": [38, 82]}, - {"cpu": 27, "numa_node": 0, - "thread_siblings": [20, 64]}, - {"cpu": 3, "numa_node": 1, - "thread_siblings": [25, 69]}, - {"cpu": 20, "numa_node": 0, - "thread_siblings": [15, 59]}, - {"cpu": 17, "numa_node": 1, - "thread_siblings": [34, 78]}, - {"cpu": 16, "numa_node": 0, - "thread_siblings": [11, 55]}] - } - } - - numa_nodes_cores_count = [2, 1] - - expected_result = "20,64,15,59,38,82" - - mock_ctx = mock.MagicMock() - action = derive_params.GetDpdkCoreListAction(inspect_data, - numa_nodes_cores_count) - result = action.run(mock_ctx) - self.assertEqual(result, expected_result) - - @mock.patch.object(actions, 'Result', autospec=True) - def test_run_invalid_inspect_data(self, mock_actions): - inspect_data = {"numa_topology": {"cpus": []}} - - numa_nodes_cores_count = [2, 1] - - mock_ctx = mock.MagicMock() - action = derive_params.GetDpdkCoreListAction(inspect_data, - numa_nodes_cores_count) - action.run(mock_ctx) - msg = 'Introspection data does not have numa_topology.cpus' - mock_actions.assert_called_once_with(error=msg) - - @mock.patch.object(actions, 'Result', autospec=True) - def test_run_invalid_numa_nodes_cores_count(self, mock_actions): - inspect_data = {"numa_topology": { - "cpus": [{"cpu": 21, "numa_node": 1, "thread_siblings": [38, 82]}, - {"cpu": 27, "numa_node": 0, "thread_siblings": [20, 64]}] - }} - - numa_nodes_cores_count = [] - - mock_ctx = mock.MagicMock() - action = derive_params.GetDpdkCoreListAction(inspect_data, - numa_nodes_cores_count) - action.run(mock_ctx) - msg = 'CPU physical cores count for each NUMA nodes is not available' - mock_actions.assert_called_once_with(error=msg) - - -class GetHostCpusListActionTest(base.TestCase): - - def test_run_valid_inspect_data(self): - inspect_data = { - "numa_topology": { - "cpus": [{"cpu": 21, "numa_node": 1, - "thread_siblings": [38, 82]}, - {"cpu": 27, "numa_node": 0, - "thread_siblings": [20, 64]}, - {"cpu": 3, "numa_node": 1, - "thread_siblings": [25, 69]}, - {"cpu": 20, "numa_node": 0, - "thread_siblings": [15, 59]}] - } - } - expected_result = "15,59,25,69" - - mock_ctx = mock.MagicMock() - action = derive_params.GetHostCpusListAction(inspect_data) - result = action.run(mock_ctx) - self.assertEqual(result, expected_result) - - @mock.patch.object(actions, 'Result', autospec=True) - def test_run_invalid_inspect_data(self, mock_actions): - inspect_data = {"numa_topology": {"cpus": []}} - - mock_ctx = mock.MagicMock() - action = derive_params.GetHostCpusListAction(inspect_data) - action.run(mock_ctx) - msg = 'Introspection data does not have numa_topology.cpus' - mock_actions.assert_called_once_with(error=msg) - - -class GetDpdkSocketMemoryActionTest(base.TestCase): - - def test_run_valid_dpdk_nics_numa_info(self): - dpdk_nics_numa_info = [{"name": "ens802f1", "numa_node": 1, - "mtu": 8192}] - numa_nodes = [0, 1] - overhead = 800 - packet_size_in_buffer = (4096 * 64) - - expected_result = "1024,3072" - mock_ctx = mock.MagicMock() - action = derive_params.GetDpdkSocketMemoryAction( - dpdk_nics_numa_info, numa_nodes, overhead, - packet_size_in_buffer) - result = action.run(mock_ctx) - self.assertEqual(result, expected_result) - - def test_run_multiple_mtu_in_same_numa_node(self): - dpdk_nics_numa_info = [{"name": "ens802f1", "numa_node": 1, - "mtu": 1500}, - {"name": "ens802f2", "numa_node": 1, - "mtu": 2048}] - numa_nodes = [0, 1] - overhead = 800 - packet_size_in_buffer = (4096 * 64) - - expected_result = "1024,2048" - mock_ctx = mock.MagicMock() - action = derive_params.GetDpdkSocketMemoryAction( - dpdk_nics_numa_info, numa_nodes, overhead, packet_size_in_buffer) - result = action.run(mock_ctx) - self.assertEqual(result, expected_result) - - def test_run_duplicate_mtu_in_same_numa_node(self): - dpdk_nics_numa_info = [{"name": "ens802f1", "numa_node": 1, - "mtu": 4096}, - {"name": "ens802f2", "numa_node": 1, - "mtu": 4096}] - numa_nodes = [0, 1] - overhead = 800 - packet_size_in_buffer = (4096 * 64) - - expected_result = "1024,2048" - mock_ctx = mock.MagicMock() - action = derive_params.GetDpdkSocketMemoryAction( - dpdk_nics_numa_info, numa_nodes, overhead, packet_size_in_buffer) - result = action.run(mock_ctx) - self.assertEqual(result, expected_result) - - def test_run_valid_roundup_mtu(self): - dpdk_nics_numa_info = [{"name": "ens802f1", "numa_node": 1, - "mtu": 1200}] - numa_nodes = [0, 1] - overhead = 800 - packet_size_in_buffer = (4096 * 64) - - expected_result = "1024,2048" - mock_ctx = mock.MagicMock() - action = derive_params.GetDpdkSocketMemoryAction( - dpdk_nics_numa_info, numa_nodes, overhead, - packet_size_in_buffer) - result = action.run(mock_ctx) - self.assertEqual(result, expected_result) - - -class ConvertNumberToRangeListActionTest(base.TestCase): - - def test_run_with_ranges(self): - num_list = "0,22,23,24,25,60,65,66,67" - expected_result = "0,22-25,60,65-67" - - mock_ctx = mock.MagicMock() - action = derive_params.ConvertNumberToRangeListAction(num_list) - result = action.run(mock_ctx) - self.assertEqual(result, expected_result) - - @mock.patch.object(actions, 'Result', autospec=True) - def test_run_with_no_range(self, mock_actions): - num_list = "0,22,24,60,65,67" - expected_result = "0,22,24,60,65,67" - - mock_ctx = mock.MagicMock() - action = derive_params.ConvertNumberToRangeListAction(num_list) - result = action.run(mock_ctx) - self.assertEqual(result, expected_result) - - @mock.patch.object(actions, 'Result', autospec=True) - def test_run_with_empty_input(self, mock_actions): - num_list = "" - - mock_ctx = mock.MagicMock() - action = derive_params.ConvertNumberToRangeListAction(num_list) - action.run(mock_ctx) - msg = "Input param 'num_list' is blank." - mock_actions.assert_called_once_with(error=msg) - - @mock.patch.object(actions, 'Result', autospec=True) - def test_run_with_invalid_input(self, mock_actions): - num_list = ",d" - - mock_ctx = mock.MagicMock() - action = derive_params.ConvertNumberToRangeListAction(num_list) - action.run(mock_ctx) - msg = ("Invalid number in input param 'num_list': invalid " - "literal for int() with base 10: ''") - mock_actions.assert_called_once_with(error=msg) - - -class ConvertRangeToNumberListActionTest(base.TestCase): - - def test_run_with_ranges_in_comma_delimited_str(self): - range_list = "24-27,60,65-67" - expected_result = "24,25,26,27,60,65,66,67" - - mock_ctx = mock.MagicMock() - action = derive_params.ConvertRangeToNumberListAction(range_list) - result = action.run(mock_ctx) - self.assertEqual(result, expected_result) - - def test_run_with_ranges_in_comma_delimited_list(self): - range_list = ['24-27', '60', '65-67'] - expected_result = "24,25,26,27,60,65,66,67" - - mock_ctx = mock.MagicMock() - action = derive_params.ConvertRangeToNumberListAction(range_list) - result = action.run(mock_ctx) - self.assertEqual(result, expected_result) - - @mock.patch.object(actions, 'Result', autospec=True) - def test_run_with_ranges_exclude_num(self, mock_actions): - range_list = "24-27,^25,60,65-67" - expected_result = "24,26,27,60,65,66,67" - - mock_ctx = mock.MagicMock() - action = derive_params.ConvertRangeToNumberListAction(range_list) - result = action.run(mock_ctx) - self.assertEqual(result, expected_result) - - def test_run_with_no_ranges(self): - range_list = "24,25,26,27,60,65,66,67" - expected_result = "24,25,26,27,60,65,66,67" - - mock_ctx = mock.MagicMock() - action = derive_params.ConvertRangeToNumberListAction(range_list) - result = action.run(mock_ctx) - self.assertEqual(result, expected_result) - - @mock.patch.object(actions, 'Result', autospec=True) - def test_run_with_empty_input(self, mock_actions): - range_list = "" - - mock_ctx = mock.MagicMock() - action = derive_params.ConvertRangeToNumberListAction(range_list) - action.run(mock_ctx) - msg = "Input param 'range_list' is blank." - mock_actions.assert_called_once_with(error=msg) - - @mock.patch.object(actions, 'Result', autospec=True) - def test_run_with_invalid_input(self, mock_actions): - range_list = ",d" - - mock_ctx = mock.MagicMock() - action = derive_params.ConvertRangeToNumberListAction(range_list) - action.run(mock_ctx) - msg = ("Invalid number in input param 'range_list': invalid " - "literal for int() with base 10: ''") - mock_actions.assert_called_once_with(error=msg) - - @mock.patch.object(actions, 'Result', autospec=True) - def test_run_with_invalid_exclude_number(self, mock_actions): - range_list = "12-15,^17" - expected_result = "12,13,14,15" - - mock_ctx = mock.MagicMock() - action = derive_params.ConvertRangeToNumberListAction(range_list) - result = action.run(mock_ctx) - self.assertEqual(result, expected_result) diff --git a/tripleo_common/tests/actions/test_parameters.py b/tripleo_common/tests/actions/test_parameters.py deleted file mode 100644 index 3c4b51944..000000000 --- a/tripleo_common/tests/actions/test_parameters.py +++ /dev/null @@ -1,47 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# All Rights Reserved. -# -# 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. -from unittest import mock - -from tripleo_common.actions import parameters -from tripleo_common import exception -from tripleo_common.tests import base - - -class GetProfileOfFlavorActionTest(base.TestCase): - - @mock.patch('tripleo_common.utils.parameters.get_profile_of_flavor') - @mock.patch('tripleo_common.actions.base.TripleOAction.' - 'get_compute_client') - def test_profile_found(self, mock_get_compute_client, - mock_get_profile_of_flavor): - mock_ctx = mock.MagicMock() - mock_get_profile_of_flavor.return_value = 'compute' - action = parameters.GetProfileOfFlavorAction('oooq_compute') - result = action.run(mock_ctx) - expected_result = "compute" - self.assertEqual(result, expected_result) - - @mock.patch('tripleo_common.utils.parameters.get_profile_of_flavor') - @mock.patch('tripleo_common.actions.base.TripleOAction.' - 'get_compute_client') - def test_profile_not_found(self, mock_get_compute_client, - mock_get_profile_of_flavor): - mock_ctx = mock.MagicMock() - profile = (exception.DeriveParamsError, ) - mock_get_profile_of_flavor.side_effect = profile - action = parameters.GetProfileOfFlavorAction('no_profile') - result = action.run(mock_ctx) - self.assertTrue(result.is_error()) - mock_get_profile_of_flavor.assert_called_once() diff --git a/tripleo_common/tests/actions/test_plan.py b/tripleo_common/tests/actions/test_plan.py deleted file mode 100644 index cda8f44aa..000000000 --- a/tripleo_common/tests/actions/test_plan.py +++ /dev/null @@ -1,455 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# All Rights Reserved. -# -# 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. -from unittest import mock - -from heatclient import exc as heatexceptions -from oslo_concurrency import processutils -from swiftclient import exceptions as swiftexceptions - -from tripleo_common.actions import plan -from tripleo_common import exception -from tripleo_common.tests import base - - -ENV_YAML_CONTENTS = """ -version: 1.0 - -template: overcloud.yaml -environments: -- path: overcloud-resource-registry-puppet.yaml -- path: environments/services/sahara.yaml -parameter_defaults: - BlockStorageCount: 42 - OvercloudControlFlavor: yummy -passwords: - AdminPassword: aaaa - ZaqarPassword: zzzz -""" - -RESOURCES_YAML_CONTENTS = """heat_template_version: 2016-04-08 -resources: - Controller: - type: OS::Heat::ResourceGroup - NotRoleContoller: - type: OS::Dummy::DummyGroup - Compute: - type: OS::Heat::ResourceGroup -notresources: - BlockStorageDummy: - type: OS::Heat::ResourceGroup -""" - - -SAMPLE_ROLE = """ -############################################################################### -# Role: sample # -############################################################################### -- name: sample - description: | - Sample! - networks: - - InternalApi - HostnameFormatDefault: '%stackname%-sample-%index%' - ServicesDefault: - - OS::TripleO::Services::Timesync -""" - -SAMPLE_ROLE_OBJ = { - 'HostnameFormatDefault': '%stackname%-sample-%index%', - 'ServicesDefault': ['OS::TripleO::Services::Timesync'], - 'description': 'Sample!\n', - 'name': 'sample', - 'networks': ['InternalApi'] -} - - -SAMPLE_ROLE_2 = """ -############################################################################### -# Role: sample2 # -############################################################################### -- name: sample2 - description: | - Sample2! - networks: - - InternalApi - HostnameFormatDefault: '%stackname%-sample-%index%' - ServicesDefault: - - OS::TripleO::Services::Timesync -""" - -SAMPLE_ROLE_2_OBJ = { - 'HostnameFormatDefault': '%stackname%-sample-%index%', - 'ServicesDefault': ['OS::TripleO::Services::Timesync'], - 'description': 'Sample2!\n', - 'name': 'sample2', - 'networks': ['InternalApi'] -} - -UPDATED_ROLE = """ -############################################################################### -# Role: sample # -############################################################################### -- name: sample - description: | - Sample! - networks: - - InternalApi - - ExternalApi - tags: - - primary - HostnameFormatDefault: '%stackname%-sample-%index%' - ServicesDefault: - - OS::TripleO::Services::Timesync -""" - -UPDATED_ROLE_OBJ = { - 'HostnameFormatDefault': '%stackname%-sample-%index%', - 'ServicesDefault': ['OS::TripleO::Services::Timesync'], - 'description': 'Sample!\n', - 'name': 'sample', - 'networks': ['InternalApi', 'ExternalApi'], - 'tags': ['primary'] -} - - -class ListPlansActionTest(base.TestCase): - - def setUp(self): - super(ListPlansActionTest, self).setUp() - self.container = 'overcloud' - self.ctx = mock.MagicMock() - - @mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client') - def test_run(self, get_obj_client_mock): - - # setup swift - swift = mock.MagicMock() - swift.get_account.return_value = ({}, [ - { - 'count': 1, - 'bytes': 55, - 'name': 'overcloud' - }, - ]) - swift.get_container.return_value = ({ - 'x-container-meta-usage-tripleo': 'plan', - }, []) - get_obj_client_mock.return_value = swift - - # Test - action = plan.ListPlansAction() - action.run(self.ctx) - - # verify - self.assertEqual([self.container], action.run(self.ctx)) - swift.get_account.assert_called() - swift.get_container.assert_called_with(self.container) - - -class DeletePlanActionTest(base.TestCase): - - def setUp(self): - super(DeletePlanActionTest, self).setUp() - self.container_name = 'overcloud' - self.stack = mock.MagicMock( - id='123', - status='CREATE_COMPLETE', - stack_name=self.container_name - ) - self.ctx = mock.MagicMock() - - @mock.patch( - 'tripleo_common.actions.base.TripleOAction.get_orchestration_client') - def test_run_stack_exists(self, get_orchestration_client): - - # setup heat - heat = mock.MagicMock() - heat.stacks.get.return_value = self.stack - get_orchestration_client.return_value = heat - - # test that stack exists - action = plan.DeletePlanAction(self.container_name) - self.assertRaises(exception.StackInUseError, action.run, self.ctx) - heat.stacks.get.assert_called_with( - self.container_name, resolve_outputs=False) - - @mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client') - @mock.patch( - 'tripleo_common.actions.base.TripleOAction.get_orchestration_client') - def test_run(self, get_orchestration_client, get_obj_client_mock): - - # setup swift - swift = mock.MagicMock() - swift.get_account.return_value = ({}, [ - {'name': self.container_name}, - {'name': 'test'}, - ]) - swift.get_container.return_value = ( - {'x-container-meta-usage-tripleo': 'plan'}, [ - {'name': 'some-name.yaml'}, - {'name': 'some-other-name.yaml'}, - {'name': 'yet-some-other-name.yaml'}, - {'name': 'finally-another-name.yaml'} - ] - ) - - get_obj_client_mock.return_value = swift - - # setup heat - heat = mock.MagicMock() - heat.stacks.get = mock.Mock( - side_effect=heatexceptions.HTTPNotFound) - get_orchestration_client.return_value = heat - - action = plan.DeletePlanAction(self.container_name) - action.run(self.ctx) - - mock_calls = [ - mock.call('overcloud', 'some-name.yaml'), - mock.call('overcloud', 'some-other-name.yaml'), - mock.call('overcloud', 'yet-some-other-name.yaml'), - mock.call('overcloud', 'finally-another-name.yaml') - ] - swift.delete_object.assert_has_calls( - mock_calls, any_order=True) - - swift.delete_container.assert_called_with(self.container_name) - - -class ExportPlanActionTest(base.TestCase): - - def setUp(self): - super(ExportPlanActionTest, self).setUp() - self.plan = 'overcloud' - self.delete_after = 3600 - self.exports_container = 'plan-exports' - - # setup swift - self.template_files = ( - 'some-name.yaml', - 'some-other-name.yaml', - 'yet-some-other-name.yaml', - 'finally-another-name.yaml' - ) - self.swift = mock.MagicMock() - self.swift.get_container.return_value = ( - {'x-container-meta-usage-tripleo': 'plan'}, [ - {'name': tf} for tf in self.template_files - ] - ) - self.swift.get_object.return_value = ({}, RESOURCES_YAML_CONTENTS) - swift_patcher = mock.patch( - 'tripleo_common.actions.base.TripleOAction.get_object_client', - return_value=self.swift) - swift_patcher.start() - self.addCleanup(swift_patcher.stop) - - self.ctx = mock.MagicMock() - - @mock.patch('tripleo_common.actions.base.TripleOAction.get_object_service') - @mock.patch('tripleo_common.utils.tarball.create_tarball') - def test_run_success(self, - mock_create_tarball, - mock_get_obj_service): - - get_object_mock_calls = [ - mock.call(self.plan, tf) for tf in self.template_files - ] - - swift_service = mock.MagicMock() - swift_service.upload.return_value = ([ - {'success': True}, - ]) - mock_get_obj_service.return_value = swift_service - - action = plan.ExportPlanAction(self.plan, self.delete_after, - self.exports_container) - action.run(self.ctx) - - self.swift.get_container.assert_called_once_with(self.plan) - self.swift.get_object.assert_has_calls( - get_object_mock_calls, any_order=True) - swift_service.upload.assert_called_once() - mock_create_tarball.assert_called_once() - - @mock.patch('tripleo_common.actions.base.TripleOAction.get_object_service') - def test_run_container_does_not_exist(self, - mock_get_obj_service): - - self.swift.get_container.side_effect = swiftexceptions.ClientException( - self.plan) - - swift_service = mock.MagicMock() - swift_service.delete.return_value = ([ - {'success': True}, - ]) - mock_get_obj_service.return_value = swift_service - - action = plan.ExportPlanAction(self.plan, self.delete_after, - self.exports_container) - result = action.run(self.ctx) - - error = "Error attempting an operation on container: %s" % self.plan - self.assertIn(error, result.error) - - @mock.patch('tripleo_common.actions.base.TripleOAction.get_object_service') - @mock.patch('tripleo_common.utils.tarball.create_tarball') - def test_run_error_creating_tarball(self, - mock_create_tarball, - mock_get_obj_service): - - mock_create_tarball.side_effect = processutils.ProcessExecutionError - - swift_service = mock.MagicMock() - swift_service.delete.return_value = ([ - {'success': True}, - ]) - mock_get_obj_service.return_value = swift_service - - action = plan.ExportPlanAction(self.plan, self.delete_after, - self.exports_container) - result = action.run(self.ctx) - - error = "Error while creating a tarball" - self.assertIn(error, result.error) - - -class ValidateRolesDataActionTest(base.TestCase): - - def setUp(self): - super(ValidateRolesDataActionTest, self).setUp() - self.container = 'overcloud' - self.ctx = mock.MagicMock() - - def test_valid_roles(self): - current_roles = [SAMPLE_ROLE_OBJ] - requested_roles = [SAMPLE_ROLE_OBJ] - action = plan.ValidateRolesDataAction(requested_roles, current_roles) - result = action.run(self.ctx) - self.assertTrue(result.data) - - def test_invalid_roles(self): - current_roles = [SAMPLE_ROLE_2_OBJ] - requested_roles = [SAMPLE_ROLE_OBJ, ] - action = plan.ValidateRolesDataAction(requested_roles, current_roles) - result = action.run(self.ctx) - self.assertTrue(result.error) - - def test_validate_role_yaml_missing_name(self): - role = SAMPLE_ROLE_OBJ.copy() - del role['name'] - current_roles = [SAMPLE_ROLE_OBJ] - requested_roles = [role, ] - action = plan.ValidateRolesDataAction(requested_roles, current_roles) - result = action.run(self.ctx) - self.assertTrue(result.error) - - def test_validate_role_yaml_invalid_type(self): - role = SAMPLE_ROLE_OBJ.copy() - role['CountDefault'] = 'should not be a string' - current_roles = [SAMPLE_ROLE_OBJ] - requested_roles = [role, ] - action = plan.ValidateRolesDataAction(requested_roles, current_roles) - result = action.run(self.ctx) - self.assertTrue(result.error) - - -class UpdateRolesActionTest(base.TestCase): - - def setUp(self): - super(UpdateRolesActionTest, self).setUp() - self.container = 'overcloud' - self.ctx = mock.MagicMock() - self.current_roles = [SAMPLE_ROLE_OBJ, SAMPLE_ROLE_2_OBJ] - - def test_no_primary_roles(self): - updated_role = UPDATED_ROLE_OBJ.copy() - del updated_role['tags'] - action = plan.UpdateRolesAction([updated_role], - self.current_roles, - True, self.container) - - self.assertRaises(exception.RoleMetadataError, action.run, self.ctx) - - @mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client') - def test_update_some_roles(self, get_obj_client_mock): - # Setup - swift = mock.MagicMock() - get_obj_client_mock.return_value = swift - - action = plan.UpdateRolesAction([UPDATED_ROLE_OBJ], - self.current_roles, - False, self.container) - result = action.run(self.ctx) - - self.assertEqual(result.data, - {'roles': [SAMPLE_ROLE_2_OBJ, UPDATED_ROLE_OBJ]}) - - @mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client') - def test_update_replace_roles(self, get_obj_client_mock): - # Setup - swift = mock.MagicMock() - get_obj_client_mock.return_value = swift - - action = plan.UpdateRolesAction([UPDATED_ROLE_OBJ], - self.current_roles, - True, self.container) - result = action.run(self.ctx) - - self.assertEqual(result.data, {'roles': [UPDATED_ROLE_OBJ, ]}) - - -class RemoveNoopDeployStepActionTest(base.TestCase): - - def setUp(self): - super(RemoveNoopDeployStepActionTest, self).setUp() - self.container = 'overcloud' - self.ctx = mock.MagicMock() - self.heat = mock.MagicMock() - self.swift = mock.MagicMock() - self.rr_before = { - 'OS::TripleO::Foo': 'bar.yaml', - 'OS::TripleO::DeploymentSteps': 'OS::Heat::None', - } - self.rr_after = { - 'OS::TripleO::Foo': 'bar.yaml', - } - - @mock.patch('tripleo_common.actions.plan.plan_utils') - @mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client') - @mock.patch( - 'tripleo_common.actions.base.TripleOAction.get_orchestration_client') - def test_roles_gathered(self, mock_orch_client, mock_obj_client, - mock_plan_utils): - mock_obj_client.return_value = self.swift - mock_orch_client.return_value = self.heat - mock_plan_utils.get_env.return_value = { - 'name': self.container, - 'resource_registry': self.rr_before, - } - mock_plan_utils.get_user_env.return_value = { - 'resource_registry': self.rr_before, - } - action = plan.RemoveNoopDeployStepAction(self.container) - action.run(self.ctx) - - mock_plan_utils.put_env.assert_called_with( - self.swift, - { - 'name': self.container, - 'resource_registry': self.rr_after, - }) - mock_plan_utils.put_user_env.assert_called_with( - self.swift, self.container, {'resource_registry': self.rr_after}) diff --git a/tripleo_common/tests/actions/test_scale.py b/tripleo_common/tests/actions/test_scale.py deleted file mode 100644 index 02bf97518..000000000 --- a/tripleo_common/tests/actions/test_scale.py +++ /dev/null @@ -1,306 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# All Rights Reserved. -# -# 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 collections -from unittest import mock - -import yaml - -from mistral_lib import actions -from swiftclient import exceptions as swiftexceptions - -from tripleo_common.actions import scale -from tripleo_common import constants -from tripleo_common.tests import base - - -def mock_stack(): - stack = mock.Mock() - stack.name = 'My Stack' - stack.parameters = {'ComputeCount': '2'} - stack.to_dict.return_value = { - 'uuid': 5, - 'name': 'My Stack', - 'parameters': stack.parameters, - } - return stack - - -class ScaleDownActionTest(base.TestCase): - - def setUp(self): - super(ScaleDownActionTest, self).setUp() - self.image = collections.namedtuple('image', ['id']) - - @mock.patch('tripleo_common.actions.base.TripleOAction.' - 'get_orchestration_client') - @mock.patch('heatclient.common.template_utils.' - 'process_multiple_environments_and_files') - @mock.patch('heatclient.common.template_utils.get_template_contents') - @mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client') - def test_run(self, mock_get_object_client, - mock_get_template_contents, mock_env_files, - mock_get_heat_client): - - mock_env_files.return_value = ({}, {}) - heatclient = mock.MagicMock() - heatclient.resources.list.return_value = [ - mock.MagicMock( - links=[{'rel': 'stack', - 'href': 'http://192.0.2.1:8004/v1/' - 'a959ac7d6a4a475daf2428df315c41ef/' - 'stacks/overcloud/123'}], - logical_resource_id='logical_id', - physical_resource_id='resource_id', - resource_type='OS::Heat::ResourceGroup', - resource_name='Compute' - ), - mock.MagicMock( - links=[{'rel': 'stack', - 'href': 'http://192.0.2.1:8004/v1/' - 'a959ac7d6a4a475daf2428df315c41ef/' - 'stacks/overcloud/124'}], - logical_resource_id='node0', - physical_resource_id='124', - resource_type='OS::TripleO::Compute', - parent_resource='Compute', - resource_name='node0', - ) - ] - heatclient.stacks.get.return_value = mock_stack() - heatclient.stacks.validate.return_value = {} - mock_get_heat_client.return_value = heatclient - - mock_ctx = mock.MagicMock() - swift = mock.MagicMock(url="http://test.com") - mock_env = yaml.safe_dump({ - 'name': 'overcloud', - 'temp_environment': 'temp_environment', - 'template': 'template', - 'environments': [{u'path': u'environments/test.yaml'}] - }, default_flow_style=False) - mock_roles = yaml.safe_dump([{"name": "foo"}]) - mock_network = yaml.safe_dump([{'enabled': False}]) - mock_exclude = yaml.safe_dump({"name": "foo"}) - swift.get_object.side_effect = ( - ({}, mock_env), - ({}, mock_env), - ({}, mock_roles), - ({}, mock_network), - ({}, mock_exclude), - ({}, mock_env), - ({}, mock_env), - ({}, mock_env), - ({}, mock_roles), - ({}, mock_network), - ({}, mock_exclude), - ({}, mock_env), - ({}, mock_env), - swiftexceptions.ClientException('atest2') - ) - - def return_container_files(*args): - return ('headers', [{'name': 'foo.role.j2.yaml'}]) - - swift.get_container = mock.MagicMock( - side_effect=return_container_files) - mock_get_object_client.return_value = swift - - env = { - 'resource_registry': { - 'resources': {'*': {'*': {'UpdateDeployment': {'hooks': []}}}} - } - } - - mock_get_template_contents.return_value = ({}, { - 'heat_template_version': '2016-04-30' - }) - - # Test - action = scale.ScaleDownAction( - constants.STACK_TIMEOUT_DEFAULT, ['124'], 'stack') - result = action.run(mock_ctx) - - heatclient.stacks.validate.assert_called_once_with( - environment=env, - files={}, - show_nested=True, - template={'heat_template_version': '2016-04-30'} - ) - - clear_list = list(['ComputeCount', 'ComputeRemovalPolicies', - 'ComputeRemovalPoliciesMode']) - _, kwargs = heatclient.stacks.update.call_args - self.assertEqual(set(kwargs['clear_parameters']), set(clear_list)) - self.assertEqual(kwargs['environment'], env) - self.assertEqual(kwargs['existing'], True) - self.assertEqual(kwargs['files'], {}) - - self.assertEqual(None, result) - - @mock.patch('tripleo_common.actions.scale.ScaleDownAction.' - '_get_removal_params_from_heat') - @mock.patch('tripleo_common.actions.scale.ScaleDownAction._update_stack') - @mock.patch('tripleo_common.actions.base.TripleOAction.' - 'get_orchestration_client') - def test_run_bad_update(self, mock_get_heat_client, - mock__update_stack, - mock__get_removal_params_from_heat): - - mock__update_stack.return_value = actions.Result(error='Update error') - mock__get_removal_params_from_heat.return_value = {} - heatclient = mock.MagicMock() - heatclient.resources.list.return_value = [ - mock.MagicMock( - links=[{'rel': 'stack', - 'href': 'http://192.0.2.1:8004/v1/' - 'a959ac7d6a4a475daf2428df315c41ef/' - 'stacks/overcloud/123'}], - logical_resource_id='logical_id', - physical_resource_id='resource_id', - resource_type='OS::Heat::ResourceGroup', - resource_name='Compute' - ), - mock.MagicMock( - links=[{'rel': 'stack', - 'href': 'http://192.0.2.1:8004/v1/' - 'a959ac7d6a4a475daf2428df315c41ef/' - 'stacks/overcloud/124'}], - logical_resource_id='node0', - physical_resource_id='123', - resource_type='OS::TripleO::Compute', - parent_resource='Compute', - resource_name='node0', - ) - ] - heatclient.stacks.get.return_value = mock_stack() - heatclient.stacks.validate.return_value = {} - mock_get_heat_client.return_value = heatclient - - mock_ctx = mock.MagicMock() - - # Test - action = scale.ScaleDownAction( - constants.STACK_TIMEOUT_DEFAULT, ['resource_id'], 'stack') - result = action.run(mock_ctx) - - self.assertEqual(actions.Result(error='Update error'), result) - - @mock.patch('tripleo_common.actions.base.TripleOAction.' - 'get_orchestration_client') - @mock.patch('heatclient.common.template_utils.' - 'process_multiple_environments_and_files') - @mock.patch('heatclient.common.template_utils.get_template_contents') - @mock.patch('tripleo_common.actions.base.TripleOAction.get_object_client') - def test_run_with_hostmatch(self, mock_get_object_client, - mock_get_template_contents, mock_env_files, - mock_get_heat_client): - - mock_env_files.return_value = ({}, {}) - heatclient = mock.MagicMock() - heatclient.resources.list.return_value = [ - mock.MagicMock( - links=[{'rel': 'stack', - 'href': 'http://192.0.2.1:8004/v1/' - 'a959ac7d6a4a475daf2428df315c41ef/' - 'stacks/overcloud/123'}], - logical_resource_id='logical_id', - physical_resource_id='resource_id', - resource_type='OS::Heat::ResourceGroup', - resource_name='Compute' - ), - mock.MagicMock( - links=[{'rel': 'stack', - 'href': 'http://192.0.2.1:8004/v1/' - 'a959ac7d6a4a475daf2428df315c41ef/' - 'stacks/overcloud/124'}], - logical_resource_id='node0', - physical_resource_id='124', - resource_type='OS::TripleO::ComputeServer', - parent_resource='Compute', - resource_name='node0', - ) - ] - heatclient.resources.get.return_value = mock.MagicMock( - attributes={'name': 'node0'}) - heatclient.stacks.get.return_value = mock_stack() - heatclient.stacks.validate.return_value = {} - mock_get_heat_client.return_value = heatclient - - mock_ctx = mock.MagicMock() - swift = mock.MagicMock(url="http://test.com") - mock_env = yaml.safe_dump({ - 'name': 'overcloud', - 'temp_environment': 'temp_environment', - 'template': 'template', - 'environments': [{u'path': u'environments/test.yaml'}] - }, default_flow_style=False) - mock_roles = yaml.safe_dump([{"name": "foo"}]) - mock_network = yaml.safe_dump([{'enabled': False}]) - mock_exclude = yaml.safe_dump({"name": "foo"}) - swift.get_object.side_effect = ( - ({}, mock_env), - ({}, mock_env), - ({}, mock_roles), - ({}, mock_network), - ({}, mock_exclude), - ({}, mock_env), - ({}, mock_env), - ({}, mock_env), - ({}, mock_roles), - ({}, mock_network), - ({}, mock_exclude), - ({}, mock_env), - ({}, mock_env), - swiftexceptions.ClientException('atest2') - ) - - def return_container_files(*args): - return ('headers', [{'name': 'foo.role.j2.yaml'}]) - - swift.get_container = mock.MagicMock( - side_effect=return_container_files) - mock_get_object_client.return_value = swift - - env = { - 'resource_registry': { - 'resources': {'*': {'*': {'UpdateDeployment': {'hooks': []}}}} - } - } - - mock_get_template_contents.return_value = ({}, { - 'heat_template_version': '2016-04-30' - }) - - # Test - action = scale.ScaleDownAction( - constants.STACK_TIMEOUT_DEFAULT, ['node0'], 'stack') - result = action.run(mock_ctx) - - heatclient.stacks.validate.assert_called_once_with( - environment=env, - files={}, - show_nested=True, - template={'heat_template_version': '2016-04-30'} - ) - - clear_list = list(['ComputeCount', 'ComputeRemovalPolicies', - 'ComputeRemovalPoliciesMode']) - _, kwargs = heatclient.stacks.update.call_args - self.assertEqual(set(kwargs['clear_parameters']), set(clear_list)) - self.assertEqual(kwargs['environment'], env) - self.assertEqual(kwargs['existing'], True) - self.assertEqual(kwargs['files'], {}) - - self.assertEqual(None, result) diff --git a/tripleo_common/tests/actions/test_validations.py b/tripleo_common/tests/actions/test_validations.py deleted file mode 100644 index c1094ae4a..000000000 --- a/tripleo_common/tests/actions/test_validations.py +++ /dev/null @@ -1,105 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# All Rights Reserved. -# -# 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 collections -from unittest import mock - -from tripleo_common.actions import validations -from tripleo_common.tests import base - - -class GetPubkeyActionTest(base.TestCase): - - @mock.patch( - 'tripleo_common.actions.base.TripleOAction.get_workflow_client') - def test_run_existing_pubkey(self, get_workflow_client_mock): - mock_ctx = mock.MagicMock() - mistral = mock.MagicMock() - get_workflow_client_mock.return_value = mistral - environment = collections.namedtuple('environment', ['variables']) - mistral.environments.get.return_value = environment(variables={ - 'public_key': 'existing_pubkey' - }) - action = validations.GetPubkeyAction() - self.assertEqual('existing_pubkey', action.run(mock_ctx)) - - @mock.patch( - 'tripleo_common.actions.base.TripleOAction.get_workflow_client') - @mock.patch('tripleo_common.utils.passwords.create_ssh_keypair') - def test_run_no_pubkey(self, mock_create_keypair, - get_workflow_client_mock): - mock_ctx = mock.MagicMock() - mistral = mock.MagicMock() - get_workflow_client_mock.return_value = mistral - mistral.environments.get.side_effect = 'nope, sorry' - mock_create_keypair.return_value = { - 'public_key': 'public_key', - 'private_key': 'private_key', - } - - action = validations.GetPubkeyAction() - self.assertEqual('public_key', action.run(mock_ctx)) - - -class Enabled(base.TestCase): - - @mock.patch( - 'tripleo_common.actions.base.TripleOAction.get_workflow_client') - def test_validations_enabled(self, get_workflow_client_mock): - mock_ctx = mock.MagicMock() - mistral = mock.MagicMock() - get_workflow_client_mock.return_value = mistral - mistral.environments.get.return_value = {} - action = validations.Enabled() - result = action._validations_enabled(mock_ctx) - self.assertEqual(result, True) - - @mock.patch( - 'tripleo_common.actions.base.TripleOAction.get_workflow_client') - def test_validations_disabled(self, get_workflow_client_mock): - mock_ctx = mock.MagicMock() - mistral = mock.MagicMock() - get_workflow_client_mock.return_value = mistral - mistral.environments.get.side_effect = Exception() - action = validations.Enabled() - result = action._validations_enabled(mock_ctx) - self.assertEqual(result, False) - - @mock.patch( - 'tripleo_common.actions.validations.Enabled._validations_enabled') - @mock.patch( - 'tripleo_common.actions.base.TripleOAction.get_workflow_client') - def test_success_with_validations_enabled(self, get_workflow_client_mock, - validations_enabled_mock): - mock_ctx = mock.MagicMock() - validations_enabled_mock.return_value = True - action = validations.Enabled() - action_result = action.run(mock_ctx) - self.assertIsNone(action_result.error) - self.assertEqual('Validations are enabled', - action_result.data['stdout']) - - @mock.patch( - 'tripleo_common.actions.validations.Enabled._validations_enabled') - @mock.patch( - 'tripleo_common.actions.base.TripleOAction.get_workflow_client') - def test_success_with_validations_disabled(self, get_workflow_client_mock, - validations_enabled_mock): - mock_ctx = mock.MagicMock() - validations_enabled_mock.return_value = False - action = validations.Enabled() - action_result = action.run(mock_ctx) - self.assertIsNone(action_result.data) - self.assertEqual('Validations are disabled', - action_result.error['stdout']) diff --git a/tripleo_common/tests/test_filters.py b/tripleo_common/tests/test_filters.py deleted file mode 100644 index c81de0d3c..000000000 --- a/tripleo_common/tests/test_filters.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2016 Red Hat, Inc. -# -# 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 sys -from unittest import mock - -from tripleo_common.tests import base -from tripleo_common.tests import fake_nova - -# See the README file in the fake_nova module directory for details on why -# this is being done. -if 'nova' not in sys.modules: - sys.modules['nova'] = fake_nova -else: - raise RuntimeError('nova module already found in sys.modules. The ' - 'fake_nova injection should be removed.') -from tripleo_common.filters import capabilities_filter # noqa - - -class TestCapabilitiesFilter(base.TestCase): - def test_no_requested_node(self): - instance = capabilities_filter.TripleOCapabilitiesFilter() - host_state = mock.Mock() - host_state.stats.get.return_value = '' - spec_obj = mock.Mock() - spec_obj.scheduler_hints.get.return_value = [] - self.assertTrue(instance.host_passes(host_state, spec_obj)) - - def test_requested_node_matches(self): - def mock_host_get(key): - if key == 'node': - return 'compute-0' - self.fail('Unexpected key requested by filter') - - def mock_spec_get(key): - if key == 'capabilities:node': - return ['compute-0'] - self.fail('Unexpected key requested by filter') - - instance = capabilities_filter.TripleOCapabilitiesFilter() - host_state = mock.Mock() - host_state.stats.get.side_effect = mock_host_get - spec_obj = mock.Mock() - spec_obj.scheduler_hints.get.side_effect = mock_spec_get - self.assertTrue(instance.host_passes(host_state, spec_obj)) - - def test_requested_node_no_match(self): - instance = capabilities_filter.TripleOCapabilitiesFilter() - host_state = mock.Mock() - host_state.stats.get.return_value = 'controller-0' - spec_obj = mock.Mock() - spec_obj.scheduler_hints.get.return_value = ['compute-0'] - self.assertFalse(instance.host_passes(host_state, spec_obj)) diff --git a/tripleo_common/tests/test_workflows.py b/tripleo_common/tests/test_workflows.py deleted file mode 100644 index bd21acd0e..000000000 --- a/tripleo_common/tests/test_workflows.py +++ /dev/null @@ -1,43 +0,0 @@ -# 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 os - -import yaml - -from tripleo_common.tests import base - - -WORKBOOK_DIRECTORY = os.path.join(os.path.dirname(__file__), - '..', '..', 'workbooks') - - -class TestWorkflowStructure(base.TestCase): - - def setUp(self): - self.workbooks = os.listdir(WORKBOOK_DIRECTORY) - super(TestWorkflowStructure, self).setUp() - - def test_tags_are_set(self): - for workbook in self.workbooks: - if workbook.startswith('.'): - continue - full_path = os.path.join(WORKBOOK_DIRECTORY, workbook) - with open(full_path) as f: - wb_yaml = yaml.load(f) - message = ("tripleo-common-managed tag is missing from a " - "workflow in {}").format(full_path) - for wf_name, wf_spec in wb_yaml['workflows'].items(): - self.assertIn('tags', wf_spec, message) - self.assertIn('tripleo-common-managed', wf_spec['tags'], - message) diff --git a/workbooks/baremetal.yaml b/workbooks/baremetal.yaml deleted file mode 100644 index 87692bd82..000000000 --- a/workbooks/baremetal.yaml +++ /dev/null @@ -1,1349 +0,0 @@ ---- -version: '2.0' -name: tripleo.baremetal.v1 -description: TripleO Baremetal Workflows - -workflows: - - set_node_state: - input: - - node_uuid - - state_action - - target_state - - error_states: - # The default includes all failure states, even unused by TripleO. - - 'error' - - 'adopt failed' - - 'clean failed' - - 'deploy failed' - - 'inspect failed' - - 'rescue failed' - - tags: - - tripleo-common-managed - - tasks: - - set_provision_state: - on-success: wait_for_provision_state - on-error: set_provision_state_failed - action: ironic.node_set_provision_state node_uuid=<% $.node_uuid %> state=<% $.state_action %> - - set_provision_state_failed: - publish: - message: <% task(set_provision_state).result %> - on-complete: fail - - wait_for_provision_state: - action: ironic.node_get - input: - node_id: <% $.node_uuid %> - fields: ['provision_state', 'last_error'] - timeout: 1200 #20 minutes - retry: - delay: 3 - count: 400 - continue-on: <% not task().result.provision_state in [$.target_state] + $.error_states %> - on-complete: - - state_not_reached: <% task().result.provision_state != $.target_state %> - - state_not_reached: - publish: - message: >- - Node <% $.node_uuid %> did not reach state "<% $.target_state %>", - the state is "<% task(wait_for_provision_state).result.provision_state %>", - error: <% task(wait_for_provision_state).result.last_error %> - on-complete: fail - - output-on-error: - result: <% $.message %> - - set_power_state: - input: - - node_uuid - - state_action - - target_state - - error_state: 'error' - - tags: - - tripleo-common-managed - - tasks: - - set_power_state: - on-success: wait_for_power_state - on-error: set_power_state_failed - action: ironic.node_set_power_state node_id=<% $.node_uuid %> state=<% $.state_action %> - - set_power_state_failed: - publish: - message: <% task(set_power_state).result %> - on-complete: fail - - wait_for_power_state: - action: ironic.node_get - input: - node_id: <% $.node_uuid %> - fields: ['power_state', 'last_error'] - timeout: 120 #2 minutes - retry: - delay: 6 - count: 20 - continue-on: <% not task().result.power_state in [$.target_state, $.error_state] %> - on-complete: - - state_not_reached: <% task().result.power_state != $.target_state %> - - state_not_reached: - publish: - message: >- - Node <% $.node_uuid %> did not reach power state "<% $.target_state %>", - the state is "<% task(wait_for_power_state).result.power_state %>", - error: <% task(wait_for_power_state).result.last_error %> - on-complete: fail - - output-on-error: - result: <% $.message %> - - manual_cleaning: - input: - - node_uuid - - clean_steps - - timeout: 7200 # 2 hours (cleaning can take really long) - - retry_delay: 10 - - retry_count: 720 - - queue_name: tripleo - - tags: - - tripleo-common-managed - - tasks: - - set_provision_state: - on-success: wait_for_provision_state - on-error: set_provision_state_failed - action: ironic.node_set_provision_state node_uuid=<% $.node_uuid %> state='clean' cleansteps=<% $.clean_steps %> - - set_provision_state_failed: - on-success: send_message - publish: - status: FAILED - message: <% task(set_provision_state).result %> - - wait_for_provision_state: - action: ironic.node_get node_id=<% $.node_uuid %> - timeout: <% $.timeout %> - retry: - delay: <% $.retry_delay %> - count: <% $.retry_count %> - continue-on: <% task().result.provision_state != 'manageable' %> - on-complete: - - send_message: <% task().result.provision_state = 'manageable' %> - - state_not_reached: <% task().result.provision_state != 'manageable' %> - - state_not_reached: - publish: - status: FAILED - message: Cleaning of node <% $.node_uuid %> timed out. - 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() %> - - validate_nodes: - description: Validate nodes JSON - - input: - - nodes_json - - queue_name: tripleo - - tags: - - tripleo-common-managed - - tasks: - - validate_nodes: - action: tripleo.baremetal.validate_nodes - on-success: send_message - on-error: validation_failed - input: - nodes_json: <% $.nodes_json %> - - validation_failed: - on-success: send_message - publish: - status: FAILED - message: <% task(validate_nodes).result %> - - send_message: - workflow: tripleo.messaging.v1.send - input: - queue_name: <% $.queue_name %> - type: <% execution().name %> - status: <% $.get('status', 'SUCCESS') %> - message: <% $.get('message', '') %> - execution: <% execution() %> - - register_or_update: - description: Take nodes JSON and create nodes in a "manageable" state - - input: - - nodes_json - - remove: False - - queue_name: tripleo - - kernel_name: null - - ramdisk_name: null - - instance_boot_option: null - - initial_state: manageable - - tags: - - tripleo-common-managed - - tasks: - - validate_input: - workflow: tripleo.baremetal.v1.validate_nodes - on-success: register_or_update_nodes - on-error: validation_failed - input: - nodes_json: <% $.nodes_json %> - queue_name: <% $.queue_name %> - - validation_failed: - on-success: send_message - publish: - status: FAILED - message: <% task(validate_input).result %> - registered_nodes: [] - - register_or_update_nodes: - action: tripleo.baremetal.register_or_update_nodes - on-success: - - set_nodes_managed: <% $.initial_state != "enroll" %> - - send_message: <% $.initial_state = "enroll" %> - on-error: set_status_failed_register_or_update_nodes - input: - nodes_json: <% $.nodes_json %> - remove: <% $.remove %> - kernel_name: <% $.kernel_name %> - ramdisk_name: <% $.ramdisk_name %> - instance_boot_option: <% $.instance_boot_option %> - publish: - registered_nodes: <% task().result %> - new_nodes: <% task().result.where($.provision_state = 'enroll') %> - - set_status_failed_register_or_update_nodes: - on-success: send_message - publish: - status: FAILED - message: <% task(register_or_update_nodes).result %> - registered_nodes: [] - - set_nodes_managed: - on-success: - - set_nodes_available: <% $.initial_state = "available" %> - - send_message: <% $.initial_state != "available" %> - on-error: set_status_failed_nodes_managed - workflow: tripleo.baremetal.v1.manage - input: - node_uuids: <% $.new_nodes.uuid %> - queue_name: <% $.queue_name %> - publish: - status: SUCCESS - message: <% $.new_nodes.len() %> node(s) successfully moved to the "manageable" state. - - set_status_failed_nodes_managed: - on-success: send_message - publish: - status: FAILED - message: <% task(set_nodes_managed).result %> - - set_nodes_available: - on-success: send_message - on-error: set_status_failed_nodes_available - workflow: tripleo.baremetal.v1.provide node_uuids=<% $.new_nodes.uuid %> queue_name=<% $.queue_name %> - publish: - status: SUCCESS - message: <% $.new_nodes.len() %> node(s) successfully moved to the "available" state. - - set_status_failed_nodes_available: - on-success: send_message - publish: - status: FAILED - message: <% task(set_nodes_available).result %> - - 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: <% { registered_nodes => $.registered_nodes or [] } %> - - provide: - description: Take a list of nodes and move them to "available" - - input: - - node_uuids - - queue_name: tripleo - - tags: - - tripleo-common-managed - - tasks: - - set_nodes_available: - on-success: cell_v2_discover_hosts - on-error: set_status_failed_nodes_available - with-items: uuid in <% $.node_uuids %> - workflow: tripleo.baremetal.v1.set_node_state - input: - node_uuid: <% $.uuid %> - queue_name: <% $.queue_name %> - state_action: 'provide' - target_state: 'available' - - set_status_failed_nodes_available: - on-success: send_message - publish: - status: FAILED - message: <% task(set_nodes_available).result %> - - cell_v2_discover_hosts: - on-success: try_power_off - on-error: cell_v2_discover_hosts_failed - workflow: tripleo.baremetal.v1.cellv2_discovery - input: - node_uuids: <% $.node_uuids %> - queue_name: <% $.queue_name %> - timeout: 900 #15 minutes - retry: - delay: 30 - count: 30 - - cell_v2_discover_hosts_failed: - on-success: send_message - publish: - status: FAILED - message: <% task(cell_v2_discover_hosts).result %> - - try_power_off: - on-success: send_message - on-error: power_off_failed - with-items: uuid in <% $.node_uuids %> - workflow: tripleo.baremetal.v1.set_power_state - input: - node_uuid: <% $.uuid %> - queue_name: <% $.queue_name %> - state_action: 'off' - target_state: 'power off' - publish: - status: SUCCESS - message: <% $.node_uuids.len() %> node(s) successfully moved to the "available" state. - - power_off_failed: - on-success: send_message - publish: - status: FAILED - message: <% task(try_power_off).result %> - - send_message: - workflow: tripleo.messaging.v1.send - input: - queue_name: <% $.queue_name %> - type: <% execution().name %> - status: <% $.get('status', 'SUCCESS') %> - message: <% $.get('message', '') %> - execution: <% execution() %> - - provide_manageable_nodes: - description: Provide all nodes in a 'manageable' state. - - input: - - queue_name: tripleo - - tags: - - tripleo-common-managed - - tasks: - - get_manageable_nodes: - action: ironic.node_list maintenance=False associated=False provision_state="manageable" limit=0 - on-success: provide_manageable - on-error: set_status_failed_get_manageable_nodes - publish: - managed_nodes: <% task().result.uuid %> - - set_status_failed_get_manageable_nodes: - on-success: send_message - publish: - status: FAILED - message: <% task(get_manageable_nodes).result %> - - provide_manageable: - on-success: send_message - workflow: tripleo.baremetal.v1.provide - input: - node_uuids: <% $.managed_nodes %> - queue_name: <% $.queue_name %> - publish: - status: SUCCESS - - send_message: - workflow: tripleo.messaging.v1.send - input: - queue_name: <% $.queue_name %> - type: <% execution().name %> - status: <% $.get('status', 'SUCCESS') %> - message: <% $.get('message', '') %> - execution: <% execution() %> - - manage: - description: Set a list of nodes to 'manageable' state - - input: - - node_uuids - - queue_name: tripleo - - tags: - - tripleo-common-managed - - tasks: - - set_nodes_manageable: - on-success: send_message - on-error: set_status_failed_nodes_manageable - with-items: uuid in <% $.node_uuids %> - workflow: tripleo.baremetal.v1.set_node_state - input: - node_uuid: <% $.uuid %> - state_action: 'manage' - target_state: 'manageable' - error_states: - # node going back to enroll designates power credentials failure - - 'enroll' - - 'error' - - set_status_failed_nodes_manageable: - on-success: send_message - publish: - status: FAILED - message: <% task(set_nodes_manageable).result %> - - send_message: - workflow: tripleo.messaging.v1.send - input: - queue_name: <% $.queue_name %> - type: <% execution().name %> - status: <% $.get('status', 'SUCCESS') %> - message: <% $.get('message', '') %> - execution: <% execution() %> - - _introspect: - description: > - An internal workflow. The tripleo.baremetal.v1.introspect workflow - should be used for introspection. - - input: - - node_uuid - - timeout - - queue_name - - output: - result: <% task(start_introspection).result %> - - tags: - - tripleo-common-managed - - tasks: - start_introspection: - action: baremetal_introspection.introspect uuid=<% $.node_uuid %> - on-success: wait_for_introspection_to_finish - on-error: set_status_failed_start_introspection - - set_status_failed_start_introspection: - publish: - status: FAILED - message: <% task(start_introspection).result %> - introspected_nodes: [] - on-success: send_message - - wait_for_introspection_to_finish: - action: baremetal_introspection.wait_for_finish - input: - uuids: <% [$.node_uuid] %> - # The interval is 10 seconds, so divide to make the overall timeout - # in seconds correct. - max_retries: <% $.timeout / 10 %> - retry_interval: 10 - publish: - introspected_node: <% task().result.values().first() %> - status: <% bool(task().result.values().first().error) and "FAILED" or "SUCCESS" %> - publish-on-error: - status: FAILED - message: <% task().result %> - on-success: wait_for_introspection_to_finish_success - on-error: wait_for_introspection_to_finish_error - - wait_for_introspection_to_finish_success: - publish: - message: <% "Introspection of node completed:{0}. Status:{1}. Errors:{2}".format($.introspected_node.uuid, $.status, $.introspected_node.error) %> - on-success: send_message - - wait_for_introspection_to_finish_error: - on-success: send_message - publish: - status: FAILED - message: <% "Introspection of node attempt failed:{0}.".format($.node_uuid) %> - - 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: <% { introspected_node => $.get('introspected_node'), node_uuid => $.node_uuid } %> - - introspect: - description: > - Take a list of nodes and move them through introspection. - - By default each node will attempt introspection up to 3 times (two - retries plus the initial attemp) if it fails. This behaviour can be - modified by changing the max_retry_attempts input. - - The workflow will assume the node has timed out after 20 minutes (1200 - seconds). This can be changed by passing the node_timeout input in - seconds. - - input: - - node_uuids - - run_validations: False - - queue_name: tripleo - - concurrency: 20 - - max_retry_attempts: 2 - - node_timeout: 1200 - - tags: - - tripleo-common-managed - - tasks: - initialize: - publish: - introspection_attempt: 0 - on-complete: - - run_validations: <% $.run_validations %> - - introspect_nodes: <% not $.run_validations %> - - run_validations: - workflow: tripleo.validations.v1.run_groups - input: - group_names: - - 'pre-introspection' - queue_name: <% $.queue_name %> - on-success: introspect_nodes - on-error: set_validations_failed - - set_validations_failed: - on-success: send_message - publish: - status: FAILED - message: <% task(run_validations).result %> - - introspect_nodes: - with-items: uuid in <% $.node_uuids %> - concurrency: <% $.concurrency %> - workflow: _introspect - input: - node_uuid: <% $.uuid %> - queue_name: <% $.queue_name %> - timeout: <% $.node_timeout %> - # on-error is triggered if one or more nodes failed introspection. We - # still go to get_introspection_status as it will collect the result - # for each node. Unless we hit the retry limit. - on-error: - - get_introspection_status: <% $.introspection_attempt <= $.max_retry_attempts %> - - max_retry_attempts_reached: <% $.introspection_attempt > $.max_retry_attempts %> - on-success: get_introspection_status - - get_introspection_status: - with-items: uuid in <% $.node_uuids %> - action: baremetal_introspection.get_status - input: - uuid: <% $.uuid %> - publish: - introspected_nodes: <% task().result.toDict($.uuid, $) %> - # Currently there is no way for us to ignore user introspection - # aborts. This means we will retry aborted nodes until the Ironic API - # gives us more details (error code or a boolean to show aborts etc.) - # If a node hasn't finished, we consider it to be failed. - # TODO(d0ugal): When possible, don't retry introspection of nodes - # that a user manually aborted. - failed_introspection: <% task().result.where($.finished = true and $.error != null).select($.uuid) + task().result.where($.finished = false).select($.uuid) %> - publish-on-error: - # If a node fails to start introspection, getting the status can fail. - # When that happens, the result is a string and the nodes need to be - # filtered out. - introspected_nodes: <% task().result.where(isDict($)).toDict($.uuid, $) %> - # If there was an error, the exception string we get doesn't give us - # the UUID. So we use a set difference to find the UUIDs missing in - # the results. These are then added to the failed nodes. - failed_introspection: <% ($.node_uuids.toSet() - task().result.where(isDict($)).select($.uuid).toSet()) + task().result.where(isDict($)).where($.finished = true and $.error != null).toSet() + task().result.where(isDict($)).where($.finished = false).toSet() %> - on-error: increase_attempt_counter - on-success: - - successful_introspection: <% $.failed_introspection.len() = 0 %> - - increase_attempt_counter: <% $.failed_introspection.len() > 0 %> - - increase_attempt_counter: - publish: - introspection_attempt: <% $.introspection_attempt + 1 %> - on-complete: - retry_failed_nodes - - retry_failed_nodes: - publish: - status: RUNNING - message: <% 'Retrying {0} nodes that failed introspection. Attempt {1} of {2} '.format($.failed_introspection.len(), $.introspection_attempt, $.max_retry_attempts + 1) %> - # We are about to retry, update the tracking stats. - node_uuids: <% $.failed_introspection %> - on-success: - - send_message - - introspect_nodes - - max_retry_attempts_reached: - publish: - status: FAILED - message: <% 'Retry limit reached with {0} nodes still failing introspection'.format($.failed_introspection.len()) %> - on-complete: send_message - - successful_introspection: - publish: - status: SUCCESS - message: Successfully introspected <% $.introspected_nodes.len() %> node(s). - 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: <% { introspected_nodes => $.get('introspected_nodes', []), failed_introspection => $.get('failed_introspection', []) } %> - - introspect_manageable_nodes: - description: Introspect all nodes in a 'manageable' state. - - input: - - run_validations: False - - queue_name: tripleo - - concurrency: 20 - - tags: - - tripleo-common-managed - - tasks: - - get_manageable_nodes: - action: ironic.node_list maintenance=False associated=False provision_state="manageable" limit=0 - on-success: validate_nodes - on-error: set_status_failed_get_manageable_nodes - publish: - managed_nodes: <% task().result.uuid %> - - set_status_failed_get_manageable_nodes: - on-success: send_message - publish: - status: FAILED - message: <% task(get_manageable_nodes).result %> - - validate_nodes: - on-success: - - introspect_manageable: <% $.managed_nodes.len() > 0 %> - - set_status_failed_no_nodes: <% $.managed_nodes.len() = 0 %> - - set_status_failed_no_nodes: - on-success: send_message - publish: - status: FAILED - message: No manageable nodes to introspect. Check node states and maintenance. - - introspect_manageable: - on-success: send_message - on-error: set_status_introspect_manageable - workflow: tripleo.baremetal.v1.introspect - input: - node_uuids: <% $.managed_nodes %> - run_validations: <% $.run_validations %> - queue_name: <% $.queue_name %> - concurrency: <% $.concurrency %> - publish: - introspected_nodes: <% task().result.introspected_nodes %> - - set_status_introspect_manageable: - on-success: send_message - publish: - status: FAILED - message: <% task(introspect_manageable).result %> - introspected_nodes: [] - - 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: <% { introspected_nodes => $.get('introspected_nodes', []) } %> - - configure: - description: Take a list of manageable nodes and update their boot configuration. - - input: - - node_uuids - - queue_name: tripleo - - kernel_name: bm-deploy-kernel - - ramdisk_name: bm-deploy-ramdisk - - instance_boot_option: null - - root_device: null - - root_device_minimum_size: 4 - - overwrite_root_device_hints: False - - tags: - - tripleo-common-managed - - tasks: - - configure_boot: - on-success: configure_root_device - on-error: set_status_failed_configure_boot - with-items: node_uuid in <% $.node_uuids %> - action: tripleo.baremetal.configure_boot node_uuid=<% $.node_uuid %> kernel_name=<% $.kernel_name %> ramdisk_name=<% $.ramdisk_name %> instance_boot_option=<% $.instance_boot_option %> - - configure_root_device: - on-success: send_message - on-error: set_status_failed_configure_root_device - with-items: node_uuid in <% $.node_uuids %> - action: tripleo.baremetal.configure_root_device node_uuid=<% $.node_uuid %> root_device=<% $.root_device %> minimum_size=<% $.root_device_minimum_size %> overwrite=<% $.overwrite_root_device_hints %> - publish: - status: SUCCESS - message: 'Successfully configured the nodes.' - - set_status_failed_configure_boot: - on-success: send_message - publish: - status: FAILED - message: <% task(configure_boot).result %> - - set_status_failed_configure_root_device: - on-success: send_message - publish: - status: FAILED - message: <% task(configure_root_device).result %> - - send_message: - workflow: tripleo.messaging.v1.send - input: - queue_name: <% $.queue_name %> - type: <% execution().name %> - status: <% $.get('status', 'SUCCESS') %> - message: <% $.get('message', '') %> - execution: <% execution() %> - - configure_manageable_nodes: - description: Update the boot configuration of all nodes in 'manageable' state. - - input: - - queue_name: tripleo - - kernel_name: 'bm-deploy-kernel' - - ramdisk_name: 'bm-deploy-ramdisk' - - instance_boot_option: null - - root_device: null - - root_device_minimum_size: 4 - - overwrite_root_device_hints: False - - tags: - - tripleo-common-managed - - tasks: - - get_manageable_nodes: - action: ironic.node_list maintenance=False associated=False provision_state="manageable" limit=0 - on-success: configure_manageable - on-error: set_status_failed_get_manageable_nodes - publish: - managed_nodes: <% task().result.uuid %> - - configure_manageable: - on-success: send_message - on-error: set_status_failed_configure_manageable - workflow: tripleo.baremetal.v1.configure - input: - node_uuids: <% $.managed_nodes %> - queue_name: <% $.queue_name %> - kernel_name: <% $.kernel_name %> - ramdisk_name: <% $.ramdisk_name %> - instance_boot_option: <% $.instance_boot_option %> - root_device: <% $.root_device %> - root_device_minimum_size: <% $.root_device_minimum_size %> - overwrite_root_device_hints: <% $.overwrite_root_device_hints %> - publish: - message: 'Manageable nodes configured successfully.' - - set_status_failed_configure_manageable: - on-success: send_message - publish: - status: FAILED - message: <% task(configure_manageable).result %> - - set_status_failed_get_manageable_nodes: - on-success: send_message - publish: - status: FAILED - message: <% task(get_manageable_nodes).result %> - - send_message: - workflow: tripleo.messaging.v1.send - input: - queue_name: <% $.queue_name %> - type: <% execution().name %> - status: <% $.get('status', 'SUCCESS') %> - message: <% $.get('message', '') %> - execution: <% execution() %> - - tag_node: - description: Tag a node with a role - input: - - node_uuid - - role: null - - queue_name: tripleo - - tags: - - tripleo-common-managed - - tasks: - - update_node: - on-complete: send_message - action: tripleo.baremetal.update_node_capability node_uuid=<% $.node_uuid %> capability='profile' value=<% $.role %> - publish: - message: <% task().result %> - status: SUCCESS - - send_message: - workflow: tripleo.messaging.v1.send - input: - queue_name: <% $.queue_name %> - type: <% execution().name %> - status: <% $.get('status', 'SUCCESS') %> - message: <% $.get('message', '') %> - execution: <% execution() %> - - tag_nodes: - description: Runs the tag_node workflow in a loop - input: - - tag_node_uuids - - untag_node_uuids - - role - - plan: overcloud - - queue_name: tripleo - - tags: - - tripleo-common-managed - - tasks: - - tag_nodes: - with-items: node_uuid in <% $.tag_node_uuids %> - workflow: tripleo.baremetal.v1.tag_node - input: - node_uuid: <% $.node_uuid %> - queue_name: <% $.queue_name %> - role: <% $.role %> - concurrency: 1 - on-success: untag_nodes - on-error: send_message - - untag_nodes: - with-items: node_uuid in <% $.untag_node_uuids %> - workflow: tripleo.baremetal.v1.tag_node - input: - node_uuid: <% $.node_uuid %> - queue_name: <% $.queue_name %> - concurrency: 1 - on-success: update_role_parameters - on-error: send_message - - update_role_parameters: - on-complete: send_message - action: tripleo.parameters.update_role role=<% $.role %> container=<% $.plan %> - publish: - message: <% task().result %> - status: SUCCESS - - send_message: - workflow: tripleo.messaging.v1.send - input: - queue_name: <% $.queue_name %> - type: <% execution().name %> - status: <% $.get('status', 'FAILED') %> - message: <% $.get('message', '') %> - execution: <% execution() %> - - nodes_with_hint: - description: Find nodes matching a hint regex - input: - - hint_regex - - queue_name: tripleo - - tags: - - tripleo-common-managed - - tasks: - get_nodes: - with-items: provision_state in <% ['available', 'active'] %> - action: ironic.node_list maintenance=false provision_state=<% $.provision_state %> detail=true - on-success: get_matching_nodes - on-error: set_status_failed_get_nodes - - get_matching_nodes: - with-items: node in <% task(get_nodes).result.flatten() %> - action: tripleo.baremetal.get_node_hint node=<% $.node %> - on-success: send_message - on-error: set_status_failed_get_matching_nodes - publish: - matching_nodes: <% let(hint_regex => $.hint_regex) -> task().result.where($.hint and $.hint.matches($hint_regex)).uuid %> - - set_status_failed_get_nodes: - on-success: send_message - publish: - status: FAILED - message: <% task(get_nodes).result %> - - set_status_failed_get_matching_nodes: - on-success: send_message - publish: - status: FAILED - message: <% task(get_matching_nodes).result %> - - 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: - matching_nodes: <% $.matching_nodes or [] %> - - nodes_with_profile: - description: Find nodes with a specific profile - input: - - profile - - queue_name: tripleo - - tags: - - tripleo-common-managed - - tasks: - get_active_nodes: - action: ironic.node_list maintenance=false provision_state='active' detail=true - on-success: get_available_nodes - on-error: set_status_failed_get_active_nodes - - get_available_nodes: - action: ironic.node_list maintenance=false provision_state='available' detail=true - on-success: get_matching_nodes - on-error: set_status_failed_get_available_nodes - - get_matching_nodes: - with-items: node in <% task(get_available_nodes).result + task(get_active_nodes).result %> - action: tripleo.baremetal.get_profile node=<% $.node %> - on-success: send_message - on-error: set_status_failed_get_matching_nodes - publish: - matching_nodes: <% let(input_profile_name => $.profile) -> task().result.where($.profile = $input_profile_name).uuid %> - - set_status_failed_get_active_nodes: - on-success: send_message - publish: - status: FAILED - message: <% task(get_active_nodes).result %> - - set_status_failed_get_available_nodes: - on-success: send_message - publish: - status: FAILED - message: <% task(get_available_nodes).result %> - - set_status_failed_get_matching_nodes: - on-success: send_message - publish: - status: FAILED - message: <% task(get_matching_nodes).result %> - - 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: <% { matching_nodes => $.matching_nodes or [] } %> - - create_raid_configuration: - description: Create and apply RAID configuration for given nodes - input: - - node_uuids - - configuration - - queue_name: tripleo - - tags: - - tripleo-common-managed - - tasks: - - set_configuration: - with-items: node_uuid in <% $.node_uuids %> - action: ironic.node_set_target_raid_config node_ident=<% $.node_uuid %> target_raid_config=<% $.configuration %> - on-success: apply_configuration - on-error: set_configuration_failed - - set_configuration_failed: - on-success: send_message - publish: - status: FAILED - message: <% task(set_configuration).result %> - - apply_configuration: - with-items: node_uuid in <% $.node_uuids %> - workflow: tripleo.baremetal.v1.manual_cleaning - input: - node_uuid: <% $.node_uuid %> - clean_steps: - - interface: raid - step: delete_configuration - - interface: raid - step: create_configuration - timeout: 1800 # building RAID should be fast than general cleaning - retry_count: 180 - retry_delay: 10 - on-success: send_message - on-error: apply_configuration_failed - publish: - message: <% task().result %> - status: SUCCESS - - apply_configuration_failed: - on-success: send_message - publish: - status: FAILED - message: <% task(apply_configuration).result %> - - send_message: - workflow: tripleo.messaging.v1.send - input: - queue_name: <% $.queue_name %> - type: <% execution().name %> - status: <% $.get('status', 'SUCCESS') %> - message: <% $.get('message', '') %> - execution: <% execution() %> - - - cellv2_discovery: - description: Run cell_v2 host discovery - - input: - - node_uuids - - tags: - - tripleo-common-managed - - tasks: - - cell_v2_discover_hosts: - on-success: name_to_uuids - action: tripleo.baremetal.cell_v2_discover_hosts - - name_to_uuids: - on-success: wait_for_nova_resources - action: ironic.node_get - input: - node_id: <% $.node %> - fields: ['uuid'] - with-items: node in <% $.node_uuids %> - publish: - node_uuids: <% task().result.uuid %> - - wait_for_nova_resources: - with-items: node_uuid in <% $.node_uuids %> - action: nova.hypervisors_find hypervisor_hostname=<% $.node_uuid %> - - clean_nodes: - description: Wipe partition tables on all disks of given nodes - - input: - - node_uuids - - concurrency: 20 - - queue_name: tripleo - - tags: - - tripleo-common-managed - - tasks: - - clean_nodes: - workflow: tripleo.baremetal.v1.manual_cleaning - input: - node_uuid: <% $.node_uuid %> - clean_steps: - - interface: deploy - step: erase_devices_metadata - # Lower timeout, since metadata cleaning takes less time - timeout: 1200 # 20 minutes - retry_delay: 10 - retry_count: 120 - # Let mistral handle concurrency - with-items: node_uuid in <% $.node_uuids %> - concurrency: <% $.concurrency %> - 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() %> - - clean_manageable_nodes: - description: Clean all nodes in a 'manageable' state. - - input: - - concurrency: 20 - - queue_name: tripleo - - tags: - - tripleo-common-managed - - tasks: - - get_manageable_nodes: - action: ironic.node_list - input: - maintenance: false - associated: false - provision_state: manageable - on-success: clean_manageable - on-error: send_message - publish-on-error: - status: FAILED - message: <% task().result %> - publish: - cleaned_nodes: <% task().result.uuid %> - - clean_manageable: - on-success: send_message - workflow: tripleo.baremetal.v1.clean_nodes - input: - node_uuids: <% $.cleaned_nodes %> - concurrency: <% $.concurrency %> - queue_name: <% $.queue_name %> - publish: - status: SUCCESS - - 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: - cleaned_nodes: <% $.get('cleaned_nodes', []) %> - - apply_bios_settings: - description: Apply BIOS settings for given nodes - input: - - node_uuids - - settings - - queue_name: tripleo - - tags: - - tripleo-common-managed - - tasks: - - apply_configuration: - with-items: node_uuid in <% $.node_uuids %> - workflow: tripleo.baremetal.v1.manual_cleaning - input: - node_uuid: <% $.node_uuid %> - clean_steps: - - interface: bios - step: apply_configuration - args: <% $.settings %> - on-complete: send_message - publish-on-error: - status: FAILED - message: <% task().result %> - - send_message: - workflow: tripleo.messaging.v1.send - input: - queue_name: <% $.queue_name %> - type: <% execution().name %> - status: <% $.get('status', 'SUCCESS') %> - message: <% $.get('message', '') %> - execution: <% execution() %> - - apply_bios_settings_on_manageable_nodes: - description: Apply BIOS settings on manageable nodes - input: - - settings - - concurrency: 20 - - queue_name: tripleo - - tags: - - tripleo-common-managed - - tasks: - - get_manageable_nodes: - action: ironic.node_list - input: - maintenance: false - associated: false - provision_state: manageable - on-success: apply_configuration_manageable - on-error: send_message - publish-on-error: - status: FAILED - message: <% task().result %> - publish: - applied_nodes: <% task().result.uuid %> - - apply_configuration_manageable: - workflow: tripleo.baremetal.v1.manual_cleaning - input: - node_uuids: <% $.applied_nodes %> - concurrency: <% $.concurrency %> - clean_steps: - - interface: bios - step: apply_configuration - args: <% $.settings %> - on-complete: send_message - publish-on-error: - status: FAILED - message: <% task().result %> - - 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: - applied_nodes: <% $.get('applied_nodes', []) %> - - reset_bios_settings: - description: Reset BIOS settings for given nodes to factory default - input: - - node_uuids - - queue_name: tripleo - - tags: - - tripleo-common-managed - - tasks: - - factory_reset: - with-items: node_uuid in <% $.node_uuids %> - workflow: tripleo.baremetal.v1.manual_cleaning - input: - node_uuid: <% $.node_uuid %> - clean_steps: - - interface: bios - step: factory_reset - on-complete: send_message - publish-on-error: - status: FAILED - message: <% task().result %> - - send_message: - workflow: tripleo.messaging.v1.send - input: - queue_name: <% $.queue_name %> - type: <% execution().name %> - status: <% $.get('status', 'SUCCESS') %> - message: <% $.get('message', '') %> - execution: <% execution() %> - - reset_bios_settings_on_manageable_nodes: - description: Reset BIOS settings on manageable nodes to factory default - input: - - concurrency: 20 - - queue_name: tripleo - - tags: - - tripleo-common-managed - - tasks: - - get_manageable_nodes: - action: ironic.node_list - input: - maintenance: false - associated: false - provision_state: manageable - on-success: factory_reset_manageable - on-error: send_message - publish-on-error: - status: FAILED - message: <% task().result %> - publish: - reset_nodes: <% task().result.uuid %> - - factory_reset_manageable: - workflow: tripleo.baremetal.v1.manual_cleaning - input: - node_uuids: <% $.reset_nodes %> - concurrency: <% $.concurrency %> - clean_steps: - - interface: bios - step: factory_reset - on-complete: send_message - publish-on-error: - status: FAILED - message: <% task().result %> - - 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: - reset_nodes: <% $.get('reset_nodes', []) %> diff --git a/workbooks/derive_params.yaml b/workbooks/derive_params.yaml deleted file mode 100644 index b6e69a416..000000000 --- a/workbooks/derive_params.yaml +++ /dev/null @@ -1,512 +0,0 @@ ---- -version: '2.0' -name: tripleo.derive_params.v1 -description: TripleO Workflows to derive deployment parameters from the introspected data - -workflows: - - derive_parameters: - description: The main workflow for deriving parameters from the introspected data - - input: - - plan: overcloud - - queue_name: tripleo - - persist_params_in_plan: true - - user_inputs: {} - - tags: - - tripleo-common-managed - - tasks: - get_flattened_parameters: - action: tripleo.parameters.get_flatten container=<% $.plan %> - publish: - environment_parameters: <% task().result.environment_parameters %> - heat_resource_tree: <% task().result.heat_resource_tree %> - on-success: - - get_roles: <% $.environment_parameters and $.heat_resource_tree %> - - set_status_failed_get_flattened_parameters: <% (not $.environment_parameters) or (not $.heat_resource_tree) %> - on-error: set_status_failed_get_flattened_parameters - - get_roles: - action: tripleo.role.list container=<% $.plan %> - publish: - role_name_list: <% task().result %> - on-success: - - get_valid_roles: <% $.role_name_list %> - - set_status_failed_get_roles: <% not $.role_name_list %> - on-error: set_status_failed_on_error_get_roles - - # Obtain only the roles which has count > 0, by checking Count parameter, like ComputeCount - get_valid_roles: - publish: - valid_role_name_list: <% let(hr => $.heat_resource_tree.parameters) -> $.role_name_list.where(int($hr.get(concat($, 'Count'), {}).get('default', 0)) > 0) %> - on-success: - - for_each_role: <% $.valid_role_name_list %> - - set_status_failed_get_valid_roles: <% not $.valid_role_name_list %> - - # Execute the basic preparation workflow for each role to get introspection data - for_each_role: - with-items: role_name in <% $.valid_role_name_list %> - concurrency: 1 - workflow: _derive_parameters_per_role - input: - plan: <% $.plan %> - role_name: <% $.role_name %> - environment_parameters: <% $.environment_parameters %> - heat_resource_tree: <% $.heat_resource_tree %> - user_inputs: <% $.user_inputs %> - publish: - # Gets all the roles derived parameters as dictionary - result: <% task().result.select($.get('derived_parameters', {})).sum() %> - on-success: - - send_message: <% not $.persist_params_in_plan %> - - reset_derive_parameters_in_plan: <% $.persist_params_in_plan %> - on-error: set_status_failed_for_each_role - - reset_derive_parameters_in_plan: - action: tripleo.parameters.reset - input: - container: <% $.plan %> - key: 'derived_parameters' - on-success: - # Add the derived parameters to the deployment plan only when $.result - # (the derived parameters) is non-empty. Otherwise, we're done. - - update_derive_parameters_in_plan: <% $.result %> - - send_message: <% not $.result %> - on-error: set_status_failed_reset_derive_parameters_in_plan - - update_derive_parameters_in_plan: - action: tripleo.parameters.update - input: - container: <% $.plan %> - key: 'derived_parameters' - parameters: <% $.get('result', {}) %> - on-success: send_message - on-error: set_status_failed_update_derive_parameters_in_plan - - set_status_failed_get_flattened_parameters: - on-success: send_message - publish: - status: FAILED - message: <% task(get_flattened_parameters).result %> - - set_status_failed_get_roles: - on-success: send_message - publish: - status: FAILED - message: "Unable to determine the list of roles in the deployment plan" - - set_status_failed_on_error_get_roles: - on-success: send_message - publish: - status: FAILED - message: <% task(get_roles).result %> - - set_status_failed_get_valid_roles: - on-success: send_message - publish: - status: FAILED - message: 'Unable to determine the list of valid roles in the deployment plan.' - - set_status_failed_for_each_role: - on-success: update_message_format - publish: - status: FAILED - # gets the status and message for all roles from task result. - message: <% task(for_each_role).result.select(dict('role_name' => $.role_name, 'status' => $.get('status', 'SUCCESS'), 'message' => $.get('message', ''))) %> - - update_message_format: - on-success: send_message - publish: - # updates the message format(Role 'role name': message) for each roles which are failed and joins the message list as string with ', ' separator. - message: <% $.message.where($.get('status', 'SUCCESS') != 'SUCCESS').select(concat("Role '{}':".format($.role_name), " ", $.get('message', '(error unknown)'))).join(', ') %> - - set_status_failed_reset_derive_parameters_in_plan: - on-success: send_message - publish: - status: FAILED - message: <% task(reset_derive_parameters_in_plan).result %> - - set_status_failed_update_derive_parameters_in_plan: - on-success: send_message - publish: - status: FAILED - message: <% task(update_derive_parameters_in_plan).result %> - - send_message: - workflow: tripleo.messaging.v1.send - input: - queue_name: <% $.queue_name %> - type: <% execution().name %> - status: <% $.get('status', 'SUCCESS') %> - execution: <% execution() %> - message: <% $.get('message', '') %> - plan_name: <% $.plan %> - payload: - result: <% $.get('result', '') %> - - get_flattened_parameters: - description: Workflow to retreive a list of flattened parameters - - input: - - plan: overcloud - - queue_name: tripleo - - output: - flattened_parameters: <% $.flattened_parameters %> - - tags: - - tripleo-common-managed - - tasks: - get_flattened_parameters: - action: tripleo.parameters.get_flatten container=<% $.plan %> - on-success: send_message - publish: - status: SUCCESS - message: <% task().result %> - flattened_parameters: <% task().result %> - publish-on-error: - status: FAILED - message: <% task().result %> - - send_message: - workflow: tripleo.messaging.v1.send - input: - queue_name: <% $.queue_name %> - type: <% execution().name %> - status: <% $.get('status', 'SUCCESS') - execution: <% execution() %> - messages: <% $.get('message', '') %> - payload: - flattened_parameters: <% $.get('flattened_parameters', []) %> - - _derive_parameters_per_role: - description: > - Workflow which runs per role to get the introspection data on the first matching node assigned to role. - Once introspection data is fetched, this worklow will trigger the actual derive parameters workflow - input: - - plan - - role_name - - environment_parameters - - heat_resource_tree - - user_inputs - - output: - derived_parameters: <% $.get('derived_parameters', {}) %> - # Need role_name in output parameter to display the status for all roles in main workflow when any role fails here. - role_name: <% $.role_name %> - - tags: - - tripleo-common-managed - - tasks: - get_role_info: - workflow: _get_role_info - input: - role_name: <% $.role_name %> - heat_resource_tree: <% $.heat_resource_tree %> - publish: - role_features: <% task().result.get('role_features', []) %> - role_services: <% task().result.get('role_services', []) %> - on-success: - # Continue only if there are features associated with this role. Otherwise, we're done. - - get_scheduler_hints: <% $.role_features %> - on-error: set_status_failed_get_role_info - - # Find a node associated with this role. Look for nodes matching any scheduler hints - # associated with the role, and if there are no scheduler hints then locate nodes - # with a profile matching the role's flavor. - get_scheduler_hints: - publish: - scheduler_hints: <% let(param_name => concat($.role_name, 'SchedulerHints')) -> $.heat_resource_tree.parameters.get($param_name, {}).get('default', {}) %> - on-success: - - get_hint_regex: <% $.scheduler_hints %> - # If there are no scheduler hints then move on to use the flavor - - get_flavor_name: <% not $.scheduler_hints %> - - get_hint_regex: - publish: - hint_regex: <% $.scheduler_hints.get('capabilities:node', '').replace('%index%', '(\d+)') %> - on-success: - - get_node_with_hint: <% $.hint_regex %> - # If there is no 'capabilities:node' hint then move on to use the flavor - - get_flavor_name: <% not $.hint_regex %> - - get_node_with_hint: - workflow: tripleo.baremetal.v1.nodes_with_hint - input: - hint_regex: <% concat('^', $.hint_regex, '$') %> - publish: - role_node_uuid: <% task().result.matching_nodes.first('') %> - on-success: - - get_introspection_data: <% $.role_node_uuid %> - # If no nodes match the scheduler hint then move on to use the flavor - - get_flavor_name: <% not $.role_node_uuid %> - on-error: set_status_failed_on_error_get_node_with_hint - - get_flavor_name: - publish: - flavor_name: <% let(param_name => concat('Overcloud', $.role_name, 'Flavor').replace('OvercloudControllerFlavor', 'OvercloudControlFlavor')) -> $.heat_resource_tree.parameters.get($param_name, {}).get('default', '') %> - on-success: - - get_profile_name: <% $.flavor_name %> - - set_status_failed_get_flavor_name: <% not $.flavor_name %> - - get_profile_name: - action: tripleo.parameters.get_profile_of_flavor flavor_name=<% $.flavor_name %> - publish: - profile_name: <% task().result %> - on-success: get_profile_node - on-error: set_status_failed_get_profile_name - - get_profile_node: - workflow: tripleo.baremetal.v1.nodes_with_profile - input: - profile: <% $.profile_name %> - publish: - role_node_uuid: <% task().result.matching_nodes.first('') %> - on-success: - - get_introspection_data: <% $.role_node_uuid %> - - set_status_failed_no_matching_node_get_profile_node: <% not $.role_node_uuid %> - on-error: set_status_failed_on_error_get_profile_node - - get_introspection_data: - action: baremetal_introspection.get_data uuid=<% $.role_node_uuid %> - publish: - hw_data: <% task().result %> - # Establish an empty dictionary of derived_parameters prior to - # invoking the individual "feature" algorithms - derived_parameters: <% dict() %> - on-success: handle_dpdk_feature - on-error: set_status_failed_get_introspection_data - - handle_dpdk_feature: - on-success: - - get_dpdk_derive_params: <% $.role_features.contains('DPDK') %> - - handle_sriov_feature: <% not $.role_features.contains('DPDK') %> - - get_dpdk_derive_params: - workflow: tripleo.derive_params_formulas.v1.dpdk_derive_params - input: - plan: <% $.plan %> - role_name: <% $.role_name %> - heat_resource_tree: <% $.heat_resource_tree %> - hw_data: <% $.hw_data %> - user_inputs: <% $.user_inputs %> - publish: - derived_parameters: <% task().result.get('derived_parameters', {}) %> - on-success: handle_sriov_feature - on-error: set_status_failed_get_dpdk_derive_params - - handle_sriov_feature: - on-success: - - get_sriov_derive_params: <% $.role_features.contains('SRIOV') %> - - handle_host_feature: <% not $.role_features.contains('SRIOV') %> - - get_sriov_derive_params: - workflow: tripleo.derive_params_formulas.v1.sriov_derive_params - input: - role_name: <% $.role_name %> - hw_data: <% $.hw_data %> - derived_parameters: <% $.derived_parameters %> - publish: - derived_parameters: <% task().result.get('derived_parameters', {}) %> - on-success: handle_host_feature - on-error: set_status_failed_get_sriov_derive_params - - handle_host_feature: - on-success: - - get_host_derive_params: <% $.role_features.contains('HOST') %> - - handle_hci_feature: <% not $.role_features.contains('HOST') %> - - get_host_derive_params: - workflow: tripleo.derive_params_formulas.v1.host_derive_params - input: - role_name: <% $.role_name %> - hw_data: <% $.hw_data %> - user_inputs: <% $.user_inputs %> - derived_parameters: <% $.derived_parameters %> - publish: - derived_parameters: <% task().result.get('derived_parameters', {}) %> - on-success: handle_hci_feature - on-error: set_status_failed_get_host_derive_params - - handle_hci_feature: - on-success: - - get_hci_derive_params: <% $.role_features.contains('HCI') %> - - get_hci_derive_params: - workflow: tripleo.derive_params_formulas.v1.hci_derive_params - input: - role_name: <% $.role_name %> - environment_parameters: <% $.environment_parameters %> - heat_resource_tree: <% $.heat_resource_tree %> - introspection_data: <% $.hw_data %> - user_inputs: <% $.user_inputs %> - derived_parameters: <% $.derived_parameters %> - publish: - derived_parameters: <% task().result.get('derived_parameters', {}) %> - on-error: set_status_failed_get_hci_derive_params - # Done (no more derived parameter features) - - set_status_failed_get_role_info: - publish: - role_name: <% $.role_name %> - status: FAILED - message: <% task(get_role_info).result.get('message', '') %> - on-success: fail - - set_status_failed_get_flavor_name: - publish: - role_name: <% $.role_name %> - status: FAILED - message: <% "Unable to determine flavor for role '{0}'".format($.role_name) %> - on-success: fail - - set_status_failed_get_profile_name: - publish: - role_name: <% $.role_name %> - status: FAILED - message: <% task(get_profile_name).result %> - on-success: fail - - set_status_failed_no_matching_node_get_profile_node: - publish: - role_name: <% $.role_name %> - status: FAILED - message: <% "Unable to determine matching node for profile '{0}'".format($.profile_name) %> - on-success: fail - - set_status_failed_on_error_get_profile_node: - publish: - role_name: <% $.role_name %> - status: FAILED - message: <% task(get_profile_node).result %> - on-success: fail - - set_status_failed_on_error_get_node_with_hint: - publish: - role_name: <% $.role_name %> - status: FAILED - message: <% task(get_node_with_hint).result %> - on-success: fail - - set_status_failed_get_introspection_data: - publish: - role_name: <% $.role_name %> - status: FAILED - message: <% task(get_introspection_data).result %> - on-success: fail - - set_status_failed_get_dpdk_derive_params: - publish: - role_name: <% $.role_name %> - status: FAILED - message: <% task(get_dpdk_derive_params).result.message %> - on-success: fail - - set_status_failed_get_sriov_derive_params: - publish: - role_name: <% $.role_name %> - status: FAILED - message: <% task(get_sriov_derive_params).result.message %> - on-success: fail - - set_status_failed_get_host_derive_params: - publish: - role_name: <% $.role_name %> - status: FAILED - message: <% task(get_host_derive_params).result.message %> - on-success: fail - - set_status_failed_get_hci_derive_params: - publish: - role_name: <% $.role_name %> - status: FAILED - message: <% task(get_hci_derive_params).result.message %> - on-success: fail - - - _get_role_info: - description: > - Workflow that determines the list of derived parameter features (DPDK, - HCI, etc.) for a role based on the services assigned to the role. - - input: - - role_name - - heat_resource_tree - - tags: - - tripleo-common-managed - - tasks: - get_resource_chains: - publish: - resource_chains: <% $.heat_resource_tree.resources.values().where($.get('type', '') = 'OS::Heat::ResourceChain') %> - on-success: - - get_role_chain: <% $.resource_chains %> - - set_status_failed_get_resource_chains: <% not $.resource_chains %> - - get_role_chain: - publish: - role_chain: <% let(chain_name => concat($.role_name, 'ServiceChain'))-> $.heat_resource_tree.resources.values().where($.name = $chain_name).first({}) %> - on-success: - - get_service_chain: <% $.role_chain %> - - set_status_failed_get_role_chain: <% not $.role_chain %> - - get_service_chain: - publish: - service_chain: <% let(resources => $.role_chain.resources)-> $.resource_chains.where($resources.contains($.id)).first('') %> - on-success: - - get_role_services: <% $.service_chain %> - - set_status_failed_get_service_chain: <% not $.service_chain %> - - get_role_services: - publish: - role_services: <% let(resources => $.heat_resource_tree.resources)-> $.service_chain.resources.select($resources.get($)) %> - on-success: - - check_features: <% $.role_services %> - - set_status_failed_get_role_services: <% not $.role_services %> - - check_features: - on-success: build_feature_dict - publish: - # The role supports the DPDK feature if the NeutronDatapathType parameter is present - dpdk: <% let(resources => $.heat_resource_tree.resources) -> $.role_services.any($.get('parameters', []).contains('NeutronDatapathType') or $.get('resources', []).select($resources.get($)).any($.get('parameters', []).contains('NeutronDatapathType'))) %> - - # The role supports the SRIOV feature if it includes NeutronSriovAgent services. - sriov: <% $.role_services.any($.get('type', '').endsWith('::NeutronSriovAgent')) %> - - # The role supports the HCI feature if it includes both NovaCompute and CephOSD services. - hci: <% $.role_services.any($.get('type', '').endsWith('::NovaCompute')) and $.role_services.any($.get('type', '').endsWith('::CephOSD')) %> - - build_feature_dict: - on-success: filter_features - publish: - feature_dict: <% dict(DPDK => $.dpdk, SRIOV => $.sriov, HOST => ($.dpdk or $.sriov), HCI => $.hci) %> - - filter_features: - publish: - # The list of features that are enabled (i.e. are true in the feature_dict). - role_features: <% let(feature_dict => $.feature_dict)-> $feature_dict.keys().where($feature_dict[$]) %> - - set_status_failed_get_resource_chains: - publish: - message: <% 'Unable to locate any resource chains in the heat resource tree' %> - on-success: fail - - set_status_failed_get_role_chain: - publish: - message: <% "Unable to determine the service chain resource for role '{0}'".format($.role_name) %> - on-success: fail - - set_status_failed_get_service_chain: - publish: - message: <% "Unable to determine the service chain for role '{0}'".format($.role_name) %> - on-success: fail - - set_status_failed_get_role_services: - publish: - message: <% "Unable to determine list of services for role '{0}'".format($.role_name) %> - on-success: fail diff --git a/workbooks/derive_params_formulas.yaml b/workbooks/derive_params_formulas.yaml deleted file mode 100644 index dff30c13e..000000000 --- a/workbooks/derive_params_formulas.yaml +++ /dev/null @@ -1,836 +0,0 @@ ---- -version: '2.0' -name: tripleo.derive_params_formulas.v1 -description: TripleO Workflows to derive deployment parameters from the introspected data - -workflows: - - - dpdk_derive_params: - description: > - Workflow to derive parameters for DPDK service. - input: - - plan - - role_name - - heat_resource_tree - - hw_data # introspection data - - user_inputs - - derived_parameters: {} - - output: - derived_parameters: <% $.derived_parameters.mergeWith($.get('dpdk_parameters', {})) %> - - tags: - - tripleo-common-managed - - tasks: - get_network_config: - action: tripleo.parameters.get_network_config - input: - container: <% $.plan %> - role_name: <% $.role_name %> - publish: - network_configs: <% task().result.get('network_config', []) %> - on-success: get_dpdk_nics_numa_info - on-error: set_status_failed_get_network_config - - get_dpdk_nics_numa_info: - action: tripleo.derive_params.get_dpdk_nics_numa_info - input: - network_configs: <% $.network_configs %> - inspect_data: <% $.hw_data %> - publish: - dpdk_nics_numa_info: <% task().result %> - on-success: - # TODO: Need to remove condtions here - # adding condition and throw error in action for empty check - - get_dpdk_nics_numa_nodes: <% $.dpdk_nics_numa_info %> - - set_status_failed_get_dpdk_nics_numa_info: <% not $.dpdk_nics_numa_info %> - on-error: set_status_failed_on_error_get_dpdk_nics_numa_info - - get_dpdk_nics_numa_nodes: - publish: - dpdk_nics_numa_nodes: <% $.dpdk_nics_numa_info.groupBy($.numa_node).select($[0]).orderBy($) %> - on-success: - - get_numa_nodes: <% $.dpdk_nics_numa_nodes %> - - set_status_failed_get_dpdk_nics_numa_nodes: <% not $.dpdk_nics_numa_nodes %> - - get_numa_nodes: - publish: - numa_nodes: <% $.hw_data.numa_topology.ram.select($.numa_node).orderBy($) %> - on-success: - - get_num_phy_cores_per_numa_for_pmd: <% $.numa_nodes %> - - set_status_failed_get_numa_nodes: <% not $.numa_nodes %> - - get_num_phy_cores_per_numa_for_pmd: - publish: - num_phy_cores_per_numa_node_for_pmd: <% $.user_inputs.get('num_phy_cores_per_numa_node_for_pmd', 0) %> - on-success: - - get_num_cores_per_numa_nodes: <% isInteger($.num_phy_cores_per_numa_node_for_pmd) and $.num_phy_cores_per_numa_node_for_pmd > 0 %> - - set_status_failed_get_num_phy_cores_per_numa_for_pmd_invalid: <% not isInteger($.num_phy_cores_per_numa_node_for_pmd) %> - - set_status_failed_get_num_phy_cores_per_numa_for_pmd_not_provided: <% $.num_phy_cores_per_numa_node_for_pmd = 0 %> - - # For NUMA node with DPDK nic, number of cores should be used from user input - # For NUMA node without DPDK nic, number of cores should be 1 - get_num_cores_per_numa_nodes: - publish: - num_cores_per_numa_nodes: <% let(dpdk_nics_nodes => $.dpdk_nics_numa_nodes, cores => $.num_phy_cores_per_numa_node_for_pmd) -> $.numa_nodes.select(switch($ in $dpdk_nics_nodes => $cores, not $ in $dpdk_nics_nodes => 1)) %> - on-success: get_pmd_cpus - - get_pmd_cpus: - action: tripleo.derive_params.get_dpdk_core_list - input: - inspect_data: <% $.hw_data %> - numa_nodes_cores_count: <% $.num_cores_per_numa_nodes %> - publish: - pmd_cpus: <% task().result %> - on-success: - - get_pmd_cpus_range_list: <% $.pmd_cpus %> - - set_status_failed_get_pmd_cpus: <% not $.pmd_cpus %> - on-error: set_status_failed_on_error_get_pmd_cpus - - get_pmd_cpus_range_list: - action: tripleo.derive_params.convert_number_to_range_list - input: - num_list: <% $.pmd_cpus %> - publish: - pmd_cpus: <% task().result %> - on-success: get_host_cpus - on-error: set_status_failed_get_pmd_cpus_range_list - - get_host_cpus: - workflow: tripleo.derive_params_formulas.v1.get_host_cpus - input: - role_name: <% $.role_name %> - hw_data: <% $.hw_data %> - publish: - host_cpus: <% task().result.get('host_cpus', '') %> - on-success: get_sock_mem - on-error: set_status_failed_get_host_cpus - - get_sock_mem: - action: tripleo.derive_params.get_dpdk_socket_memory - input: - dpdk_nics_numa_info: <% $.dpdk_nics_numa_info %> - numa_nodes: <% $.numa_nodes %> - overhead: <% $.user_inputs.get('overhead', 800) %> - packet_size_in_buffer: <% 4096*64 %> - publish: - sock_mem: <% task().result %> - on-success: - - get_neutron_bridge_mappings: <% $.sock_mem %> - - set_status_failed_get_sock_mem: <% not $.sock_mem %> - on-error: set_status_failed_on_error_get_sock_mem - - get_neutron_bridge_mappings: - publish: - neutron_bridge_mappings: <% $.heat_resource_tree.parameters.get('NeutronBridgeMappings', {}).get('default', '') %> - on-success: - - get_phy_nw_bridge_mappings: <% $.neutron_bridge_mappings %> - - get_neutron_network_type: <% not $.neutron_bridge_mappings %> - - # Gets the physical network and ovs bridge mappings - get_phy_nw_bridge_mappings: - publish: - phy_nw_bridge_mappings: <% $.neutron_bridge_mappings.split(',').select(let(mapping => $.split(':')) -> dict($mapping[0] => $mapping[1])).sum() %> - on-success: get_bridge_numa_nodes_mappings - - # Gets the ovs bridge and NUMA nodes mappings - get_bridge_numa_nodes_mappings: - publish: - bridge_numa_nodes_mappings: <% $.dpdk_nics_numa_info.groupBy($.bridge_name).select(dict($[0]=>$[1].select($.numa_node).distinct())).sum() %> - on-success: get_phy_nw_numa_nodes_mappings - - # Gets the physical network and NUMA nodes mappings - get_phy_nw_numa_nodes_mappings: - publish: - phy_nw_numa_nodes_mappings: <% let(nw_bridge_mappings => $.phy_nw_bridge_mappings) -> $.bridge_numa_nodes_mappings.items().select(let(br => $[0], nodes => $[1]) -> $nw_bridge_mappings.items().where($[1]=$br).select(dict($[0] => $nodes)).sum()).sum() %> - on-success: get_neutron_network_type - - get_neutron_network_type: - publish: - neutron_network_type: <% $.heat_resource_tree.parameters.get('NeutronNetworkType', {}).get('default', '') %> - on-success: - - get_tunnel_numa_nodes_mappings: <% 'vxlan' in $.neutron_network_type %> - - get_dpdk_parameters: <% not 'vxlan' in $.neutron_network_type %> - - # Gets the list of NUMA nodes associated to all tunneled networks - # OVS-DPDK on VxLAN tunnel requires Tenant Network IP to be applied on the OVS User Bridge itself. - # With this assumption, if the IP is set on the OVS User Bridge, then OVS-DPDK is used for VxLAN tunnels also. - # Here dpdk_nics_numa_info will have the OVS User Bridges with DPDK ports only. - get_tunnel_numa_nodes_mappings: - publish: - tunnel_numa_nodes_mappings: <% $.dpdk_nics_numa_info.where($.addresses.any($.ip_netmask)).select($.numa_node).distinct() %> - on-success: get_dpdk_parameters - - get_dpdk_parameters: - publish: - dpdk_parameters: <% dict(concat($.role_name, 'Parameters') => dict('OvsPmdCoreList' => $.get('pmd_cpus', ''), 'OvsDpdkCoreList' => $.get('host_cpus', ''), 'OvsDpdkSocketMemory' => $.get('sock_mem', ''))) %> - on-success: - - add_phy_nw_numa_nodes_mappings: <% $.get('phy_nw_numa_nodes_mappings', {}) %> - - add_tunnel_numa_nodes_mappings: <% $.get('tunnel_numa_nodes_mappings', []) %> - - add_phy_nw_numa_nodes_mappings: - publish: - dpdk_parameters: <% $.dpdk_parameters.mergeWith(dict(concat($.role_name, 'Parameters') => dict('NeutronPhysnetNUMANodesMapping' => $.get('phy_nw_numa_nodes_mappings', {})))) %> - - add_tunnel_numa_nodes_mappings: - publish: - dpdk_parameters: <% $.dpdk_parameters.mergeWith(dict(concat($.role_name, 'Parameters') => dict('NeutronTunnelNUMANodes' => $.get('tunnel_numa_nodes_mappings', [])))) %> - - set_status_failed_get_network_config: - publish: - status: FAILED - message: <% task(get_network_config).result %> - on-success: fail - - set_status_failed_get_dpdk_nics_numa_info: - publish: - status: FAILED - message: "Unable to determine DPDK NIC's NUMA information" - on-success: fail - - set_status_failed_on_error_get_dpdk_nics_numa_info: - publish: - status: FAILED - message: <% task(get_dpdk_nics_numa_info).result %> - on-success: fail - - set_status_failed_get_dpdk_nics_numa_nodes: - publish: - status: FAILED - message: "Unable to determine DPDK NIC's numa nodes" - on-success: fail - - set_status_failed_get_numa_nodes: - publish: - status: FAILED - message: 'Unable to determine available NUMA nodes' - on-success: fail - - set_status_failed_get_num_phy_cores_per_numa_for_pmd_invalid: - publish: - status: FAILED - message: <% "num_phy_cores_per_numa_node_for_pmd user input '{0}' is invalid".format($.num_phy_cores_per_numa_node_for_pmd) %> - on-success: fail - - set_status_failed_get_num_phy_cores_per_numa_for_pmd_not_provided: - publish: - status: FAILED - message: 'num_phy_cores_per_numa_node_for_pmd user input is not provided' - on-success: fail - - set_status_failed_get_pmd_cpus: - publish: - status: FAILED - message: 'Unable to determine OvsPmdCoreList parameter' - on-success: fail - - set_status_failed_on_error_get_pmd_cpus: - publish: - status: FAILED - message: <% task(get_pmd_cpus).result %> - on-success: fail - - set_status_failed_get_pmd_cpus_range_list: - publish: - status: FAILED - message: <% task(get_pmd_cpus_range_list).result %> - on-success: fail - - set_status_failed_get_host_cpus: - publish: - status: FAILED - message: <% task(get_host_cpus).result.get('message', '') %> - on-success: fail - - set_status_failed_get_sock_mem: - publish: - status: FAILED - message: 'Unable to determine OvsDpdkSocketMemory parameter' - on-success: fail - - set_status_failed_on_error_get_sock_mem: - publish: - status: FAILED - message: <% task(get_sock_mem).result %> - on-success: fail - - - sriov_derive_params: - description: > - This workflow derives parameters for the SRIOV feature. - - input: - - role_name - - hw_data # introspection data - - derived_parameters: {} - - output: - derived_parameters: <% $.derived_parameters.mergeWith($.get('sriov_parameters', {})) %> - - tags: - - tripleo-common-managed - - tasks: - get_host_cpus: - workflow: tripleo.derive_params_formulas.v1.get_host_cpus - input: - role_name: <% $.role_name %> - hw_data: <% $.hw_data %> - publish: - host_cpus: <% task().result.get('host_cpus', '') %> - on-success: get_sriov_parameters - on-error: set_status_failed_get_host_cpus - - get_sriov_parameters: - publish: - # SriovHostCpusList parameter is added temporarily and it's removed later from derived parameters result. - sriov_parameters: <% dict(concat($.role_name, 'Parameters') => dict('SriovHostCpusList' => $.get('host_cpus', ''))) %> - - set_status_failed_get_host_cpus: - publish: - status: FAILED - message: <% task(get_host_cpus).result.get('message', '') %> - on-success: fail - - - get_host_cpus: - description: > - Fetching the host CPU list from the introspection data, and then converting the raw list into a range list. - - input: - - hw_data # introspection data - - output: - host_cpus: <% $.get('host_cpus', '') %> - - tags: - - tripleo-common-managed - - tasks: - get_host_cpus: - action: tripleo.derive_params.get_host_cpus_list inspect_data=<% $.hw_data %> - publish: - host_cpus: <% task().result %> - on-success: - - get_host_cpus_range_list: <% $.host_cpus %> - - set_status_failed_get_host_cpus: <% not $.host_cpus %> - on-error: set_status_failed_on_error_get_host_cpus - - get_host_cpus_range_list: - action: tripleo.derive_params.convert_number_to_range_list - input: - num_list: <% $.host_cpus %> - publish: - host_cpus: <% task().result %> - on-error: set_status_failed_get_host_cpus_range_list - - set_status_failed_get_host_cpus: - publish: - status: FAILED - message: 'Unable to determine host cpus' - on-success: fail - - set_status_failed_on_error_get_host_cpus: - publish: - status: FAILED - message: <% task(get_host_cpus).result %> - on-success: fail - - set_status_failed_get_host_cpus_range_list: - publish: - status: FAILED - message: <% task(get_host_cpus_range_list).result %> - on-success: fail - - - host_derive_params: - description: > - This workflow derives parameters for the Host process, and is mainly associated with CPU pinning and huge memory pages. - This workflow can be dependent on any feature or also can be invoked individually as well. - - input: - - role_name - - hw_data # introspection data - - user_inputs - - derived_parameters: {} - - output: - derived_parameters: <% $.derived_parameters.mergeWith($.get('host_parameters', {})) %> - - tags: - - tripleo-common-managed - - tasks: - get_cpus: - publish: - cpus: <% $.hw_data.numa_topology.cpus %> - on-success: - - get_role_derive_params: <% $.cpus %> - - set_status_failed_get_cpus: <% not $.cpus %> - - get_role_derive_params: - publish: - role_derive_params: <% $.derived_parameters.get(concat($.role_name, 'Parameters'), {}) %> - # removing the role parameters (eg. ComputeParameters) in derived_parameters dictionary since already copied in role_derive_params. - derived_parameters: <% $.derived_parameters.delete(concat($.role_name, 'Parameters')) %> - on-success: get_host_cpus - - get_host_cpus: - publish: - host_cpus: <% $.role_derive_params.get('OvsDpdkCoreList', '') or $.role_derive_params.get('SriovHostCpusList', '') %> - # SriovHostCpusList parameter is added temporarily for host_cpus and not needed in derived_parameters result. - # SriovHostCpusList parameter is deleted in derived_parameters list and adding the updated role parameters - # back in the derived_parameters. - derived_parameters: <% $.derived_parameters + dict(concat($.role_name, 'Parameters') => $.role_derive_params.delete('SriovHostCpusList')) %> - on-success: get_host_dpdk_combined_cpus - - get_host_dpdk_combined_cpus: - publish: - host_dpdk_combined_cpus: <% let(pmd_cpus => $.role_derive_params.get('OvsPmdCoreList', '')) -> switch($pmd_cpus => concat($pmd_cpus, ',', $.host_cpus), not $pmd_cpus => $.host_cpus) %> - reserved_cpus: [] - on-success: - - get_host_dpdk_combined_cpus_num_list: <% $.host_dpdk_combined_cpus %> - - set_status_failed_get_host_dpdk_combined_cpus: <% not $.host_dpdk_combined_cpus %> - - get_host_dpdk_combined_cpus_num_list: - action: tripleo.derive_params.convert_range_to_number_list - input: - range_list: <% $.host_dpdk_combined_cpus %> - publish: - host_dpdk_combined_cpus: <% task().result %> - reserved_cpus: <% task().result.split(',') %> - on-success: get_nova_cpus - on-error: set_status_failed_get_host_dpdk_combined_cpus_num_list - - get_nova_cpus: - publish: - nova_cpus: <% let(reserved_cpus => $.reserved_cpus) -> $.cpus.select($.thread_siblings).flatten().where(not (str($) in $reserved_cpus)).join(',') %> - on-success: - - get_isol_cpus: <% $.nova_cpus %> - - set_status_failed_get_nova_cpus: <% not $.nova_cpus %> - - # concatinates OvsPmdCoreList range format and NovaVcpuPinSet in range format. it may not be in perfect range format. - # example: concatinates '12-15,19' and 16-18' ranges '12-15,19,16-18' - get_isol_cpus: - publish: - isol_cpus: <% let(pmd_cpus => $.role_derive_params.get('OvsPmdCoreList','')) -> switch($pmd_cpus => concat($pmd_cpus, ',', $.nova_cpus), not $pmd_cpus => $.nova_cpus) %> - on-success: get_isol_cpus_num_list - - # Gets the isol_cpus in the number list - # example: '12-15,19,16-18' into '12,13,14,15,16,17,18,19' - get_isol_cpus_num_list: - action: tripleo.derive_params.convert_range_to_number_list - input: - range_list: <% $.isol_cpus %> - publish: - isol_cpus: <% task().result %> - on-success: get_nova_cpus_range_list - on-error: set_status_failed_get_isol_cpus_num_list - - get_nova_cpus_range_list: - action: tripleo.derive_params.convert_number_to_range_list - input: - num_list: <% $.nova_cpus %> - publish: - nova_cpus: <% task().result %> - on-success: get_isol_cpus_range_list - on-error: set_status_failed_get_nova_cpus_range_list - - # converts number format isol_cpus into range format - # example: '12,13,14,15,16,17,18,19' into '12-19' - get_isol_cpus_range_list: - action: tripleo.derive_params.convert_number_to_range_list - input: - num_list: <% $.isol_cpus %> - publish: - isol_cpus: <% task().result %> - on-success: get_host_mem - on-error: set_status_failed_get_isol_cpus_range_list - - get_host_mem: - publish: - host_mem: <% $.user_inputs.get('host_mem_default', 4096) %> - on-success: check_default_hugepage_supported - - check_default_hugepage_supported: - publish: - default_hugepage_supported: <% $.hw_data.get('inventory', {}).get('cpu', {}).get('flags', []).contains('pdpe1gb') %> - on-success: - - get_total_memory: <% $.default_hugepage_supported %> - - set_status_failed_check_default_hugepage_supported: <% not $.default_hugepage_supported %> - - get_total_memory: - publish: - total_memory: <% $.hw_data.get('inventory', {}).get('memory', {}).get('physical_mb', 0) %> - on-success: - - get_hugepage_allocation_percentage: <% $.total_memory %> - - set_status_failed_get_total_memory: <% not $.total_memory %> - - get_hugepage_allocation_percentage: - publish: - huge_page_allocation_percentage: <% $.user_inputs.get('huge_page_allocation_percentage', 0) %> - on-success: - - get_hugepages: <% isInteger($.huge_page_allocation_percentage) and $.huge_page_allocation_percentage > 0 %> - - set_status_failed_get_hugepage_allocation_percentage_invalid: <% not isInteger($.huge_page_allocation_percentage) %> - - set_status_failed_get_hugepage_allocation_percentage_not_provided: <% $.huge_page_allocation_percentage = 0 %> - - get_hugepages: - publish: - hugepages: <% let(huge_page_perc => float($.huge_page_allocation_percentage)/100)-> int((($.total_memory/1024)-4) * $huge_page_perc) %> - on-success: - - get_cpu_model: <% $.hugepages %> - - set_status_failed_get_hugepages: <% not $.hugepages %> - - get_cpu_model: - publish: - intel_cpu_model: <% $.hw_data.get('inventory', {}).get('cpu', {}).get('model_name', '').startsWith('Intel') %> - on-success: get_iommu_info - - get_iommu_info: - publish: - iommu_info: <% switch($.intel_cpu_model => 'intel_iommu=on iommu=pt', not $.intel_cpu_model => '') %> - on-success: get_kernel_args - - get_kernel_args: - publish: - kernel_args: <% concat('default_hugepagesz=1GB hugepagesz=1G ', 'hugepages=', str($.hugepages), ' ', $.iommu_info, ' isolcpus=', $.isol_cpus) %> - on-success: get_host_parameters - - get_host_parameters: - publish: - host_parameters: <% dict(concat($.role_name, 'Parameters') => dict('NovaComputeCpuDedicatedSet' => $.get('nova_cpus', ''), 'NovaComputeCpuSharedSet' => $.get('host_cpus', ''), 'NovaReservedHostMemory' => $.get('host_mem', ''), 'KernelArgs' => $.get('kernel_args', ''), 'IsolCpusList' => $.get('isol_cpus', ''))) %> - - set_status_failed_get_cpus: - publish: - status: FAILED - message: "Unable to determine CPU's on NUMA nodes" - on-success: fail - - set_status_failed_get_host_dpdk_combined_cpus: - publish: - status: FAILED - message: 'Unable to combine host and dpdk cpus list' - on-success: fail - - set_status_failed_get_host_dpdk_combined_cpus_num_list: - publish: - status: FAILED - message: <% task(get_host_dpdk_combined_cpus_num_list).result %> - on-success: fail - - set_status_failed_get_nova_cpus: - publish: - status: FAILED - message: 'Unable to determine nova vcpu pin set' - on-success: fail - - set_status_failed_get_nova_cpus_range_list: - publish: - status: FAILED - message: <% task(get_nova_cpus_range_list).result %> - on-success: fail - - set_status_failed_get_isol_cpus_num_list: - publish: - status: FAILED - message: <% task(get_isol_cpus_num_list).result %> - on-success: fail - - set_status_failed_get_isol_cpus_range_list: - publish: - status: FAILED - message: <% task(get_isol_cpus_range_list).result %> - on-success: fail - - set_status_failed_check_default_hugepage_supported: - publish: - status: FAILED - message: 'default huge page size 1GB is not supported' - on-success: fail - - set_status_failed_get_total_memory: - publish: - status: FAILED - message: 'Unable to determine total memory' - on-success: fail - - set_status_failed_get_hugepage_allocation_percentage_invalid: - publish: - status: FAILED - message: <% "huge_page_allocation_percentage user input '{0}' is invalid".format($.huge_page_allocation_percentage) %> - on-success: fail - - set_status_failed_get_hugepage_allocation_percentage_not_provided: - publish: - status: FAILED - message: 'huge_page_allocation_percentage user input is not provided' - on-success: fail - - set_status_failed_get_hugepages: - publish: - status: FAILED - message: 'Unable to determine huge pages' - on-success: fail - - - hci_derive_params: - description: Derive the deployment parameters for HCI - input: - - role_name - - environment_parameters - - heat_resource_tree - - introspection_data - - user_inputs - - derived_parameters: {} - - output: - derived_parameters: <% $.derived_parameters.mergeWith($.get('hci_parameters', {})) %> - - tags: - - tripleo-common-managed - - tasks: - get_hci_inputs: - publish: - hci_profile: <% $.user_inputs.get('hci_profile', '') %> - hci_profile_config: <% $.user_inputs.get('hci_profile_config', {}) %> - MB_PER_GB: 1024 - on-success: - - get_average_guest_memory_size_in_mb: <% $.hci_profile and $.hci_profile_config.get($.hci_profile, {}) %> - - set_failed_invalid_hci_profile: <% $.hci_profile and not $.hci_profile_config.get($.hci_profile, {}) %> - # When no hci_profile is specified, the workflow terminates without deriving any HCI parameters. - - get_average_guest_memory_size_in_mb: - publish: - average_guest_memory_size_in_mb: <% $.hci_profile_config.get($.hci_profile, {}).get('average_guest_memory_size_in_mb', 0) %> - on-success: - - get_average_guest_cpu_utilization_percentage: <% isInteger($.average_guest_memory_size_in_mb) %> - - set_failed_invalid_average_guest_memory_size_in_mb: <% not isInteger($.average_guest_memory_size_in_mb) %> - - get_average_guest_cpu_utilization_percentage: - publish: - average_guest_cpu_utilization_percentage: <% $.hci_profile_config.get($.hci_profile, {}).get('average_guest_cpu_utilization_percentage', 0) %> - on-success: - - get_gb_overhead_per_guest: <% isInteger($.average_guest_cpu_utilization_percentage) %> - - set_failed_invalid_average_guest_cpu_utilization_percentage: <% not isInteger($.average_guest_cpu_utilization_percentage) %> - - get_gb_overhead_per_guest: - publish: - gb_overhead_per_guest: <% $.user_inputs.get('gb_overhead_per_guest', 0.5) %> - on-success: - - get_gb_per_osd: <% isNumber($.gb_overhead_per_guest) %> - - set_failed_invalid_gb_overhead_per_guest: <% not isNumber($.gb_overhead_per_guest) %> - - get_gb_per_osd: - publish: - gb_per_osd: <% $.user_inputs.get('gb_per_osd', 5) %> - on-success: - - get_cores_per_osd: <% isNumber($.gb_per_osd) %> - - set_failed_invalid_gb_per_osd: <% not isNumber($.gb_per_osd) %> - - get_cores_per_osd: - publish: - cores_per_osd: <% $.user_inputs.get('cores_per_osd', 1.0) %> - on-success: - - get_extra_configs: <% isNumber($.cores_per_osd) %> - - set_failed_invalid_cores_per_osd: <% not isNumber($.cores_per_osd) %> - - get_extra_configs: - publish: - extra_config: <% $.environment_parameters.get('ExtraConfig', {}) %> - role_extra_config: <% $.environment_parameters.get(concat($.role_name, 'ExtraConfig'), {}) %> - role_env_params: <% $.environment_parameters.get(concat($.role_name, 'Parameters'), {}) %> - role_derive_params: <% $.derived_parameters.get(concat($.role_name, 'Parameters'), {}) %> - on-success: calc_osds - - calc_osds: - publish: - num_dev: <% $.heat_resource_tree.parameters.get('CephAnsibleDisksConfig', {}).get('default', {}).get('devices', []).count() %> - num_lvm: <% $.heat_resource_tree.parameters.get('CephAnsibleDisksConfig', {}).get('default', {}).get('lvm_volumes', []).count() %> - on-success: get_num_osds - - get_num_osds: - publish: - num_osds: <% int($.num_dev + $.num_lvm) %> - on-success: - - get_memory_mb: <% $.num_osds %> - # If there's no CephAnsibleDisksConfig then look for OSD configuration in hiera data - - get_num_osds_from_hiera: <% not $.num_osds %> - - get_num_osds_from_hiera: - publish: - num_osds: <% $.role_extra_config.get('ceph::profile::params::osds', $.extra_config.get('ceph::profile::params::osds', {})).keys().count() %> - on-success: - - get_memory_mb: <% $.num_osds %> - - set_failed_no_osds: <% not $.num_osds %> - - get_memory_mb: - publish: - memory_mb: <% $.introspection_data.get('memory_mb', 0) %> - on-success: - - get_nova_vcpu_pin_set: <% $.memory_mb %> - - set_failed_get_memory_mb: <% not $.memory_mb %> - - # Determine the number of CPU cores available to Nova and Ceph. If - # NovaVcpuPinSet is defined then use the number of vCPUs in the set, - # otherwise use all of the cores identified in the introspection data. - - get_nova_vcpu_pin_set: - publish: - # NovaVcpuPinSet can be defined in multiple locations, and it's - # important to select the value in order of precedence: - # - # 1) User specified value for this role - # 2) User specified default value for all roles - # 3) Value derived by another derived parameters workflow - nova_vcpu_pin_set: <% $.role_env_params.get('NovaVcpuPinSet', $.environment_parameters.get('NovaVcpuPinSet', $.role_derive_params.get('NovaVcpuPinSet', ''))) %> - on-success: - - get_nova_vcpu_count: <% $.nova_vcpu_pin_set %> - - get_num_cores: <% not $.nova_vcpu_pin_set %> - - get_nova_vcpu_count: - action: tripleo.derive_params.convert_range_to_number_list - input: - range_list: <% $.nova_vcpu_pin_set %> - publish: - num_cores: <% task().result.split(',').count() %> - on-success: calculate_nova_parameters - on-error: set_failed_get_nova_vcpu_count - - get_num_cores: - publish: - num_cores: <% $.introspection_data.get('cpus', 0) %> - on-success: - - calculate_nova_parameters: <% $.num_cores %> - - set_failed_get_num_cores: <% not $.num_cores %> - - # HCI calculations are broken into multiple steps. This is necessary - # because variables published by a Mistral task are not available - # for use by that same task. Variables computed and published in a task - # are only available in subsequent tasks. - # - # The HCI calculations compute two Nova parameters: - # - reserved_host_memory - # - cpu_allocation_ratio - # - # The reserved_host_memory calculation computes the amount of memory - # that needs to be reserved for Ceph and the total amount of "guest - # overhead" memory that is based on the anticipated number of guests. - # Psuedo-code for the calculation (disregarding MB and GB units) is - # as follows: - # - # ceph_memory = mem_per_osd * num_osds - # nova_memory = total_memory - ceph_memory - # num_guests = nova_memory / - # (average_guest_memory_size + overhead_per_guest) - # reserved_memory = ceph_memory + (num_guests * overhead_per_guest) - # - # The cpu_allocation_ratio calculation is similar in that it takes into - # account the number of cores that must be reserved for Ceph. - # - # ceph_cores = cores_per_osd * num_osds - # guest_cores = num_cores - ceph_cores - # guest_vcpus = guest_cores / average_guest_utilization - # cpu_allocation_ratio = guest_vcpus / num_cores - - calculate_nova_parameters: - publish: - avg_guest_util: <% $.average_guest_cpu_utilization_percentage / 100.0 %> - avg_guest_size_gb: <% $.average_guest_memory_size_in_mb / float($.MB_PER_GB) %> - memory_gb: <% $.memory_mb / float($.MB_PER_GB) %> - ceph_mem_gb: <% $.gb_per_osd * $.num_osds %> - nonceph_cores: <% $.num_cores - int($.cores_per_osd * $.num_osds) %> - on-success: calc_step_2 - - calc_step_2: - publish: - num_guests: <% int(($.memory_gb - $.ceph_mem_gb) / ($.avg_guest_size_gb + $.gb_overhead_per_guest)) %> - guest_vcpus: <% $.nonceph_cores / $.avg_guest_util %> - on-success: calc_step_3 - - calc_step_3: - publish: - reserved_host_memory: <% $.MB_PER_GB * int($.ceph_mem_gb + ($.num_guests * $.gb_overhead_per_guest)) %> - cpu_allocation_ratio: <% $.guest_vcpus / $.num_cores %> - on-success: validate_results - - validate_results: - publish: - # Verify whether HCI is viable: - # - At least 80% of the memory is reserved for Ceph and guest overhead - # - At least half of the CPU cores must be available to Nova - mem_ok: <% $.reserved_host_memory <= ($.memory_mb * 0.8) %> - cpu_ok: <% $.cpu_allocation_ratio >= 0.5 %> - on-success: - - set_failed_insufficient_mem: <% not $.mem_ok %> - - set_failed_insufficient_cpu: <% not $.cpu_ok %> - - publish_hci_parameters: <% $.mem_ok and $.cpu_ok %> - - publish_hci_parameters: - publish: - # TODO(abishop): Update this when the cpu_allocation_ratio can be set - # via a THT parameter (no such parameter currently exists). Until a - # THT parameter exists, use hiera data to set the cpu_allocation_ratio. - hci_parameters: <% dict(concat($.role_name, 'Parameters') => dict('NovaReservedHostMemory' => $.reserved_host_memory)) + dict(concat($.role_name, 'ExtraConfig') => dict('nova::cpu_allocation_ratio' => $.cpu_allocation_ratio)) %> - - set_failed_invalid_hci_profile: - publish: - message: "'<% $.hci_profile %>' is not a valid HCI profile." - on-success: fail - - set_failed_invalid_average_guest_memory_size_in_mb: - publish: - message: "'<% $.average_guest_memory_size_in_mb %>' is not a valid average_guest_memory_size_in_mb value." - on-success: fail - - set_failed_invalid_gb_overhead_per_guest: - publish: - message: "'<% $.gb_overhead_per_guest %>' is not a valid gb_overhead_per_guest value." - on-success: fail - - set_failed_invalid_gb_per_osd: - publish: - message: "'<% $.gb_per_osd %>' is not a valid gb_per_osd value." - on-success: fail - - set_failed_invalid_cores_per_osd: - publish: - message: "'<% $.cores_per_osd %>' is not a valid cores_per_osd value." - on-success: fail - - set_failed_invalid_average_guest_cpu_utilization_percentage: - publish: - message: "'<% $.average_guest_cpu_utilization_percentage %>' is not a valid average_guest_cpu_utilization_percentage value." - on-success: fail - - set_failed_no_osds: - publish: - message: "No Ceph OSDs found in the overcloud definition ('ceph::profile::params::osds')." - on-success: fail - - set_failed_get_memory_mb: - publish: - message: "Unable to determine the amount of physical memory (no 'memory_mb' found in introspection_data)." - on-success: fail - - set_failed_get_nova_vcpu_count: - publish: - message: <% task(get_nova_vcpu_count).result %> - on-success: fail - - set_failed_get_num_cores: - publish: - message: "Unable to determine the number of CPU cores (no 'cpus' found in introspection_data)." - on-success: fail - - set_failed_insufficient_mem: - publish: - message: "<% $.memory_mb %> MB is not enough memory to run hyperconverged." - on-success: fail - - set_failed_insufficient_cpu: - publish: - message: "<% $.num_cores %> CPU cores are not enough to run hyperconverged." - on-success: fail diff --git a/workbooks/messaging.yaml b/workbooks/messaging.yaml deleted file mode 100644 index 70be16cce..000000000 --- a/workbooks/messaging.yaml +++ /dev/null @@ -1,155 +0,0 @@ ---- -version: '2.0' -name: tripleo.messaging.v1 -description: TripleO Zaqar Workflows - -workflows: - - send: - - description: >- - Send a message to a Zaqar queue and optionally persist it to Swift - - This workflow sends a standard message to Zaqar (taking care of the - error handling and retry logic) and optionally persists the message - to Swift. The output of the workflow directly matches the input, this - means it can be used to send a message and set the output of the parent - calling workflow. - - If plan_name is provided the message will be persisted to Swift. In a - container named "{plan_name}-messages". The swift objects will be named: - - {TYPE}/{TIMESTAMP}.yaml - - If a deployment_status is provided, the top-level deployment_status.yaml - will also be updated, which will contain the deployment_status and the - related message. - - The standard message format will be:: - - body: { - type: 'tripleo.workflow.name', # Matches the workflow name - payload: { - status: 'STATUS', # One of RUNNING, SUCCESS, FAILED - root_execution_id: 'UUID of the root execution', - execution_id: 'UUID', - message: "Human readable description", - < Arbitrary data. This should match the workflow output data > - } - } - - Workflow Input: - queue_name - The Zaqar queue name to post to. - type - The message type, this should match the calling workflows name - execution - Details about the workflow execution. Should be passed by using <% execution() %> - status - Optional. The status of the message. SUCCESS/RUNNING/FAILED. - message - Optional. A human readable message to be included - payload - Optional. A dictionary output data to be sent in the message. - plan_name - Optional. The deployment plan name. This is used for the swift messages container. - deployment_status - Optional. If set the top-level deployment_status.yaml will be updated. - - input: - - queue_name - - type - - execution - - status: 'SUCCESS' - - message: null - - payload: {} - - plan_name: null - - deployment_status: null - - - tags: - - tripleo-common-managed - - output: - type: <% $.type %> - payload: <% $.payload %> - - tasks: - - merge_payload: - on-success: - publish: - branch: - # The payload with arbitrary keys is merged with the status, message and execution. - payload: <% {status => $.status, message => $.message, root_execution_id => $.execution.root_execution_id, execution_id => $.execution.id, plan_name => $.plan_name, deployment_status => $.deployment_status} + $.payload %> - next: prepare_messages - - prepare_messages: - on-success: - publish: - branch: - swift_message: <% {type => $.type, payload => $.payload} %> - deployment_status_message: <% {deployment_status => $.deployment_status, workflow_status => {type => $.type, payload => $.payload}} %> - container: <% "{0}-messages".format($.plan_name) %> - next: branch_workflow - - # It should be possible for this to happen in the next section above, but - # there seems to be a Mistral bug... to be confirmed... - branch_workflow: - on-success: - - send_message - - complete_swift: <% not bool($.plan_name) %> - - verify_container_exists: <% bool($.plan_name) %> - - send_message: - action: zaqar.queue_post - retry: - delay: 4 - count: 16 - input: - queue_name: <% $.queue_name %> - messages: - body: <% {type => $.type, payload => $.payload} %> - on-success: check_status - - verify_container_exists: - workflow: tripleo.swift.v1.container_exists container=<% $.container %> - input: - create_container: true - retry: - delay: 4 - count: 16 - on-success: - - wait_for_swift: <% not bool($.deployment_status) %> - - persist_to_swift_plan_latest: <% bool($.deployment_status) %> - - persist_to_swift - - persist_to_swift: - action: swift.put_object - retry: - delay: 4 - count: 16 - input: - container: <% $.container %> - obj: <% "{0}/{1}.yaml".format($.type, now().format("%Y-%m-%d_%H:%M:%S")) %> - contents: <% yaml_dump($.swift_message) %> - on-success: wait_for_swift - - persist_to_swift_plan_latest: - action: swift.put_object - retry: - delay: 4 - count: 16 - input: - container: <% $.container %> - obj: <% "deployment_status.yaml" %> - contents: <% yaml_dump($.deployment_status_message) %> - on-success: wait_for_swift - - wait_for_swift: - # We want persist_to_swift and either persist_to_swift_plan_latest or - # verify_container_exists to join here. Two of the three tasks. - join: 2 - on-success: complete_swift - - complete_swift: - on-success: check_status - - check_status: - # We want both complete_swift and send_message to join here. This means - # that zaqar and swift (if enabled) will all be finished. - join: all - on-complete: - - fail(msg=<% "Workflow failed due to message status. Status:{} Message:{}".format($.get('status'), $.get('message')) %>): <% $.get('status') = "FAILED" %> diff --git a/workbooks/swift.yaml b/workbooks/swift.yaml deleted file mode 100644 index 53735a3e1..000000000 --- a/workbooks/swift.yaml +++ /dev/null @@ -1,79 +0,0 @@ ---- -version: '2.0' -name: tripleo.swift.v1 -description: TripleO Swift Utility Workflows - -workflows: - - container_exists: - - description: >- - Verify if a Swift container exists - - Given the name of a Swift container this workflow will verify if it - already exists. The workflow will ERROR if it doesn't and end in - SUCCESS if it does. - - If create_container: true is passed in, then the container will be - created if it doesn't exist. In this case, if the workflow fails the - container failed to create. - - input: - - container - - headers: {} - - create_container: false - - tags: - - tripleo-common-managed - - tasks: - - # We use the "prefix" input to only list the containers starting with - # the container name we want to find. There is no way to do an exact - # match, but this will greatly reduce the possible number of results. - get_containers: - action: swiftservice.list - input: - options: - prefix: <% $.container %> - publish: - container_exists: <% bool(task().result) and $.container in task().result[0].listing.name %> - create_input: <% $.headers and {"container" => $.container, "headers" => $.headers} or {"container" => $.container} %> - on-success: - - succeed: <% $.container_exists %> - - fail: <% not $.create_container and not $.container_exists %> - - create_container: <% $.create_container and not $.container_exists %> - - create_container: - action: swift.put_container - input: <% $.create_input %> - - object_exists: - - description: > - Verify if a Swift object exists - - Given the name of a Swift container and object this workflow will - verify if it already exists. The workflow will ERROR if it doesn't - and end in SUCCESS if it does. - - - input: - - container - - object - - tags: - - tripleo-common-managed - - tasks: - - get_objects: - action: swift.get_container - input: - container: <% $.container %> - prefix: <% $.object %> - publish: - object_exists: <% bool(task().result) and $.object in task().result[1].select($.name) %> - on-success: - - succeed: <% $.object_exists %> - - fail: <% not $.object_exists %> diff --git a/workbooks/validations.yaml b/workbooks/validations.yaml deleted file mode 100644 index 4a989985d..000000000 --- a/workbooks/validations.yaml +++ /dev/null @@ -1,78 +0,0 @@ ---- -version: '2.0' -name: tripleo.validations.v1 -description: TripleO Validations Workflows v1 - -workflows: - - add_validation_ssh_key_parameter: - input: - - container - - queue_name: tripleo - - tags: - - tripleo-common-managed - - tasks: - test_validations_enabled: - action: tripleo.validations.enabled - on-success: get_pubkey - on-error: unset_validation_key_parameter - - get_pubkey: - action: tripleo.validations.get_pubkey - on-success: set_validation_key_parameter - publish: - pubkey: <% task().result %> - - set_validation_key_parameter: - action: tripleo.parameters.update - input: - parameters: - node_admin_extra_ssh_keys: <% $.pubkey %> - container: <% $.container %> - - # NOTE(shadower): We need to clear keys from a previous deployment - unset_validation_key_parameter: - action: tripleo.parameters.update - input: - parameters: - node_admin_extra_ssh_keys: "" - container: <% $.container %> - - copy_ssh_key: - input: - # FIXME: we should stop using heat-admin as e.g. split-stack - # environments (where Nova didn't create overcloud nodes) don't - # have it present - - overcloud_admin: heat-admin - - queue_name: tripleo - tags: - - tripleo-common-managed - tasks: - get_servers: - action: nova.servers_list - on-success: get_pubkey - publish: - servers: <% task().result._info %> - - get_pubkey: - action: tripleo.validations.get_pubkey - on-success: deploy_ssh_key - publish: - pubkey: <% task().result %> - - deploy_ssh_key: - workflow: tripleo.deployment.v1.deploy_on_server - with-items: server in <% $.servers %> - input: - server_name: <% $.server.name %> - server_uuid: <% $.server.id %> - config: | - #!/bin/bash - if ! grep "<% $.pubkey %>" /home/<% $.overcloud_admin %>/.ssh/authorized_keys; then - echo "<% $.pubkey %>" >> /home/<% $.overcloud_admin %>/.ssh/authorized_keys - fi - config_name: copy_ssh_key - group: script - queue_name: <% $.queue_name %>