From 588ccf60acf0ad084f23626ee34a22c03c80cd81 Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Tue, 15 Feb 2022 20:53:11 +0400 Subject: [PATCH 01/16] #99 PBRs module --- plugins/module_utils/prism/pbrs.py | 154 ++++++++++++++++++ plugins/modules/ntnx_pbrs.py | 247 +++++++++++++++++++++++++++++ 2 files changed, 401 insertions(+) create mode 100644 plugins/module_utils/prism/pbrs.py create mode 100644 plugins/modules/ntnx_pbrs.py diff --git a/plugins/module_utils/prism/pbrs.py b/plugins/module_utils/prism/pbrs.py new file mode 100644 index 000000000..f93446eed --- /dev/null +++ b/plugins/module_utils/prism/pbrs.py @@ -0,0 +1,154 @@ +# 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 + +import os +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": 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": config["network"].get("prefix")} + + payload["spec"]["resources"]["destination"] = destination + + return payload, None + + def _build_spec_protocol(self, payload, config): + protocol_type = None + protocol_parameters = {} + if config.get("tcp"): + protocol_type = "TCP" + src_port_range_list = [] + if "*" not in config["tcp"]["src"]: + for port in config["tcp"]["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["tcp"]["dst"]: + for port in config["tcp"]["dst"]: + port = port.split("-") + dest_port_range_list.append({"start_port": int(port[0]), "end_port": int(port[-1])}) + if src_port_range_list: + protocol_parameters["tcp"]["source_port_range_list"] = src_port_range_list + if dest_port_range_list: + protocol_parameters["tcp"]["destination_port_range_list"] = dest_port_range_list + + elif config.get("udp"): + protocol_type = "UDP" + src_port_range_list = [] + if "*" not in config["udp"]["src"]: + for port in config["udp"]["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["udp"]["dst"]: + for port in config["udp"]["dst"]: + port = port.split("-") + dest_port_range_list.append({"start_port": int(port[0]), "end_port": int(port[-1])}) + if src_port_range_list: + protocol_parameters["udp"]["source_port_range_list"] = src_port_range_list + if dest_port_range_list: + protocol_parameters["udp"]["destination_port_range_list"] = dest_port_range_list + + 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"] + + elif config.get("any"): + 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("allow"): + action["action"] = "PERMIT" + if config.get("deny"): + action["action"] = "DENY" # TODO check + if config.get("reroute"): + action["action"] = "REROUTE" + action["service_ip_list"] = [config.get("reroute")] + + payload["spec"]["resources"]["action"] = action + + return payload, None diff --git a/plugins/modules/ntnx_pbrs.py b/plugins/modules/ntnx_pbrs.py new file mode 100644 index 000000000..0bc7903bd --- /dev/null +++ b/plugins/modules/ntnx_pbrs.py @@ -0,0 +1,247 @@ +#!/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 + #TODO here should be additional arguments documentation +""" + +EXAMPLES = r""" +# TODO +""" + +RETURN = r""" +# TODO +""" + +from ..module_utils.base_module import BaseModule # noqa: E402 +from ..module_utils.prism.tasks import Task # noqa: E402 +from ..module_utils.prism.pbrs import Pbr # 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(), + prefix=dict() + ) + + route_spec = dict( + any=dict(type="bool", default=True), + external=dict(type="bool"), + network=dict(type="dict", + options=network_spec, + ), + ) + + tcp_and_udp_spec = dict( + src=dict(type="list", default=["*"]), + dst=dict(type="list", default=["*"]) + ) + + icmp_spec = dict( + code=dict(type="int"), + type=dict(type="int") + ) + + protocol_spec = dict( + any=dict(type="bool", default=True), + 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="object", + options=icmp_spec), + ) + + action_spec = dict( + deny=dict(type="bool"), + allow=dict(type="bool", default=True), + reroute=dict(type="str"), + ) + + module_args = dict( + priority=dict(type="int", required=True), + + pbr_uuid=dict(type="str"), + + vpc=dict(type="dict", + options=entity_by_spec, + mutually_exclusive=mutually_exclusive), + + source=dict(type="dict", + options=route_spec, + apply_defaults=True, + mutually_exclusive=[("any", "external", "network")]), + + destination=dict(type="dict", + options=route_spec, + apply_defaults=True, + 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, + apply_defaults=True, + 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(), + 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() From fb76bea1d8c0866ce9a26bea22fcbd64224f8129 Mon Sep 17 00:00:00 2001 From: alaa-bish Date: Wed, 16 Feb 2022 07:41:34 +0000 Subject: [PATCH 02/16] fix sanity and add doc: Gihub#101 --- plugins/module_utils/prism/pbrs.py | 49 ++++-- plugins/modules/ntnx_pbrs.py | 229 ++++++++++++++++++++++------- 2 files changed, 210 insertions(+), 68 deletions(-) diff --git a/plugins/module_utils/prism/pbrs.py b/plugins/module_utils/prism/pbrs.py index f93446eed..c13df9a64 100644 --- a/plugins/module_utils/prism/pbrs.py +++ b/plugins/module_utils/prism/pbrs.py @@ -22,7 +22,7 @@ def __init__(self, module): "source": self._build_spec_source, "destination": self._build_spec_destination, "protocol": self._build_spec_protocol, - "action": self._build_spec_action + "action": self._build_spec_action, } def _get_default_spec(self): @@ -31,8 +31,7 @@ def _get_default_spec(self): "api_version": "3.1.0", "metadata": {"kind": "routing_policy"}, "spec": { - "resources": { - }, + "resources": {}, }, } ) @@ -60,8 +59,10 @@ def _build_spec_source(self, payload, config): elif config.get("external"): source["address_type"] = "INTERNET" elif config.get("network"): - source["ip_subnet"] = {"ip": config["network"].get("ip"), - "prefix_length": config["network"].get("prefix")} + source["ip_subnet"] = { + "ip": config["network"].get("ip"), + "prefix_length": config["network"].get("prefix"), + } payload["spec"]["resources"]["source"] = source @@ -74,8 +75,10 @@ def _build_spec_destination(self, payload, config): elif config.get("external"): destination["address_type"] = "INTERNET" elif config.get("network"): - destination["ip_subnet"] = {"ip": config["network"].get("ip"), - "prefix_length": config["network"].get("prefix")} + destination["ip_subnet"] = { + "ip": config["network"].get("ip"), + "prefix_length": config["network"].get("prefix"), + } payload["spec"]["resources"]["destination"] = destination @@ -90,16 +93,24 @@ def _build_spec_protocol(self, payload, config): if "*" not in config["tcp"]["src"]: for port in config["tcp"]["src"]: port = port.split("-") - src_port_range_list.append({"start_port": int(port[0]), "end_port": int(port[-1])}) + src_port_range_list.append( + {"start_port": int(port[0]), "end_port": int(port[-1])} + ) dest_port_range_list = [] if "*" not in config["tcp"]["dst"]: for port in config["tcp"]["dst"]: port = port.split("-") - dest_port_range_list.append({"start_port": int(port[0]), "end_port": int(port[-1])}) + dest_port_range_list.append( + {"start_port": int(port[0]), "end_port": int(port[-1])} + ) if src_port_range_list: - protocol_parameters["tcp"]["source_port_range_list"] = src_port_range_list + protocol_parameters["tcp"][ + "source_port_range_list" + ] = src_port_range_list if dest_port_range_list: - protocol_parameters["tcp"]["destination_port_range_list"] = dest_port_range_list + protocol_parameters["tcp"][ + "destination_port_range_list" + ] = dest_port_range_list elif config.get("udp"): protocol_type = "UDP" @@ -107,16 +118,24 @@ def _build_spec_protocol(self, payload, config): if "*" not in config["udp"]["src"]: for port in config["udp"]["src"]: port = port.split("-") - src_port_range_list.append({"start_port": int(port[0]), "end_port": int(port[-1])}) + src_port_range_list.append( + {"start_port": int(port[0]), "end_port": int(port[-1])} + ) dest_port_range_list = [] if "*" not in config["udp"]["dst"]: for port in config["udp"]["dst"]: port = port.split("-") - dest_port_range_list.append({"start_port": int(port[0]), "end_port": int(port[-1])}) + dest_port_range_list.append( + {"start_port": int(port[0]), "end_port": int(port[-1])} + ) if src_port_range_list: - protocol_parameters["udp"]["source_port_range_list"] = src_port_range_list + protocol_parameters["udp"][ + "source_port_range_list" + ] = src_port_range_list if dest_port_range_list: - protocol_parameters["udp"]["destination_port_range_list"] = dest_port_range_list + protocol_parameters["udp"][ + "destination_port_range_list" + ] = dest_port_range_list elif config.get("icmp"): protocol_type = "ICMP" diff --git a/plugins/modules/ntnx_pbrs.py b/plugins/modules/ntnx_pbrs.py index 0bc7903bd..a2f9f5cb1 100644 --- a/plugins/modules/ntnx_pbrs.py +++ b/plugins/modules/ntnx_pbrs.py @@ -8,7 +8,6 @@ __metaclass__ = type DOCUMENTATION = r""" ---- module: ntnx_pbrs short_description: pbr module which suports pbr CRUD operations version_added: 1.0.0 @@ -57,8 +56,143 @@ description: This is the wait description. type: bool required: false - default: True - #TODO here should be additional arguments documentation + default: true + priority: + description: To-Write + type: int + required: true + pbr_uuid: + description: To-Write + 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: + - To-Write + type: dict + suboptions: + any: + description: + - To-Write + type: bool + default: true + external: + description: + - To-Write + type: bool + network: + description: + - To-Write + type: dict + suboptions: + ip: + description: Subnet ip address + type: str + prefix: + description: ip address prefix length + type: str + destination: + type: dict + description: To-Write + suboptions: + any: + description: + - To-Write + type: bool + default: true + external: + description: + - To-Write + type: bool + network: + description: + - To-Write + 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: To-Write + type: bool + default: true + tcp: + description: To-Write + type: dict + suboptions: + src: + default: '*' + type: list + elements: str + description: To-Write + dst: + default: '*' + type: list + elements: str + description: To-Write + udp: + description: To-Write + type: dict + suboptions: + src: + default: '*' + type: list + elements: str + description: To-Write + dst: + default: '*' + type: list + elements: str + description: To-Write + number: + type: int + description: To-Write + icmp: + description: To-Write + type: dict + suboptions: + code: + type: int + description: To-Write + action: + type: dict + description: To-Write + suboptions: + deny: + type: bool + description: To-Write + allow: + type: bool + default: true + description: To-Write + reroute: + type: str + description: To-Write +author: + - Prem Karat (@premkarat) + - Gevorg Khachatryan (@Gevorg-Khachatryan-97) + - Alaa Bishtawi (@alaa-bish) + - Dina AbuHijleh (@dina-abuhijleh) """ EXAMPLES = r""" @@ -80,38 +214,30 @@ def get_module_spec(): entity_by_spec = dict(name=dict(type="str"), uuid=dict(type="str")) - network_spec = dict( - ip=dict(), - prefix=dict() - ) + network_spec = dict(ip=dict(type="str"), prefix=dict(type="str")) route_spec = dict( any=dict(type="bool", default=True), external=dict(type="bool"), - network=dict(type="dict", - options=network_spec, - ), + network=dict( + type="dict", + options=network_spec, + ), ) tcp_and_udp_spec = dict( - src=dict(type="list", default=["*"]), - dst=dict(type="list", default=["*"]) + 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") - ) + icmp_spec = dict(code=dict(type="int"), type=dict(type="int")) protocol_spec = dict( any=dict(type="bool", default=True), - tcp=dict(type="dict", - options=tcp_and_udp_spec), - udp=dict(type="dict", - options=tcp_and_udp_spec), + 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="object", - options=icmp_spec), + icmp=dict(type="dict", options=icmp_spec), ) action_spec = dict( @@ -122,34 +248,34 @@ def get_module_spec(): module_args = dict( priority=dict(type="int", required=True), - pbr_uuid=dict(type="str"), - - vpc=dict(type="dict", - options=entity_by_spec, - mutually_exclusive=mutually_exclusive), - - source=dict(type="dict", - options=route_spec, - apply_defaults=True, - mutually_exclusive=[("any", "external", "network")]), - - destination=dict(type="dict", - options=route_spec, - apply_defaults=True, - 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, - apply_defaults=True, - mutually_exclusive=[("deny", "allow", "reroute")] - ), + vpc=dict( + type="dict", options=entity_by_spec, mutually_exclusive=mutually_exclusive + ), + source=dict( + type="dict", + options=route_spec, + apply_defaults=True, + mutually_exclusive=[("any", "external", "network")], + ), + destination=dict( + type="dict", + options=route_spec, + apply_defaults=True, + 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, + apply_defaults=True, + mutually_exclusive=[("deny", "allow", "reroute")], + ), ) return module_args @@ -218,10 +344,7 @@ def wait_for_task_completion(module, result): def run_module(): - module = BaseModule( - argument_spec=get_module_spec(), - supports_check_mode=True - ) + module = BaseModule(argument_spec=get_module_spec(), supports_check_mode=True) remove_param_with_none_value(module.params) result = { "changed": False, From 3baba470a7a47fcba789e41b785979f63eb3b608 Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Wed, 16 Feb 2022 12:38:26 +0400 Subject: [PATCH 03/16] #99 spec fixes --- plugins/modules/ntnx_pbrs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/ntnx_pbrs.py b/plugins/modules/ntnx_pbrs.py index 0bc7903bd..810bee5c0 100644 --- a/plugins/modules/ntnx_pbrs.py +++ b/plugins/modules/ntnx_pbrs.py @@ -110,7 +110,7 @@ def get_module_spec(): udp=dict(type="dict", options=tcp_and_udp_spec), number=dict(type="int"), - icmp=dict(type="object", + icmp=dict(type="dict", options=icmp_spec), ) From d755447108eda969863c3aad8aec10c605f5f91c Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Wed, 16 Feb 2022 13:06:42 +0400 Subject: [PATCH 04/16] #99 spec generation fixes --- plugins/module_utils/prism/pbrs.py | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/plugins/module_utils/prism/pbrs.py b/plugins/module_utils/prism/pbrs.py index f93446eed..0f4d3453b 100644 --- a/plugins/module_utils/prism/pbrs.py +++ b/plugins/module_utils/prism/pbrs.py @@ -85,6 +85,7 @@ def _build_spec_protocol(self, payload, config): protocol_type = None protocol_parameters = {} if config.get("tcp"): + tcp = {} protocol_type = "TCP" src_port_range_list = [] if "*" not in config["tcp"]["src"]: @@ -97,11 +98,14 @@ def _build_spec_protocol(self, payload, config): port = port.split("-") dest_port_range_list.append({"start_port": int(port[0]), "end_port": int(port[-1])}) if src_port_range_list: - protocol_parameters["tcp"]["source_port_range_list"] = src_port_range_list + tcp["source_port_range_list"] = src_port_range_list if dest_port_range_list: - protocol_parameters["tcp"]["destination_port_range_list"] = dest_port_range_list + tcp["destination_port_range_list"] = dest_port_range_list + if tcp: + protocol_parameters["tcp"] = tcp elif config.get("udp"): + udp = {} protocol_type = "UDP" src_port_range_list = [] if "*" not in config["udp"]["src"]: @@ -114,14 +118,16 @@ def _build_spec_protocol(self, payload, config): port = port.split("-") dest_port_range_list.append({"start_port": int(port[0]), "end_port": int(port[-1])}) if src_port_range_list: - protocol_parameters["udp"]["source_port_range_list"] = src_port_range_list + udp["source_port_range_list"] = src_port_range_list if dest_port_range_list: - protocol_parameters["udp"]["destination_port_range_list"] = dest_port_range_list + udp["destination_port_range_list"] = dest_port_range_list + if udp: + protocol_parameters["udp"] = udp elif config.get("icmp"): protocol_type = "ICMP" if config["icmp"].get("code"): - protocol_parameters["icmp"]["icmp_code"] = config["icmp"]["code"] + protocol_parameters["icmp"] = {"icmp_code": config["icmp"]["code"]} if config["icmp"].get("type"): protocol_parameters["icmp"]["icmp_type"] = config["icmp"]["type"] @@ -129,7 +135,7 @@ def _build_spec_protocol(self, payload, config): protocol_type = "PROTOCOL_NUMBER" protocol_parameters["protocol_number"] = config["number"] - elif config.get("any"): + else: protocol_type = "ALL" payload["spec"]["resources"]["protocol_type"] = protocol_type From 2440af2e3c42a5278a6a3912f394826849a1620e Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Wed, 16 Feb 2022 17:08:49 +0400 Subject: [PATCH 05/16] #99 spec generation fixes --- plugins/module_utils/prism/pbrs.py | 11 +++++------ plugins/modules/ntnx_pbrs.py | 13 +++++++++---- 2 files changed, 14 insertions(+), 10 deletions(-) diff --git a/plugins/module_utils/prism/pbrs.py b/plugins/module_utils/prism/pbrs.py index 0f4d3453b..ab5ce2009 100644 --- a/plugins/module_utils/prism/pbrs.py +++ b/plugins/module_utils/prism/pbrs.py @@ -61,7 +61,7 @@ def _build_spec_source(self, payload, config): source["address_type"] = "INTERNET" elif config.get("network"): source["ip_subnet"] = {"ip": config["network"].get("ip"), - "prefix_length": config["network"].get("prefix")} + "prefix_length": int(config["network"].get("prefix"))} payload["spec"]["resources"]["source"] = source @@ -75,7 +75,7 @@ def _build_spec_destination(self, payload, config): destination["address_type"] = "INTERNET" elif config.get("network"): destination["ip_subnet"] = {"ip": config["network"].get("ip"), - "prefix_length": config["network"].get("prefix")} + "prefix_length": int(config["network"].get("prefix"))} payload["spec"]["resources"]["destination"] = destination @@ -146,14 +146,13 @@ def _build_spec_protocol(self, payload, config): def _build_spec_action(self, payload, config): action = {} - - if config.get("allow"): - action["action"] = "PERMIT" if config.get("deny"): action["action"] = "DENY" # TODO check - if config.get("reroute"): + 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 diff --git a/plugins/modules/ntnx_pbrs.py b/plugins/modules/ntnx_pbrs.py index 810bee5c0..e26e44a23 100644 --- a/plugins/modules/ntnx_pbrs.py +++ b/plugins/modules/ntnx_pbrs.py @@ -86,7 +86,7 @@ def get_module_spec(): ) route_spec = dict( - any=dict(type="bool", default=True), + any=dict(type="bool"), external=dict(type="bool"), network=dict(type="dict", options=network_spec, @@ -104,7 +104,7 @@ def get_module_spec(): ) protocol_spec = dict( - any=dict(type="bool", default=True), + any=dict(type="bool"), tcp=dict(type="dict", options=tcp_and_udp_spec), udp=dict(type="dict", @@ -116,12 +116,12 @@ def get_module_spec(): action_spec = dict( deny=dict(type="bool"), - allow=dict(type="bool", default=True), + allow=dict(type="bool"), reroute=dict(type="str"), ) module_args = dict( - priority=dict(type="int", required=True), + priority=dict(type="int"), pbr_uuid=dict(type="str"), @@ -220,6 +220,11 @@ def wait_for_task_completion(module, result): def run_module(): module = BaseModule( argument_spec=get_module_spec(), + mutually_exclusive=[("priority", "pbr_uuid")], + required_if=[ + ("state", "present", ("priority",)), + ("state", "absent", ("pbr_uuid",)), + ], supports_check_mode=True ) remove_param_with_none_value(module.params) From ddc840c5ab6b092f55db7c0fd92c717315d4112e Mon Sep 17 00:00:00 2001 From: alaa-bish Date: Thu, 17 Feb 2022 08:13:43 +0200 Subject: [PATCH 06/16] Fix sanity --- plugins/module_utils/prism/pbrs.py | 12 +++++++---- .../module_utils/prism/virtual_switches.py | 4 +++- plugins/modules/ntnx_pbrs.py | 20 +++++++------------ 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/plugins/module_utils/prism/pbrs.py b/plugins/module_utils/prism/pbrs.py index 4764018cc..b8abcef7f 100644 --- a/plugins/module_utils/prism/pbrs.py +++ b/plugins/module_utils/prism/pbrs.py @@ -59,8 +59,10 @@ def _build_spec_source(self, payload, config): 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"))} + source["ip_subnet"] = { + "ip": config["network"].get("ip"), + "prefix_length": int(config["network"].get("prefix")), + } payload["spec"]["resources"]["source"] = source @@ -73,8 +75,10 @@ def _build_spec_destination(self, payload, config): 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"))} + destination["ip_subnet"] = { + "ip": config["network"].get("ip"), + "prefix_length": int(config["network"].get("prefix")), + } payload["spec"]["resources"]["destination"] = destination diff --git a/plugins/module_utils/prism/virtual_switches.py b/plugins/module_utils/prism/virtual_switches.py index 5c8bac218..19b61fb3d 100644 --- a/plugins/module_utils/prism/virtual_switches.py +++ b/plugins/module_utils/prism/virtual_switches.py @@ -13,7 +13,9 @@ 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( + entity_type="distributed_virtual_switch", filter="name=={0}".format(name) + ) if not uuid: error = "Virtual Switch {0} not found.".format(name) return None, error diff --git a/plugins/modules/ntnx_pbrs.py b/plugins/modules/ntnx_pbrs.py index 653b4c7aa..ac8b9d332 100644 --- a/plugins/modules/ntnx_pbrs.py +++ b/plugins/modules/ntnx_pbrs.py @@ -60,7 +60,6 @@ priority: description: To-Write type: int - required: true pbr_uuid: description: To-Write type: str @@ -88,7 +87,6 @@ description: - To-Write type: bool - default: true external: description: - To-Write @@ -112,7 +110,6 @@ description: - To-Write type: bool - default: true external: description: - To-Write @@ -135,7 +132,6 @@ any: description: To-Write type: bool - default: true tcp: description: To-Write type: dict @@ -174,6 +170,9 @@ code: type: int description: To-Write + type: + description: To-Write + type: int action: type: dict description: To-Write @@ -183,7 +182,6 @@ description: To-Write allow: type: bool - default: true description: To-Write reroute: type: str @@ -234,13 +232,10 @@ def get_module_spec(): 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), + 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), + icmp=dict(type="dict", options=icmp_spec), ) action_spec = dict( @@ -251,7 +246,6 @@ def get_module_spec(): module_args = dict( priority=dict(type="int"), - pbr_uuid=dict(type="str"), vpc=dict( type="dict", options=entity_by_spec, mutually_exclusive=mutually_exclusive @@ -355,7 +349,7 @@ def run_module(): ("state", "present", ("priority",)), ("state", "absent", ("pbr_uuid",)), ], - supports_check_mode=True + supports_check_mode=True, ) remove_param_with_none_value(module.params) result = { From 526b5b071dc03bf6b8c24b70cf8aed737365083b Mon Sep 17 00:00:00 2001 From: alaa-bish Date: Thu, 17 Feb 2022 10:24:33 +0200 Subject: [PATCH 07/16] Add integration Test: Gihub#101 --- .../nutanix_pbrs/tasks/create_pbrs.yml | 183 ++++++++++++++++++ .../targets/nutanix_pbrs/tasks/main.yml | 3 + .../targets/nutanix_pbrs/vars/main.yml | 27 +++ 3 files changed, 213 insertions(+) create mode 100644 tests/integration/targets/nutanix_pbrs/tasks/create_pbrs.yml create mode 100644 tests/integration/targets/nutanix_pbrs/tasks/main.yml create mode 100644 tests/integration/targets/nutanix_pbrs/vars/main.yml 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 From b34f7bb02708b5562327d489940888ab125d3d93 Mon Sep 17 00:00:00 2001 From: alaa-bish Date: Thu, 17 Feb 2022 11:12:39 +0200 Subject: [PATCH 08/16] fix doc:Gihub#101 --- plugins/modules/ntnx_pbrs.py | 271 ++++++++++++++++++++++++++++++----- 1 file changed, 237 insertions(+), 34 deletions(-) diff --git a/plugins/modules/ntnx_pbrs.py b/plugins/modules/ntnx_pbrs.py index ac8b9d332..db385b3f6 100644 --- a/plugins/modules/ntnx_pbrs.py +++ b/plugins/modules/ntnx_pbrs.py @@ -8,6 +8,7 @@ __metaclass__ = type DOCUMENTATION = r""" +--- module: ntnx_pbrs short_description: pbr module which suports pbr CRUD operations version_added: 1.0.0 @@ -58,10 +59,10 @@ required: false default: true priority: - description: To-Write + description: The policy priority number type: int pbr_uuid: - description: To-Write + description: PBR UUID type: str vpc: description: @@ -79,21 +80,17 @@ - Mutually exclusive with (name) type: str source: - description: - - To-Write + description: Where the traffic came from type: dict suboptions: any: - description: - - To-Write + description: From any source type: bool external: - description: - - To-Write + description: External Network type: bool network: - description: - - To-Write + description: specfic network address type: dict suboptions: ip: @@ -104,19 +101,16 @@ type: str destination: type: dict - description: To-Write + description: Where the traffic going to suboptions: any: - description: - - To-Write + description: From any destination type: bool external: - description: - - To-Write + description: External Network type: bool network: - description: - - To-Write + description: specfic network address type: dict suboptions: ip: @@ -130,62 +124,62 @@ description: The Network Protocol that will used suboptions: any: - description: To-Write + description: any protcol number type: bool tcp: - description: To-Write + description: The Transmission Control will be used type: dict suboptions: src: default: '*' type: list elements: str - description: To-Write + description: Where the traffic came from dst: default: '*' type: list elements: str - description: To-Write + description: Where the traffic going to udp: - description: To-Write + description: User datagram protocol will be used type: dict suboptions: src: default: '*' type: list elements: str - description: To-Write + description: Where the traffic came from dst: default: '*' type: list elements: str - description: To-Write + description: Where the traffic going to number: type: int - description: To-Write + description: The internet protocol number icmp: - description: To-Write + description: Internet Control Message Protocol will be used type: dict suboptions: code: type: int - description: To-Write + description: ICMP code type: - description: To-Write + description: ICMP type type: int action: type: dict - description: To-Write + description: The behavior on the request suboptions: deny: type: bool - description: To-Write + description: Drop the request allow: type: bool - description: To-Write + description: Accept the request reroute: type: str - description: To-Write + description: Change the request route author: - Prem Karat (@premkarat) - Gevorg Khachatryan (@Gevorg-Khachatryan-97) @@ -194,11 +188,220 @@ """ EXAMPLES = r""" -# TODO + +- 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""" -# TODO +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 679c56177a3c845e6e59b762d49e11fd931ebc62 Mon Sep 17 00:00:00 2001 From: alaa-bish Date: Thu, 17 Feb 2022 11:39:32 +0200 Subject: [PATCH 09/16] Fix sanity:Gihub#101 --- plugins/module_utils/prism/groups.py | 4 ++-- plugins/module_utils/prism/virtual_switches.py | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/plugins/module_utils/prism/groups.py b/plugins/module_utils/prism/groups.py index 5b876db59..86af84ed7 100644 --- a/plugins/module_utils/prism/groups.py +++ b/plugins/module_utils/prism/groups.py @@ -12,8 +12,8 @@ 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): + data = {"entity_type": value, "filter_criteria": key} 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/virtual_switches.py b/plugins/module_utils/prism/virtual_switches.py index 19b61fb3d..5c8bac218 100644 --- a/plugins/module_utils/prism/virtual_switches.py +++ b/plugins/module_utils/prism/virtual_switches.py @@ -13,9 +13,7 @@ def get_dvs_uuid(config, module): if "name" in config: groups = Groups(module) name = config["name"] - uuid = groups.get_uuid( - entity_type="distributed_virtual_switch", filter="name=={0}".format(name) - ) + uuid = groups.get_uuid("distributed_virtual_switch", "name=={0}".format(name)) if not uuid: error = "Virtual Switch {0} not found.".format(name) return None, error From 3cdcc89c34d7a053694d0713e0d6db9e16217fbb Mon Sep 17 00:00:00 2001 From: alaa-bish Date: Thu, 17 Feb 2022 11:52:29 +0200 Subject: [PATCH 10/16] Fix Isort --- plugins/modules/ntnx_pbrs.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/ntnx_pbrs.py b/plugins/modules/ntnx_pbrs.py index db385b3f6..3e974c320 100644 --- a/plugins/modules/ntnx_pbrs.py +++ b/plugins/modules/ntnx_pbrs.py @@ -405,8 +405,8 @@ """ from ..module_utils.base_module import BaseModule # noqa: E402 -from ..module_utils.prism.tasks import Task # 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 From 6dad4bf6fbc38f2c3d13d98e1307892f7e94381e Mon Sep 17 00:00:00 2001 From: alaa-bish Date: Thu, 17 Feb 2022 12:01:51 +0200 Subject: [PATCH 11/16] Add pbr example --- examples/create_pbr.yml | 44 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 examples/create_pbr.yml 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 }}" From eba0857a7ce88069f7c9283e3477529d72b68e2f Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Thu, 17 Feb 2022 14:49:12 +0400 Subject: [PATCH 12/16] #105 fixes fo groups get_uuid --- plugins/module_utils/prism/groups.py | 4 ++-- plugins/module_utils/prism/virtual_switches.py | 2 +- plugins/module_utils/prism/vms.py | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/plugins/module_utils/prism/groups.py b/plugins/module_utils/prism/groups.py index 86af84ed7..d2efe7eb2 100644 --- a/plugins/module_utils/prism/groups.py +++ b/plugins/module_utils/prism/groups.py @@ -12,8 +12,8 @@ def __init__(self, module): resource_type = "/groups" super(Groups, self).__init__(module, resource_type=resource_type) - def get_uuid(self, value, key): - data = {"entity_type": value, "filter_criteria": key} + 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/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) From 571e846732a09132f3dcd410f3df7406a757647a Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Thu, 17 Feb 2022 15:12:43 +0400 Subject: [PATCH 13/16] #99 protocol spec generation fixes --- plugins/module_utils/prism/pbrs.py | 48 ++++++++---------------------- 1 file changed, 12 insertions(+), 36 deletions(-) diff --git a/plugins/module_utils/prism/pbrs.py b/plugins/module_utils/prism/pbrs.py index b8abcef7f..9174bf52b 100644 --- a/plugins/module_utils/prism/pbrs.py +++ b/plugins/module_utils/prism/pbrs.py @@ -85,55 +85,31 @@ def _build_spec_destination(self, payload, config): return payload, None def _build_spec_protocol(self, payload, config): - protocol_type = None protocol_parameters = {} - if config.get("tcp"): - tcp = {} - protocol_type = "TCP" + 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["tcp"]["src"]: - for port in config["tcp"]["src"]: + 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["tcp"]["dst"]: - for port in config["tcp"]["dst"]: + 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: - tcp["source_port_range_list"] = src_port_range_list + value["source_port_range_list"] = src_port_range_list if dest_port_range_list: - tcp["destination_port_range_list"] = dest_port_range_list - if tcp: - protocol_parameters["tcp"] = tcp - - elif config.get("udp"): - udp = {} - protocol_type = "UDP" - src_port_range_list = [] - if "*" not in config["udp"]["src"]: - for port in config["udp"]["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["udp"]["dst"]: - for port in config["udp"]["dst"]: - port = port.split("-") - dest_port_range_list.append( - {"start_port": int(port[0]), "end_port": int(port[-1])} - ) - if src_port_range_list: - udp["source_port_range_list"] = src_port_range_list - if dest_port_range_list: - udp["destination_port_range_list"] = dest_port_range_list - if udp: - protocol_parameters["udp"] = udp + value["destination_port_range_list"] = dest_port_range_list + if value: + protocol_parameters[key] = value elif config.get("icmp"): protocol_type = "ICMP" From b8bf1c5092881376adc7af87b835ef4d7ad6a9a4 Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Thu, 17 Feb 2022 15:16:03 +0400 Subject: [PATCH 14/16] #99 black fixes --- plugins/module_utils/prism/groups.py | 5 ++++- plugins/module_utils/prism/pbrs.py | 4 +--- plugins/modules/ntnx_pbrs.py | 9 ++------- 3 files changed, 7 insertions(+), 11 deletions(-) diff --git a/plugins/module_utils/prism/groups.py b/plugins/module_utils/prism/groups.py index d2efe7eb2..1b654b90a 100644 --- a/plugins/module_utils/prism/groups.py +++ b/plugins/module_utils/prism/groups.py @@ -13,7 +13,10 @@ def __init__(self, module): super(Groups, self).__init__(module, resource_type=resource_type) def get_uuid(self, value, key="name", entity_type=""): - data = {"entity_type": entity_type, "filter_criteria": "{0}=={1}".format(key, value)} + 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 index 9174bf52b..7df46f2d3 100644 --- a/plugins/module_utils/prism/pbrs.py +++ b/plugins/module_utils/prism/pbrs.py @@ -30,9 +30,7 @@ def _get_default_spec(self): { "api_version": "3.1.0", "metadata": {"kind": "routing_policy"}, - "spec": { - "resources": {}, - }, + "spec": {"resources": {}}, } ) diff --git a/plugins/modules/ntnx_pbrs.py b/plugins/modules/ntnx_pbrs.py index 3e974c320..1cfa65af7 100644 --- a/plugins/modules/ntnx_pbrs.py +++ b/plugins/modules/ntnx_pbrs.py @@ -420,10 +420,7 @@ def get_module_spec(): route_spec = dict( any=dict(type="bool"), external=dict(type="bool"), - network=dict( - type="dict", - options=network_spec, - ), + network=dict(type="dict", options=network_spec), ) tcp_and_udp_spec = dict( @@ -442,9 +439,7 @@ def get_module_spec(): ) action_spec = dict( - deny=dict(type="bool"), - allow=dict(type="bool"), - reroute=dict(type="str"), + deny=dict(type="bool"), allow=dict(type="bool"), reroute=dict(type="str") ) module_args = dict( From b2c32efa77f23118dbd8f9091606f47a35043567 Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Thu, 17 Feb 2022 16:00:55 +0400 Subject: [PATCH 15/16] #99 flake8 fix --- plugins/module_utils/prism/pbrs.py | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/module_utils/prism/pbrs.py b/plugins/module_utils/prism/pbrs.py index 7df46f2d3..3ee7d3603 100644 --- a/plugins/module_utils/prism/pbrs.py +++ b/plugins/module_utils/prism/pbrs.py @@ -4,7 +4,6 @@ __metaclass__ = type -import os from copy import deepcopy from .prism import Prism From b324177a67de51a326cd80f3d91a9519ce177685 Mon Sep 17 00:00:00 2001 From: Gevorg-Khachatryaan Date: Thu, 17 Feb 2022 17:53:07 +0400 Subject: [PATCH 16/16] #99 update arguments validation --- plugins/modules/ntnx_pbrs.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/plugins/modules/ntnx_pbrs.py b/plugins/modules/ntnx_pbrs.py index 1cfa65af7..d84c9417e 100644 --- a/plugins/modules/ntnx_pbrs.py +++ b/plugins/modules/ntnx_pbrs.py @@ -451,13 +451,11 @@ def get_module_spec(): source=dict( type="dict", options=route_spec, - apply_defaults=True, mutually_exclusive=[("any", "external", "network")], ), destination=dict( type="dict", options=route_spec, - apply_defaults=True, mutually_exclusive=[("any", "external", "network")], ), protocol=dict( @@ -469,7 +467,6 @@ def get_module_spec(): action=dict( type="dict", options=action_spec, - apply_defaults=True, mutually_exclusive=[("deny", "allow", "reroute")], ), ) @@ -544,7 +541,7 @@ def run_module(): argument_spec=get_module_spec(), mutually_exclusive=[("priority", "pbr_uuid")], required_if=[ - ("state", "present", ("priority",)), + ("state", "present", ("priority", "action", "source", "destination")), ("state", "absent", ("pbr_uuid",)), ], supports_check_mode=True,