diff --git a/examples/create_pbr.yml b/examples/create_pbr.yml new file mode 100644 index 000000000..eb2345f52 --- /dev/null +++ b/examples/create_pbr.yml @@ -0,0 +1,44 @@ +--- +- name: Auto Generated Playbook + hosts: localhost + gather_facts: false + collections: + - nutanix.ncp + tasks: + - name: Setting Variables + set_fact: + ip: "" + username: "" + password: "" + cluster_name: "" + cluster_uuid: "" + priority: "" + vpc_uuid: "" + + - name: create PBR with vpc uuid with any source or destination or protocol with deny action + ntnx_pbrs: + validate_certs: False + state: present + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + priority: "{{ priority }}" + vpc: + uuid: "{{ vpc_uuid }}" + source: + any: True + destination: + any: True + action: + deny: True + protocol: + any: True + register: result + - name: Delete pbrs + ntnx_pbrs: + state: absent + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: false + pbr_uuid: "{{ result.pbr_uuid }}" diff --git a/plugins/module_utils/prism/groups.py b/plugins/module_utils/prism/groups.py index 5b876db59..1b654b90a 100644 --- a/plugins/module_utils/prism/groups.py +++ b/plugins/module_utils/prism/groups.py @@ -12,8 +12,11 @@ def __init__(self, module): resource_type = "/groups" super(Groups, self).__init__(module, resource_type=resource_type) - def get_uuid(self, entity_type, filter): - data = {"entity_type": entity_type, "filter_criteria": filter} + def get_uuid(self, value, key="name", entity_type=""): + data = { + "entity_type": entity_type, + "filter_criteria": "{0}=={1}".format(key, value), + } resp, status = self.list(data, use_base_url=True) if resp.get("group_results"): return resp["group_results"][0]["entity_results"][0]["entity_id"] diff --git a/plugins/module_utils/prism/pbrs.py b/plugins/module_utils/prism/pbrs.py new file mode 100644 index 000000000..3ee7d3603 --- /dev/null +++ b/plugins/module_utils/prism/pbrs.py @@ -0,0 +1,143 @@ +# This file is part of Ansible +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +from copy import deepcopy + +from .prism import Prism +from .vpcs import get_vpc_uuid + + +class Pbr(Prism): + def __init__(self, module): + resource_type = "/routing_policies" + super(Pbr, self).__init__(module, resource_type=resource_type) + self.build_spec_methods = { + "priority": self._build_spec_priority, + # "pbr_uuid": self.build_spec_pbr_uuid, + "vpc": self._build_spec_vpc, + "source": self._build_spec_source, + "destination": self._build_spec_destination, + "protocol": self._build_spec_protocol, + "action": self._build_spec_action, + } + + def _get_default_spec(self): + return deepcopy( + { + "api_version": "3.1.0", + "metadata": {"kind": "routing_policy"}, + "spec": {"resources": {}}, + } + ) + + def _build_spec_priority(self, payload, config): + payload["spec"]["resources"]["priority"] = config + payload["spec"]["name"] = "Policy with priority{0}".format(config) + + return payload, None + + def _build_spec_vpc(self, payload, config): + uuid, error = get_vpc_uuid(config, self.module) + if error: + return None, error + payload["spec"]["resources"]["vpc_reference"] = self._get_vpc_ref(uuid) + return payload, None + + def _get_vpc_ref(self, uuid): + return deepcopy({"kind": "vpc", "uuid": uuid}) + + def _build_spec_source(self, payload, config): + source = {} + if config.get("any"): + source["address_type"] = "ALL" + elif config.get("external"): + source["address_type"] = "INTERNET" + elif config.get("network"): + source["ip_subnet"] = { + "ip": config["network"].get("ip"), + "prefix_length": int(config["network"].get("prefix")), + } + + payload["spec"]["resources"]["source"] = source + + return payload, None + + def _build_spec_destination(self, payload, config): + destination = {} + if config.get("any"): + destination["address_type"] = "ALL" + elif config.get("external"): + destination["address_type"] = "INTERNET" + elif config.get("network"): + destination["ip_subnet"] = { + "ip": config["network"].get("ip"), + "prefix_length": int(config["network"].get("prefix")), + } + + payload["spec"]["resources"]["destination"] = destination + + return payload, None + + def _build_spec_protocol(self, payload, config): + protocol_parameters = {} + if config.get("tcp") or config.get("udp"): + key = "tcp" if config.get("tcp") else "udp" + value = {} + protocol_type = key.upper() + src_port_range_list = [] + if "*" not in config[key]["src"]: + for port in config[key]["src"]: + port = port.split("-") + src_port_range_list.append( + {"start_port": int(port[0]), "end_port": int(port[-1])} + ) + dest_port_range_list = [] + if "*" not in config[key]["dst"]: + for port in config[key]["dst"]: + port = port.split("-") + dest_port_range_list.append( + {"start_port": int(port[0]), "end_port": int(port[-1])} + ) + if src_port_range_list: + value["source_port_range_list"] = src_port_range_list + if dest_port_range_list: + value["destination_port_range_list"] = dest_port_range_list + if value: + protocol_parameters[key] = value + + elif config.get("icmp"): + protocol_type = "ICMP" + if config["icmp"].get("code"): + protocol_parameters["icmp"] = {"icmp_code": config["icmp"]["code"]} + if config["icmp"].get("type"): + protocol_parameters["icmp"]["icmp_type"] = config["icmp"]["type"] + + elif config.get("number"): + protocol_type = "PROTOCOL_NUMBER" + protocol_parameters["protocol_number"] = config["number"] + + else: + protocol_type = "ALL" + + payload["spec"]["resources"]["protocol_type"] = protocol_type + if protocol_parameters: + payload["spec"]["resources"]["protocol_parameters"] = protocol_parameters + + return payload, None + + def _build_spec_action(self, payload, config): + action = {} + if config.get("deny"): + action["action"] = "DENY" # TODO check + elif config.get("reroute"): + action["action"] = "REROUTE" + action["service_ip_list"] = [config.get("reroute")] + elif config.get("allow"): + action["action"] = "PERMIT" + + payload["spec"]["resources"]["action"] = action + + return payload, None diff --git a/plugins/module_utils/prism/virtual_switches.py b/plugins/module_utils/prism/virtual_switches.py index 5c8bac218..7012bf424 100644 --- a/plugins/module_utils/prism/virtual_switches.py +++ b/plugins/module_utils/prism/virtual_switches.py @@ -13,7 +13,7 @@ def get_dvs_uuid(config, module): if "name" in config: groups = Groups(module) name = config["name"] - uuid = groups.get_uuid("distributed_virtual_switch", "name=={0}".format(name)) + uuid = groups.get_uuid(value=name, entity_type="distributed_virtual_switch") if not uuid: error = "Virtual Switch {0} not found.".format(name) return None, error diff --git a/plugins/module_utils/prism/vms.py b/plugins/module_utils/prism/vms.py index aeacc1a3d..84e1d9c87 100644 --- a/plugins/module_utils/prism/vms.py +++ b/plugins/module_utils/prism/vms.py @@ -205,8 +205,9 @@ def _build_spec_disks(self, payload, vdisks): groups = Groups(self.module) name = vdisk["storage_container"]["name"] uuid = groups.get_uuid( + value=name, + key="container_name", entity_type="storage_container", - filter="container_name=={0}".format(name), ) if not uuid: error = "Storage container {0} not found.".format(name) diff --git a/plugins/modules/ntnx_pbrs.py b/plugins/modules/ntnx_pbrs.py new file mode 100644 index 000000000..d84c9417e --- /dev/null +++ b/plugins/modules/ntnx_pbrs.py @@ -0,0 +1,571 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: (c) 2021, Prem Karat +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) +from __future__ import absolute_import, division, print_function + +__metaclass__ = type + +DOCUMENTATION = r""" +--- +module: ntnx_pbrs +short_description: pbr module which suports pbr CRUD operations +version_added: 1.0.0 +description: 'Create, Update, Delete, Power-on, Power-off Nutanix pbr''s' +options: + nutanix_host: + description: + - PC hostname or IP address + type: str + required: true + nutanix_port: + description: + - PC port + type: str + default: 9440 + required: false + nutanix_username: + description: + - PC username + type: str + required: true + nutanix_password: + description: + - PC password; + required: true + type: str + validate_certs: + description: + - Set value to C(False) to skip validation for self signed certificates + - This is not recommended for production setup + type: bool + default: true + state: + description: + - Specify state of Virtual Machine + - If C(state) is set to C(present) the pbr is created. + - >- + If C(state) is set to C(absent) and the pbr exists in the cluster, pbr + with specified name is removed. + choices: + - present + - absent + type: str + default: present + wait: + description: This is the wait description. + type: bool + required: false + default: true + priority: + description: The policy priority number + type: int + pbr_uuid: + description: PBR UUID + type: str + vpc: + description: + - Virtual Private Clouds + type: dict + suboptions: + name: + description: + - VPC Name + - Mutually exclusive with (uuid) + type: str + uuid: + description: + - VPC UUID + - Mutually exclusive with (name) + type: str + source: + description: Where the traffic came from + type: dict + suboptions: + any: + description: From any source + type: bool + external: + description: External Network + type: bool + network: + description: specfic network address + type: dict + suboptions: + ip: + description: Subnet ip address + type: str + prefix: + description: ip address prefix length + type: str + destination: + type: dict + description: Where the traffic going to + suboptions: + any: + description: From any destination + type: bool + external: + description: External Network + type: bool + network: + description: specfic network address + type: dict + suboptions: + ip: + description: Subnet ip address + type: str + prefix: + description: ip address prefix length + type: str + protocol: + type: dict + description: The Network Protocol that will used + suboptions: + any: + description: any protcol number + type: bool + tcp: + description: The Transmission Control will be used + type: dict + suboptions: + src: + default: '*' + type: list + elements: str + description: Where the traffic came from + dst: + default: '*' + type: list + elements: str + description: Where the traffic going to + udp: + description: User datagram protocol will be used + type: dict + suboptions: + src: + default: '*' + type: list + elements: str + description: Where the traffic came from + dst: + default: '*' + type: list + elements: str + description: Where the traffic going to + number: + type: int + description: The internet protocol number + icmp: + description: Internet Control Message Protocol will be used + type: dict + suboptions: + code: + type: int + description: ICMP code + type: + description: ICMP type + type: int + action: + type: dict + description: The behavior on the request + suboptions: + deny: + type: bool + description: Drop the request + allow: + type: bool + description: Accept the request + reroute: + type: str + description: Change the request route +author: + - Prem Karat (@premkarat) + - Gevorg Khachatryan (@Gevorg-Khachatryan-97) + - Alaa Bishtawi (@alaa-bish) + - Dina AbuHijleh (@dina-abuhijleh) +""" + +EXAMPLES = r""" + +- name: create PBR with vpc name with any source or destination or protocol with deny action + ntnx_pbrs: + validate_certs: False + state: present + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + priority: "{{ priority.0 }}" + vpc: + name: "{{ vpc.name }}" + source: + any: True + destination: + any: True + action: + deny: True + protocol: + any: True + +- name: create PBR with vpc uuid with source Any and destination external and allow action with protocol number + ntnx_pbrs: + validate_certs: False + state: present + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + priority: "{{ priority.1 }}" + vpc: + uuid: "{{ vpc.uuid }}" + source: + any: True + destination: + external: True + action: + allow: True + protocol: + number: "{{protocol.number}}" + +- name: create PBR with vpc name with source external and destination network with reroute action and tcp port rangelist + ntnx_pbrs: + validate_certs: False + state: present + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + priority: "{{ priority.2 }}" + vpc: + name: "{{ vpc.name }}" + source: + external: True + destination: + network: + ip: "{{ network.ip }}" + prefix: "{{ network.prefix }}" + action: + reroute: "{{reroute_ip}}" + protocol: + tcp: + src: "{{tcp.port}}" + dst: "{{tcp.port_rangelist}}" + +- name: create PBR with vpc name with source network and destination external with reroute action and udp port rangelist + ntnx_pbrs: + validate_certs: False + state: present + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + priority: "{{ priority.3 }}" + vpc: + name: "{{ vpc.name }}" + source: + network: + ip: "{{ network.ip }}" + prefix: "{{ network.prefix }}" + destination: + any: True + action: + reroute: "{{reroute_ip}}" + protocol: + udp: + src: "{{udp.port_rangelist}}" + dst: "{{udp.port}}" + +- name: create PBR with vpc name with source network and destination external with reroute action and icmp + ntnx_pbrs: + validate_certs: False + state: present + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + priority: "{{ priority.5 }}" + vpc: + name: "{{ vpc.name }}" + source: + network: + ip: "{{ network.ip }}" + prefix: "{{ network.prefix }}" + destination: + external: True + action: + reroute: "{{reroute_ip}}" + protocol: + icmp: + code: "{{icmp.code}}" + type: "{{icmp.type}}" + +- name: Delete all Created pbrs + ntnx_pbrs: + state: absent + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: false + pbr_uuid: "{{ item }}" +""" + +RETURN = r""" +api_version: + description: API Version of the Nutanix v3 API framework. + returned: always + type: str + sample: "3.1" +metadata: + description: The PBR metadata + returned: always + type: dict + sample: { + "api_version": "3.1", + "metadata": { + "categories": {}, + "categories_mapping": {}, + "creation_time": "2022-02-17T08:29:31Z", + "kind": "routing_policy", + "last_update_time": "2022-02-17T08:29:33Z", + "owner_reference": { + "kind": "user", + "name": "admin", + "uuid": "00000000-0000-0000-0000-000000000000" + }, + "spec_version": 0, + "uuid": "64c5a93d-7cd4-45f9-81e9-e0b08d35077a" + } +} +spec: + description: An intentful representation of a PRB spec + returned: always + type: dict + sample: { + "name": "Policy with priority205", + "resources": { + "action": { + "action": "DENY" + }, + "destination": { + "address_type": "ALL" + }, + "priority": 205, + "protocol_type": "ALL", + "source": { + "address_type": "ALL" + }, + "vpc_reference": { + "kind": "vpc", + "uuid": "ebf8130e-09b8-48d9-a9d3-5ef29983f5fe" + } + } + } +status: + description: An intentful representation of a PBR status + returned: always + type: dict + sample: { + "execution_context": { + "task_uuid": [ + "f83bbb29-3ca8-42c2-b29b-4fca4a7a25c3" + ] + }, + "name": "Policy with priority205", + "resources": { + "action": { + "action": "DENY" + }, + "destination": { + "address_type": "ALL" + }, + "priority": 205, + "protocol_type": "ALL", + "routing_policy_counters": { + "byte_count": 0, + "packet_count": 0 + }, + "source": { + "address_type": "ALL" + }, + "vpc_reference": { + "kind": "vpc", + "name": "ET_pbr", + "uuid": "ebf8130e-09b8-48d9-a9d3-5ef29983f5fe" + } + }, + "state": "COMPLETE" + } +pbr_uuid: + description: The created VPC uuid + returned: always + type: str + sample: "64c5a93d-7cd4-45f9-81e9-e0b08d35077a" +task_uuid: + description: The task uuid for the creation + returned: always + type: str + sample: "f83bbb29-3ca8-42c2-b29b-4fca4a7a25c3" +""" + +from ..module_utils.base_module import BaseModule # noqa: E402 +from ..module_utils.prism.pbrs import Pbr # noqa: E402 +from ..module_utils.prism.tasks import Task # noqa: E402 +from ..module_utils.utils import remove_param_with_none_value # noqa: E402 + + +def get_module_spec(): + mutually_exclusive = [("name", "uuid")] + + entity_by_spec = dict(name=dict(type="str"), uuid=dict(type="str")) + + network_spec = dict(ip=dict(type="str"), prefix=dict(type="str")) + + route_spec = dict( + any=dict(type="bool"), + external=dict(type="bool"), + network=dict(type="dict", options=network_spec), + ) + + tcp_and_udp_spec = dict( + src=dict(type="list", default=["*"], elements="str"), + dst=dict(type="list", default=["*"], elements="str"), + ) + + icmp_spec = dict(code=dict(type="int"), type=dict(type="int")) + + protocol_spec = dict( + any=dict(type="bool"), + tcp=dict(type="dict", options=tcp_and_udp_spec), + udp=dict(type="dict", options=tcp_and_udp_spec), + number=dict(type="int"), + icmp=dict(type="dict", options=icmp_spec), + ) + + action_spec = dict( + deny=dict(type="bool"), allow=dict(type="bool"), reroute=dict(type="str") + ) + + module_args = dict( + priority=dict(type="int"), + pbr_uuid=dict(type="str"), + vpc=dict( + type="dict", options=entity_by_spec, mutually_exclusive=mutually_exclusive + ), + source=dict( + type="dict", + options=route_spec, + mutually_exclusive=[("any", "external", "network")], + ), + destination=dict( + type="dict", + options=route_spec, + mutually_exclusive=[("any", "external", "network")], + ), + protocol=dict( + type="dict", + options=protocol_spec, + apply_defaults=True, + mutually_exclusive=[("any", "tcp", "udp", "number", "icmp")], + ), + action=dict( + type="dict", + options=action_spec, + mutually_exclusive=[("deny", "allow", "reroute")], + ), + ) + + return module_args + + +def create_pbr(module, result): + pbr = Pbr(module) + spec, error = pbr.get_spec() + if error: + result["error"] = error + module.fail_json(msg="Failed generating pbr Spec", **result) + + if module.check_mode: + result["response"] = spec + return + + resp, status = pbr.create(spec) + if status["error"]: + result["error"] = status["error"] + result["response"] = resp + module.fail_json(msg="Failed creating pbr", **result) + + pbr_uuid = resp["metadata"]["uuid"] + result["changed"] = True + result["response"] = resp + result["pbr_uuid"] = pbr_uuid + result["task_uuid"] = resp["status"]["execution_context"]["task_uuid"] + + if module.params.get("wait"): + wait_for_task_completion(module, result) + resp, tmp = pbr.read(pbr_uuid) + result["response"] = resp + + +def delete_pbr(module, result): + pbr_uuid = module.params["pbr_uuid"] + if not pbr_uuid: + result["error"] = "Missing parameter pbr_uuid in playbook" + module.fail_json(msg="Failed deleting pbr", **result) + + pbr = Pbr(module) + resp, status = pbr.delete(pbr_uuid) + if status["error"]: + result["error"] = status["error"] + result["response"] = resp + module.fail_json(msg="Failed deleting pbr", **result) + + result["changed"] = True + result["response"] = resp + result["pbr_uuid"] = pbr_uuid + result["task_uuid"] = resp["status"]["execution_context"]["task_uuid"] + + if module.params.get("wait"): + wait_for_task_completion(module, result) + + +def wait_for_task_completion(module, result): + task = Task(module) + task_uuid = result["task_uuid"] + resp, status = task.wait_for_completion(task_uuid) + result["response"] = resp + if status["error"]: + result["error"] = status["error"] + result["response"] = resp + module.fail_json(msg="Failed creating pbr", **result) + + +def run_module(): + module = BaseModule( + argument_spec=get_module_spec(), + mutually_exclusive=[("priority", "pbr_uuid")], + required_if=[ + ("state", "present", ("priority", "action", "source", "destination")), + ("state", "absent", ("pbr_uuid",)), + ], + supports_check_mode=True, + ) + remove_param_with_none_value(module.params) + result = { + "changed": False, + "error": None, + "response": None, + "pbr_uuid": None, + "task_uuid": None, + } + state = module.params["state"] + if state == "present": + create_pbr(module, result) + elif state == "absent": + delete_pbr(module, result) + + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == "__main__": + main() diff --git a/tests/integration/targets/nutanix_pbrs/tasks/create_pbrs.yml b/tests/integration/targets/nutanix_pbrs/tasks/create_pbrs.yml new file mode 100644 index 000000000..e2b58b3bf --- /dev/null +++ b/tests/integration/targets/nutanix_pbrs/tasks/create_pbrs.yml @@ -0,0 +1,183 @@ +- name: create PBR with vpc name with any source or destination or protocol with deny action + ntnx_pbrs: + validate_certs: False + state: present + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + priority: "{{ priority.0 }}" + vpc: + name: "{{ vpc.name }}" + source: + any: True + destination: + any: True + action: + deny: True + protocol: + any: True + register: result + ignore_errors: True + +- name: Creation Status + assert: + that: + - result.response is defined + - result.response.status.state == 'COMPLETE' + fail_msg: " Unable to create PBR with vpc name with any source or destination or protocol with deny action " + success_msg: " PBR with vpc name with any source or destination or protocol with deny action created successfully " + +- set_fact: + todelete: "{{ todelete + [ result.pbr_uuid ] }}" + +- name: create PBR with vpc uuid with source Any and destination external and allow action with protocol number + ntnx_pbrs: + validate_certs: False + state: present + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + priority: "{{ priority.1 }}" + vpc: + uuid: "{{ vpc.uuid }}" + source: + any: True + destination: + external: True + action: + allow: True + protocol: + number: "{{protocol.number}}" + register: result + ignore_errors: True + +- name: Creation Status + assert: + that: + - result.response is defined + - result.response.status.state == 'COMPLETE' + fail_msg: " Unable to create PBR with vpc uuid with source Any and destination external and allow action with protocol number " + success_msg: " PBR with vpc uuid with source Any and destination external and allow action with protocol number created successfully " + +- set_fact: + todelete: "{{ todelete + [ result.pbr_uuid ] }}" + +- name: create PBR with vpc name with source external and destination network with reroute action and tcp port rangelist + ntnx_pbrs: + validate_certs: False + state: present + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + priority: "{{ priority.2 }}" + vpc: + name: "{{ vpc.name }}" + source: + external: True + destination: + network: + ip: "{{ network.ip }}" + prefix: "{{ network.prefix }}" + action: + reroute: "{{reroute_ip}}" + protocol: + tcp: + src: "{{tcp.port}}" + dst: "{{tcp.port_rangelist}}" + register: result + ignore_errors: True + +- name: Creation Status + assert: + that: + - result.response is defined + - result.response.status.state == 'COMPLETE' + fail_msg: " Unable to create PBR with vpc name with source external and destination network with reroute action and tcp port rangelist " + success_msg: " PBR with vpc name with source external and destination network with reroute action and tcp port rangelist created successfully " + +- set_fact: + todelete: "{{ todelete + [ result.pbr_uuid ] }}" + +- name: create PBR with vpc name with source network and destination external with reroute action and udp port rangelist + ntnx_pbrs: + validate_certs: False + state: present + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + priority: "{{ priority.3 }}" + vpc: + name: "{{ vpc.name }}" + source: + network: + ip: "{{ network.ip }}" + prefix: "{{ network.prefix }}" + destination: + any: True + action: + reroute: "{{reroute_ip}}" + protocol: + udp: + src: "{{udp.port_rangelist}}" + dst: "{{udp.port}}" + register: result + ignore_errors: True + +- name: Creation Status + assert: + that: + - result.response is defined + - result.response.status.state == 'COMPLETE' + fail_msg: " Unable to create PBR with vpc name with source network and destination external with reroute action and udp port rangelist" + success_msg: " PBR with vpc name with source network and destination external with reroute action and udp port rangelist created successfully " + +- set_fact: + todelete: "{{ todelete + [ result.pbr_uuid ] }}" + +- name: create PBR with vpc name with source network and destination external with reroute action and icmp + ntnx_pbrs: + validate_certs: False + state: present + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + priority: "{{ priority.5 }}" + vpc: + name: "{{ vpc.name }}" + source: + network: + ip: "{{ network.ip }}" + prefix: "{{ network.prefix }}" + destination: + external: True + action: + reroute: "{{reroute_ip}}" + protocol: + icmp: + code: "{{icmp.code}}" + type: "{{icmp.type}}" + register: result + ignore_errors: True + +- name: Creation Status + assert: + that: + - result.response is defined + - result.response.status.state == 'COMPLETE' + fail_msg: " Unable to create PBR with vpc name with source network and destination external with reroute action and udp port rangelist" + success_msg: " PBR with vpc name with source network and destination external with reroute action and udp port rangelist created successfully " + +- set_fact: + todelete: "{{ todelete + [ result.pbr_uuid ] }}" + +- name: Delete all Created pbrs + ntnx_pbrs: + state: absent + nutanix_host: "{{ ip }}" + nutanix_username: "{{ username }}" + nutanix_password: "{{ password }}" + validate_certs: false + pbr_uuid: "{{ item }}" + register: result + loop: "{{ todelete }}" + ignore_errors: True diff --git a/tests/integration/targets/nutanix_pbrs/tasks/main.yml b/tests/integration/targets/nutanix_pbrs/tasks/main.yml new file mode 100644 index 000000000..1dde923c3 --- /dev/null +++ b/tests/integration/targets/nutanix_pbrs/tasks/main.yml @@ -0,0 +1,3 @@ +- block: + - import_tasks: "create_pbrs.yml" + diff --git a/tests/integration/targets/nutanix_pbrs/vars/main.yml b/tests/integration/targets/nutanix_pbrs/vars/main.yml new file mode 100644 index 000000000..2299ec17e --- /dev/null +++ b/tests/integration/targets/nutanix_pbrs/vars/main.yml @@ -0,0 +1,27 @@ +--- +ip: 10.44.76.88 +username: admin +password: Nutanix.123 +priority: [205, 206, 207, 208, 209, 210] +vpc: + name: ET_pbr + uuid: ebf8130e-09b8-48d9-a9d3-5ef29983f5fe +external_subnet: + subnet_name: ET_2 + subnet_uuiid: ebf8130e- 09b8-48d9-a9d3-5ef29983f5fe +network: + ip: 192.168.2.0 + prefix: 24 +todelete: [] +protocol: + number: 80 +reroute_ip: 10.1.3.2 +tcp: + port: 80 + port_rangelist: 100-120 +udp: + port: 69 + port_rangelist: 150-170 +icmp: + code: 3 + type: 3