From 4fc083550a7ad006e770e6ec4d3009f9af686389 Mon Sep 17 00:00:00 2001 From: Muthu Rakesh <19cs127@psgitech.ac.in> Date: Wed, 14 Jun 2023 13:04:14 +0530 Subject: [PATCH 01/13] Documentation changes in the example --- plugins/modules/site_intent.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/plugins/modules/site_intent.py b/plugins/modules/site_intent.py index 1ce7446932..887db6b8c2 100644 --- a/plugins/modules/site_intent.py +++ b/plugins/modules/site_intent.py @@ -123,14 +123,14 @@ dnac_debug: "{{dnac_debug}}" dnac_log: "{{dnac_log}}" config: - site: - building: - address: string - latitude: 0 - longitude: 0 - name: string - parentName: string - type: string + - site: + building: + address: string + latitude: 0 + longitude: 0 + name: string + parentName: string + type: string """ RETURN = r""" From 7cd74aff57e1281300f767e1a1d921b07247ac8a Mon Sep 17 00:00:00 2001 From: Muthu Rakesh <19cs127@psgitech.ac.in> Date: Mon, 26 Jun 2023 16:39:56 +0530 Subject: [PATCH 02/13] network intent playbook --- playbooks/network_intent.yml | 44 ++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 playbooks/network_intent.yml diff --git a/playbooks/network_intent.yml b/playbooks/network_intent.yml new file mode 100644 index 0000000000..bf3ae95ecf --- /dev/null +++ b/playbooks/network_intent.yml @@ -0,0 +1,44 @@ +- hosts: dnac_servers + vars_files: + - credentials_245.yml + gather_facts: no + connection: local + tasks: +# +# Project Info Section +# + + - name: Create, update, delete global pool and reserve an ip pool + cisco.dnac.network_intent: + dnac_host: "{{ dnac_host }}" + dnac_port: "{{ dnac_port }}" + dnac_username: "{{ dnac_username }}" + dnac_password: "{{ dnac_password }}" + dnac_verify: "{{ dnac_verify }}" + dnac_debug: "{{ dnac_debug }}" + dnac_log: True + state: merged + config: + - GlobalPoolDetails: + settings: + ippool: + - ipPoolName: Global_Pool + gateway: "" #use this for updating + IpAddressSpace: IPv4 #required when we are creating + ipPoolCidr: 90.0.0.0/8 #required when we are creating + type: generic + dhcpServerIps: [] #use this for updating + dnsServerIps: [] #use this for updating + # prev_name: Global_Pool + ReservePoolDetails: + ipv6AddressSpace: false + ipv4GlobalPool: 90.0.0.0/8 + ipv4Prefix: true + ipv4PrefixLength: 8 + ipv4DnsServers: [] + name: IP_Pool_4 + siteName: Global/Chennai/Trill + slaacSupport: true + # prev_name: IP_Pool_4 + type: LAN + From 16d333019ecf748095f4ddd1f3453bb94bd6f489 Mon Sep 17 00:00:00 2001 From: Muthu Rakesh <19cs127@psgitech.ac.in> Date: Mon, 26 Jun 2023 16:40:48 +0530 Subject: [PATCH 03/13] network intent module --- plugins/modules/network_intent.py | 908 ++++++++++++++++++++++++++++++ 1 file changed, 908 insertions(+) create mode 100644 plugins/modules/network_intent.py diff --git a/plugins/modules/network_intent.py b/plugins/modules/network_intent.py new file mode 100644 index 0000000000..be7515e897 --- /dev/null +++ b/plugins/modules/network_intent.py @@ -0,0 +1,908 @@ + + +import copy + +try: + from ansible_collections.ansible.utils.plugins.module_utils.common.argspec_validate import ( + AnsibleArgSpecValidator, + ) +except ImportError: + ANSIBLE_UTILS_IS_INSTALLED = False +else: + ANSIBLE_UTILS_IS_INSTALLED = True +from ansible_collections.cisco.dnac.plugins.module_utils.dnac import ( + DNACSDK, + dnac_argument_spec, + validate_list_of_dicts, + log, + get_dict_result, + dnac_compare_equality, +) +from ansible.module_utils.basic import AnsibleModule + + +class DnacNetwork: + def __init__(self, module): + self.module = module + self.params = module.params + self.config = copy.deepcopy(module.params.get("config")) + self.have = {} + self.want = {} + self.have_reserve = {} + self.want_reserve = {} + self.site_id = None + self.validated = [] + dnac_params = self.get_dnac_params(self.params) + log(str(dnac_params)) + self.dnac = DNACSDK(params=dnac_params) + self.log = dnac_params.get("dnac_log") + + self.result = dict(changed=False, diff=[], response=[], warnings=[]) + + + def get_state(self): + return self.params.get("state") + + + def validate_input(self): + + temp_spec = dict( + IpAddressSpace = dict(required = False, type="string"), + dhcpServerIps = dict(required = False, type="list"), + dnsServerIps = dict(required = False, type="list"), + gateway = dict(required = False, type="string"), + ipPoolCidr = dict(required = False, type="string"), + ipPoolName = dict(required = False, type="string"), + name = dict(required = False, type="string"), + prev_name = dict(required = False, type="string"), + type = dict(required = False, type = "string", choices=["generic", "tunnel", "LAN", "WAN", "management", "service"]), + ipv6AddressSpace = dict(required = False, type = "string"), + ipv4GlobalPool = dict(required = False, type = "string"), + ipv4Prefix = dict(required = False, type = "string"), + ipv4PrefixLength = dict(required = False, type = "integer"), + ipv4GateWay = dict(required = False, type = "string"), + ipv4DhcpServers = dict(required = False, type = "list"), + ipv4DnsServers = dict(required =False, type = "list"), + ipv6GlobalPool = dict(required = False, type = "string"), + ipv6Prefix = dict(required = False, type = "string"), + ipv6PrefixLength = dict(required = False, type = "integer"), + ipv6GateWay = dict(required = False, type = "string"), + ipv6DhcpServers = dict(required = False, type = "list"), + ipv6DnsServers = dict(required = False, type = "list"), + ipv4TotalHost = dict(required = False, type = "integer"), + ipv6TotalHost = dict(required = False, type = "integer"), + slaacSupport = dict(required = False, type = "string"), + siteName = dict(required = False, type = "string") + + ) + if self.config: + msg = None + temp = [] + temp1 = [] + # Validate template params + if self.config[0].get("GlobalPoolDetails") != None: + temp = self.config[0].get("GlobalPoolDetails").get("settings").get("ippool") + + if self.config[0].get("ReservePoolDetails") != None: + temp1 = [self.config[0].get("ReservePoolDetails")] + + temp = temp + temp1 + valid_temp, invalid_params = validate_list_of_dicts( + temp, temp_spec + ) + if invalid_params: + msg = "Invalid parameters in playbook: {0}".format( + "\n".join(invalid_params) + ) + self.module.fail_json(msg=msg) + log(str(invalid_params)) + self.validated = valid_temp + + if self.log: + log(str(valid_temp)) + log(str(self.result)) +## log(str(self.validated)) + + log(str(self.validated)) + if self.params.get("config")[0].get("GlobalPoolDetails") != None: + for temp in self.validated: + log(str(temp)) + ## self.params.get("config")[0].get("GlobalPoolDetails").get("settings").get("ippool")[0] + if self.params.get("config")[0].get("GlobalPoolDetails").get("ipPoolName") != None: + msg = "missing required arguments: ipPoolName" + self.module.fail_json(msg=msg) + + + def get_dnac_params(self, params): + dnac_params = dict( + dnac_host=params.get("dnac_host"), + dnac_port=params.get("dnac_port"), + dnac_username=params.get("dnac_username"), + dnac_password=params.get("dnac_password"), + dnac_verify=params.get("dnac_verify"), + dnac_debug=params.get("dnac_debug"), + dnac_log=params.get("dnac_log"), + ) + return dnac_params + + + def requires_update(self, have, want, obj_params): + current_obj = have + requested_obj = want + log(str(current_obj)) + log(str(requested_obj)) + + + return any(not dnac_compare_equality(current_obj.get(dnac_param), + requested_obj.get(ansible_param)) + for(dnac_param, ansible_param) in obj_params) + + + def get_pool_id_from_name(self, pool_name): + pool_id = None + current_details = None + try: + + response = self.dnac._exec( + family = "network_settings", + function = "get_global_pool", + ) + + if isinstance(response, dict): + if "response" in response: + response = response.get("response") + log(str(response)) + current_details = get_dict_result(response, "ipPoolName", pool_name) + log(str(current_details)) + if current_details: + pool_id = current_details.get("id") + + except: + result = None + + return (pool_id, current_details) + + + def get_res_id_from_name(self, res_name): + id = "" + current_details = None + try: + response = self.dnac._exec( + family="network_settings", + function="get_reserve_ip_subpool", + params={"site_id": self.site_id} + ) + + if isinstance(response, dict): + if "response" in response: + response = response.get("response") + log(str(response)) + current_details = get_dict_result(response, "groupName", res_name) + log(str(current_details)) + + id = current_details.get("id") + except: + log("except") + result = None + return id + + + def get_current_pool(self, pool): + log(str(pool)) + pool_values = dict( + settings = dict( + ippool = [dict( + dhcpServerIps = pool.get("dhcpServerIps"), + dnsServerIps = pool.get("dnsServerIps"), + ipPoolCidr = pool.get("ipPoolCidr"), + ipPoolName = pool.get("ipPoolName"), + type = pool.get("type"), + )] + ) + ) + log(str(pool_values)) + if pool.get("ipv6") == False: + pool_values.get("settings").get("ippool")[0].update({"IpAddressSpace": "IPv4"}) + log("ipv6 - false") + else: + pool_values.get("settings").get("ippool")[0].update({"IpAddressSpace": "IPv6"}) + log("ipv6 - true") + if not pool["gateways"]: + pool_values.get("settings").get("ippool")[0].update({"gateway": ""}) + else: + pool_values.get("settings").get("ippool")[0].update({"gateway": pool.get("gateways")[0]}) + + return pool_values + + + def get_current_res(self, res): + log(str(res)) + res_values = dict( + name = res.get("groupName"), + site_id = res.get("siteId"), + ) + + if len(res.get("ipPools")) == 1: + res_values.update({"ipv4DhcpServers": res.get("ipPools")[0].get("dhcpServerIps")}) + res_values.update({"ipv4DnsServers": res.get("ipPools")[0].get("dnsServerIps")}) + res_values.update({"ipv4GateWay": res.get("ipPools")[0].get("gateways")[0]}) + res_values.update({"ipv6AddressSpace": "False"}) + + elif len(res.get("ipPools")) == 2: + if res.get("ipPools")[0].get("ipv6") == False: + res_values.update({"ipv4DhcpServers": res.get("ipPools")[0].get("dhcpServerIps")}) + res_values.update({"ipv4DnsServers": res.get("ipPools")[0].get("dnsServerIps")}) + res_values.update({"ipv4GateWay": res.get("ipPools")[0].get("gateways")[0]}) + res_values.update({"ipv6AddressSpace": "True"}) + res_values.update({"ipv4DhcpServers": res.get("ipPools")[1].get("dhcpServerIps")}) + res_values.update({"ipv4DnsServers": res.get("ipPools")[1].get("dnsServerIps")}) + res_values.update({"ipv4GateWay": res.get("ipPools")[1].get("gateways")[0]}) + + elif res.get("ipPools")[1].get("ipv6") == False: + res_values.update({"ipv4DhcpServers": res.get("ipPools")[1].get("dhcpServerIps")}) + res_values.update({"ipv4DnsServers": res.get("ipPools")[1].get("dnsServerIps")}) + res_values.update({"ipv4GateWay": res.get("ipPools")[1].get("gateways")[0]}) + res_values.update({"ipv6AddressSpace": "True"}) + res_values.update({"ipv4DhcpServers": res.get("ipPools")[0].get("dhcpServerIps")}) + res_values.update({"ipv4DnsServers": res.get("ipPools")[0].get("dnsServerIps")}) + res_values.update({"ipv4GateWay": res.get("ipPools")[0].get("gateways")[0]}) + + return res_values + + def get_site_id(self, site_name): + + response = {} + _id = None + result = None + try: + response = self.dnac._exec( + family="sites", + function='get_site', + params={"name":site_name}, + ) + + except: + result = None + log(str(response)) + if not response: + log("Invalid site name or site not present") + self.result["response"] = [] + self.result["msg"] = "Invalid site name or site not present" + self.module.fail_json(**self.result) + else: + _id = response.get("response")[0].get("id") + log(str(_id)) + + return _id + + + def pool_exists(self): + pool_exists = False + pool_details = {} + pool_id = None + response = None + name = None + + #get it from validated + + name = self.params.get("config")[0].get("GlobalPoolDetails").get("settings").get("ippool")[0].get("ipPoolName") + try: + + response = self.dnac._exec( + family = "network_settings", + function = "get_global_pool", + ) + log(str(response)) + if isinstance(response, dict): + if "response" in response: + response = response.get("response") + + current_details = get_dict_result(response, "ipPoolName", name) + log(str(current_details)) + if current_details: + pool_exists = True + pool_id = current_details.get("id") + elif self.config[0].get("GlobalPoolDetails").get("settings").get("ippool")[0].get("prev_name") != None: + pool_id = None + (pool_id, current_details) = self.get_pool_id_from_name(self.config[0].get("GlobalPoolDetails").get("settings").get("ippool")[0].get("prev_name")) + if pool_id == None: + msg = "Prev name doesn't exist\n" + self.module.fail_json(msg=msg) + pool_exists = True + current_details = get_dict_result(response, "id", pool_id) + log(str(current_details)) + pool_details = self.get_current_pool(current_details) + except Exception: + result = None + + log(str(pool_details)) + log(str(pool_id)) + return (pool_exists, pool_details, pool_id) + + + def res_exists(self): + current_details = None + res_exists = False + res_details = None + res_id = None + response = None + site_name = None + _id = "" + site_name = self.params.get("config")[0].get("ReservePoolDetails").get("siteName") + log(str(site_name)) + + if site_name != None: + site_id = self.get_site_id(site_name) + self.site_id = site_id + + name = self.config[0].get("ReservePoolDetails").get("name") + prev_name = self.config[0].get("ReservePoolDetails").get("prev_name") + + if prev_name: + if not self.params.get("config")[0].get("ReservePoolDetails").get("siteName"): + msg = "Mandatory Parameter siteName required\n" + self.module.fail_json(msg=msg) + _id = self.get_res_id_from_name(prev_name) + + log(str(_id)) + try: + response = self.dnac._exec( + family="network_settings", + function="get_reserve_ip_subpool", + params={"siteId":self.site_id} + ) + if isinstance(response, dict): + if "response" in response: + response = response.get("response") + log(str(response)) + + if _id: + current_details = get_dict_result(response, "id", _id) + elif name: + current_details = get_dict_result(response, "groupName", name) + # o_id = current_details.get("id") + + + + # if name and _id and _id != o_id: + # msg = "Name and Id does belong to the same object\n" + # self.module.fail_json(msg=msg) + + log(str(current_details)) + + if current_details: + res_exists = True + res_id = current_details.get("id") + res_details = self.get_current_res(current_details) + except Exception: + result = None + + log(str(res_details)) + log(str(res_id)) + return (res_exists, res_details, res_id) + + + def get_have(self): + pool_exists = False + pool_details = None + pool_id = None + have = dict() + res_exists = False + res_details = None + res_id = None + have_reserve = dict() + #checking if the pool is already exists or not + + if self.params.get("config")[0].get("GlobalPoolDetails") != None: + (pool_exists, pool_details, pool_id) = self.pool_exists() + + if self.log: + log("pool Exists: " + str(pool_exists) + "\n Current Site: " + str(pool_details)) + + if pool_exists: + have["pool_id"] = pool_id + have["pool_exists"] = pool_exists + have["pool_details"] = pool_details + log(str(pool_details)) + + + self.have = have + + if self.params.get("config")[0].get("ReservePoolDetails") != None: + (res_exists, res_details, res_id) = self.res_exists() + + if self.log: + log("Reservation Exists: " + str(res_exists) + "\n Reserved Pool: " + str(res_details)) + + + if res_exists: + have_reserve["res_exists"] = res_exists + have_reserve["res_id"] = res_id + have_reserve["res_details"] = res_details + if have_reserve.get("res_details").get("ipv6AddressSpace") == "False": + have_reserve.get("res_details").update({"ipv6AddressSpace": False}) + elif have_reserve.get("res_details").get("ipv6AddressSpace") == "True": + have_reserve.get("res_details").update({"ipv6AddressSpace": True}) + + + self.have_reserve = have_reserve + + + def get_want(self): + if self.params.get("config")[0].get("GlobalPoolDetails") != None: + want = {} + IpAddressSpace = self.params.get("config")[0].get("GlobalPoolDetails").get("settings").get("ippool")[0] + dhcpServerIps = self.params.get("config")[0].get("GlobalPoolDetails").get("settings").get("ippool")[0] + dnsServerIps = self.params.get("config")[0].get("GlobalPoolDetails").get("settings").get("ippool")[0] + gateway = self.params.get("config")[0].get("GlobalPoolDetails").get("settings").get("ippool")[0] + ipPoolCidr = self.params.get("config")[0].get("GlobalPoolDetails").get("settings").get("ippool")[0] + ipPoolName = self.params.get("config")[0].get("GlobalPoolDetails").get("settings").get("ippool")[0] + _type = self.params.get("config")[0].get("GlobalPoolDetails").get("settings").get("ippool")[0] + + want = dict( + settings = dict( + ippool = [dict( + IpAddressSpace = IpAddressSpace.get("IpAddressSpace"), + dhcpServerIps = dhcpServerIps.get("dhcpServerIps"), + dnsServerIps = dnsServerIps.get("dnsServerIps"), + gateway = gateway.get("gateway"), + ipPoolCidr = ipPoolCidr.get("ipPoolCidr"), + ipPoolName = ipPoolName.get("ipPoolName"), + type = _type.get("type"), + )] + ) + ) + log(str(self.have)) + if not self.have.get("pool_exists"): + if want.get("settings").get("ippool")[0].get("dhcpServerIps") == None: + want.get("settings").get("ippool")[0].update({"dhcpServerIps": []}) + if want.get("settings").get("ippool")[0].get("dnsServerIps") == None: + want.get("settings").get("ippool")[0].update({"dnsServerIps": []}) + if want.get("settings").get("ippool")[0].get("IpAddressSpace") == None: + want.get("settings").get("ippool")[0].update({"IpAddressSpace": ""}) + if want.get("settings").get("ippool")[0].get("gateway") == None: + want.get("settings").get("ippool")[0].update({"gateway": ""}) + if want.get("settings").get("ippool")[0].get("type") == None: + want.get("settings").get("ippool")[0].update({"type": "generic"}) + + + else: + if self.have.get("pool_details").get("settings").get("ippool")[0].get("IpAddressSpace") == "IPv4": + want.get("settings").get("ippool")[0].update({"IpAddressSpace": "IPv4"}) + log("true") + elif self.have.get("pool_details").get("settings").get("ippool")[0].get("IpAddressSpace") == "Ipv6": + want.get("settings").get("ippool")[0].update({"IpAddressSpace": "IPv6"}) + log("false") + ## want.get("settings").get("ippool")[0].update({"IpAddressSpace": "IPv6"}) + want.get("settings").get("ippool")[0].update({"type": self.have.get("pool_details").get("settings").get("ippool")[0].get("ipPoolType")}) + want.get("settings").get("ippool")[0].update({"ipPoolCidr": self.have.get("pool_details").get("settings").get("ippool")[0].get("ipPoolCidr")}) + + if want.get("settings").get("ippool")[0].get("dhcpServerIps") == None and self.have.get("pool_details").get("settings").get("ippool")[0].get("dhcpServerIps") != None: + want.get("settings").get("ippool")[0].update({"dhcpServerIps": self.have.get("pool_details").get("settings").get("ippool")[0].get("dhcpServerIps")}) + if want.get("settings").get("ippool")[0].get("dnsServerIps") == None and self.have.get("pool_details").get("settings").get("ippool")[0].get("dnsServerIps") != None: + want.get("settings").get("ippool")[0].update({"dnsServerIps": self.have.get("pool_details").get("settings").get("ippool")[0].get("dnsServerIps")}) + if want.get("settings").get("ippool")[0].get("gateway") == None and self.have.get("pool_details").get("settings").get("ippool")[0].get("gateway") != None: + want.get("settings").get("ippool")[0].update({"gateway": self.have.get("pool_details").get("settings").get("ippool")[0].get("gateway")}) + + + log(str(want)) + self.want = want + + if self.params.get("config")[0].get("ReservePoolDetails") != None: + + want_reserve = dict( + name = self.params.get("config")[0].get("ReservePoolDetails").get("name"), + type = self.params.get("config")[0].get("ReservePoolDetails").get("type"), + ipv6AddressSpace = self.params.get("config")[0].get("ReservePoolDetails").get("ipv6AddressSpace"), + ipv4GlobalPool = self.params.get("config")[0].get("ReservePoolDetails").get("ipv4GlobalPool"), + ipv4Prefix = self.params.get("config")[0].get("ReservePoolDetails").get("ipv4Prefix"), + ipv4PrefixLength = self.params.get("config")[0].get("ReservePoolDetails").get("ipv4PrefixLength"), + ipv4GateWay = self.params.get("config")[0].get("ReservePoolDetails").get("ipv4GateWay"), + ipv4DhcpServers = self.params.get("config")[0].get("ReservePoolDetails").get("ipv4DhcpServers"), + ipv4DnsServers = self.params.get("config")[0].get("ReservePoolDetails").get("ipv4DnsServers"), + ipv6GlobalPool = self.params.get("config")[0].get("ReservePoolDetails").get("ipv6GlobalPool"), + ipv6Prefix = self.params.get("config")[0].get("ReservePoolDetails").get("ipv6Prefix"), + ipv6PrefixLength = self.params.get("config")[0].get("ReservePoolDetails").get("ipv6PrefixLength"), + ipv6GateWay = self.params.get("config")[0].get("ReservePoolDetails").get("ipv6GateWay"), + ipv6DhcpServers = self.params.get("config")[0].get("ReservePoolDetails").get("ipv6DhcpServers"), + ipv6DnsServers = self.params.get("config")[0].get("ReservePoolDetails").get("ipv6DnsServers"), + ipv4TotalHost = self.params.get("config")[0].get("ReservePoolDetails").get("ipv4TotalHost"), + ipv6TotalHost = self.params.get("config")[0].get("ReservePoolDetails").get("ipv6TotalHost") + ) + + log(str(self.have_reserve)) + if not self.have_reserve: + if want_reserve.get("type") == None: + want_reserve.update({"type": generic}) + if want_reserve.get("ipv4GateWay") == None: + want_reserve.update({"ipv4GateWay": ""}) + if want_reserve.get("ipv4DhcpServers") == None: + want_reserve.update({"ipv4DhcpServers": []}) + if want_reserve.get("ipv4DnsServers") == None: + want_reserve.update({"ipv4DnsServers": []}) + if want_reserve.get("ipv6AddressSpace") == None: + want_reserve.update({"ipv6AddressSpace": False}) + if want_reserve.get("slaacSupport") == None: + want_reserve.update({"slaacSupport": True}) + if want_reserve.get("ipv4TotalHost") == None: + del want_reserve['ipv4TotalHost'] + if want_reserve.get("ipv6Prefix") == None and want_reserve.get("ipv6AddressSpace") == True: + want_reserve.update({"ipv6Prefix": True}) + else: + del want_reserve['ipv6Prefix'] + if want_reserve.get("ipv6AddressSpace") == False: + if want_reserve.get("ipv6GlobalPool") == None: + del want_reserve['ipv6GlobalPool'] + if want_reserve.get("ipv6PrefixLength") == None: + del want_reserve['ipv6PrefixLength'] + if want_reserve.get("ipv6GateWay") == None: + del want_reserve['ipv6GateWay'] + if want_reserve.get("ipv6DhcpServers") == None: + del want_reserve['ipv6DhcpServers'] + if want_reserve.get("ipv6DnsServers") == None: + del want_reserve['ipv6DnsServers'] + if want_reserve.get("ipv6TotalHost") == None: + del want_reserve['ipv6TotalHost'] + + else: + del want_reserve['type'] + del want_reserve['ipv4GlobalPool'] + del want_reserve['ipv4Prefix'] + del want_reserve['ipv4PrefixLength'] + del want_reserve['ipv4TotalHost'] + # want_reserve.update({"ipv6AddressSpace": "False"}) + + self.want_reserve = want_reserve + + + def get_execution_details(self, execid): + response = None + response = self.dnac._exec( + family="task", + function='get_business_api_execution_details', + params={"execution_id": execid} + ) + + if self.log: + log(str(response)) + + if response and isinstance(response, dict): + return response + + + def get_diff_merge(self): + if self.params.get("config")[0].get("GlobalPoolDetails") != None: + + if not self.params.get("config")[0].get("GlobalPoolDetails").get("settings").get("ippool")[0].get("ipPoolName"): + msg = "Mandatory Parameter ipPoolName required\n" + self.module.fail_json(msg=msg) + pool_updated = False + pool_created = False + + if self.have.get("pool_exists"): + log("entered") + obj_params = [ + ("settings", "settings"), + ] + if self.requires_update(self.have.get("pool_details"), self.want, obj_params): + log("Pool update requires") + #Pool Exists + pool_params = copy.deepcopy(self.want) + pool_params.get("settings").get("ippool")[0].update({"id": self.have.get("pool_id")}) + log(str(self.want)) + log(str(pool_params)) + del pool_params["settings"]["ippool"][0]["IpAddressSpace"] + del pool_params["settings"]["ippool"][0]["ipPoolCidr"] + del pool_params["settings"]["ippool"][0]["type"] + + if pool_params.get("settings").get("ippool")[0].get("dhcpServerIps") == None: + pool_params.get("settings").get("ippool")[0].update({"dhcpServerIps" : self.have.get("pool_details").get("settings").get("ippool")[0].get("dhcpServerIps")}) + if pool_params.get("settings").get("ippool")[0].get("dnsServerIps") == None: + pool_params.get("settings").get("ippool")[0].update({"dnsServerIps" : self.have.get("pool_details").get("settings").get("ippool")[0].get("dnsServerIps")}) + if pool_params.get("settings").get("ippool")[0].get("gateway") == None: + pool_params.get("settings").get("ippool")[0].update({"gateway" : self.have.get("pool_details").get("settings").get("ippool")[0].get("gateway")}) + + log(str(pool_params)) + log(str(self.have)) + response = self.dnac._exec( + family = "network_settings", + function = "update_global_pool", + params = pool_params, + op_modifies = True, + ) + + pool_updated = True + log(str(pool_updated)) + + else: + log("Pool doesn't requires an update") + self.result["response"] = self.have.get("settings") + self.result["msg"] = "Pool doesn't requires an update" + self.module.exit_json(**self.result) + + else: + #creating New Pool + pool_params = self.want + log(str(pool_params)) + response = self.dnac._exec( + family="network_settings", + function="create_global_pool", + params = pool_params, + op_modifies = True, + ) + log("PoolCreated") + log(str(response)) + pool_created = True + + if pool_created or pool_updated: + if response and isinstance(response, dict): + executionid = response.get("executionId") + + while True: + execution_details = self.get_execution_details(executionid) + if execution_details.get("status") == "SUCCESS": + self.result['changed'] = True + self.result['response'] = execution_details + break + + elif execution_details.get("bapiError"): + + self.module.fail_json(msg=execution_details.get("bapiError"), + response=execution_details) + break + + if pool_updated: + log("Pool Updated Successfully") + self.result['msg'] = "Pool Updated Successfully" + self.result['response'].update({"Id": self.have.get("pool_details").get("id")}) + + elif pool_created: + log("Pool Created Successfully") + (pool_exists, pool_details, pool_id) = self.pool_exists() + self.result['response'].update({"Id": pool_id}) + self.result['msg'] = "Pool Created Successfully" + else: + log("Pool doesn't need a update") + self.result['msg'] = "Pool doesn't requires an update" + self.result['response'].update({"Id": self.have.get("pool_details").get("id")}) + + if self.params.get("config")[0].get("ReservePoolDetails") != None: + + res_updated = False + res_created = False + log(str(self.have_reserve.get("res_details"))) + log(str(self.want_reserve)) + if self.have_reserve: + log("entered") + obj_params = [ + ("name", "name"), + ("type", "type"), + ("ipv6AddressSpace", "ipv6AddressSpace"), + ("ipv4GlobalPool", "ipv4GlobalPool"), + ("ipv4Prefix", "ipv4Prefix"), + ("ipv4PrefixLength", "ipv4PrefixLength"), + ("ipv4GateWay", "ipv4GateWay"), + ("ipv4DhcpServers", "ipv4DhcpServers"), + ("ipv4DnsServers", "ipv4DnsServers"), + ("ipv6GateWay", "ipv6GateWay"), + ("ipv6DhcpServers", "ipv6DhcpServers"), + ("ipv6DnsServers", "ipv6DnsServers"), + ("ipv4TotalHost", "ipv4TotalHost"), + ("slaacSupport", "slaacSupport") + ] + + if self.requires_update(self.have_reserve.get("res_details"), self.want_reserve, obj_params): + log("Pool update requires") + #Pool Exists + log(str(self.have_reserve)) + log(str(self.want_reserve)) + + # if not self.site_id: + # self.module.fail_json(msg="Mandatory parameter siteName not present or invalid", response=[]) + res_params = copy.deepcopy(self.want_reserve) + res_params.update({"site_id": self.site_id}) + res_params.update({"id": self.have_reserve.get("res_id")}) + response = self.dnac._exec( + family="network_settings", + function="update_reserve_ip_subpool", + params=res_params, + ) + + log("Reservation Updated") + log(str(response)) + res_updated = True + + else: + log("Reserved ip subpool doesn't requires an update") + self.result["response"] = self.have.get("ReservePoolDetails") + self.result["msg"] = "Reserved ip subpool doesn't requires an update" + self.module.exit_json(**self.result) + + else: + #creating New Pool + res_params = self.want_reserve + log(str(res_params)) + if not self.want_reserve.get("name") or not self.want_reserve.get("ipv4GlobalPool") or not self.want_reserve.get("ipv4PrefixLength") or not self.site_id: + self.module.fail_json(msg="missing parameter name or ipv4GlobalPool or ipv4PrefixLength or siteName", response=[]) + + res_params.update({"site_id": self.site_id}) + log(str(res_params)) + response = self.dnac._exec( + family="network_settings", + function="reserve_ip_subpool", + params=res_params, + ) + log("Reservation Created") + log(str(response)) + res_created = True + + if res_created or res_updated: + if response and isinstance(response, dict): + executionid = response.get("executionId") + + while True: + execution_details = self.get_execution_details(executionid) + if execution_details.get("status") == "SUCCESS": + self.result['changed'] = True + self.result['response'] = execution_details + break + + elif execution_details.get("bapiError"): + + self.module.fail_json(msg=execution_details.get("bapiError"), + response=execution_details) + break + + if res_updated: + log("Reserved Ip Subpool Updated Successfully") + self.result['msg'] = "Reserved Ip Subpool Updated Successfully" + self.result['response'].update({"Reservation details": self.have.get("res_details")}) + + elif res_created: + log("Ip Subpool Reservation Created Successfully") + (res_exists, res_details, res_id) = self.res_exists() + self.result['response'].update({"Reservation details": self.have.get("res_details")}) + self.result['msg'] = "Ip Subpool Reservation Created Successfully" + else: + log("Ip Subpool Reservation doesn't need a update") + self.result['msg'] = "Ip Subpool Reservation doesn't requires an update" + self.result['response'].update({"Reservation details": self.have.get("res_details")}) + + + def get_id_by_name(self, name): + id = None + try: + response = self.dnac._exec( + family="network_settings", + function="get_reserve_ip_subpool", + params={"siteId":self.site_id}, + ) + + log(str(response)) + + if isinstance(response, dict): + if "response" in response: + response = response.get("response") + log(str(response)) + + + current_details = get_dict_result(response, "groupName", name) + if current_details: + id = current_details.get("id") + + except: + result = None + + return id + + + def get_diff_delete(self): + + if self.params.get("config")[0].get("ReservePoolDetails") != None: + res_exists = self.have_reserve.get("res_exists") + log(str(res_exists)) + id = None + if self.want_reserve.get("name"): + log(str(self.want_reserve.get("name"))) + id = self.get_id_by_name(self.want_reserve.get("name")) + log(str(id)) + if res_exists: + if not id: + self.module.fail_json(msg="missing or incorrect parameter reserved pool name", response=[]) + log(str(self.have_reserve.get("res_id"))) + response = self.dnac._exec( + family="network_settings", + function="release_reserve_ip_subpool", + params={"id": id}, + ) + + if response and isinstance(response, dict): + executionid = response.get("executionId") + while True: + execution_details = self.get_execution_details(executionid) + if execution_details.get("status") == "SUCCESS": + self.result['changed'] = True + self.result['response'] = execution_details + log(str(response)) + self.result['msg'] = "Ip subpool reservation released successfully" + break + + elif execution_details.get("bapiError"): + self.module.fail_json(msg=execution_details.get("bapiError"), + response=execution_details) + break + + else: + self.module.fail_json(msg="Reserved Ip Subpool Not Found", response=[]) + + if self.params.get("config")[0].get("GlobalPoolDetails") != None: + pool_exists = self.have.get("pool_exists") + + if pool_exists: + response = self.dnac._exec( + family="network_settings", + function="delete_global_ip_pool", + params={"id": self.have.get("pool_id")}, + ) + + if response and isinstance(response, dict): + executionid = response.get("executionId") + while True: + execution_details = self.get_execution_details(executionid) + if execution_details.get("status") == "SUCCESS": + self.result['changed'] = True + self.result['response'] = execution_details + log(str(response)) + self.result['response'].update({"Id": self.have.get("pool_details").get("id")}) + self.result['msg'] = "Pool deleted successfully" + break + + elif execution_details.get("bapiError"): + self.module.fail_json(msg=execution_details.get("bapiError"), + response=execution_details) + break + + else: + self.module.fail_json(msg="Pool Not Found", response=[]) + + + +def main(): + """main entry point for module execution""" + + element_spec = dict( + dnac_host=dict(required=True, type="str"), + dnac_port=dict(type="str", default="443"), + dnac_username=dict(type="str", default="admin", aliases=["user"]), + dnac_password=dict(type="str", no_log=True), + dnac_verify=dict(type="bool", default="True"), + dnac_version=dict(type="str", default="2.2.3.3"), + dnac_debug=dict(type="bool", default=False), + dnac_log=dict(type="bool", default=False), + validate_response_schema=dict(type="bool", default=True), + config=dict(required=True, type="list", elements="dict"), + state=dict(default="merged", choices=["merged", "deleted"]), + ) + + module = AnsibleModule(argument_spec=element_spec, supports_check_mode=False) + + dnac_network = DnacNetwork(module) + + state = dnac_network.get_state() + dnac_network.validate_input() + + dnac_network.get_have() + dnac_network.get_want() + + if state == "merged": + dnac_network.get_diff_merge() + + elif state == "deleted": + dnac_network.get_diff_delete() + log(str(dnac_network.result)) + + module.exit_json(**dnac_network.result) + + +if __name__ == "__main__": + main() From abfd282e9e10dd37666e0040ad963ce5cda32f20 Mon Sep 17 00:00:00 2001 From: Muthu Rakesh <19cs127@psgitech.ac.in> Date: Fri, 30 Jun 2023 11:00:43 +0530 Subject: [PATCH 04/13] network setting modules global pool(full), reserve ip pool(full), network (partial) --- playbooks/network_intent.yml | 50 +- plugins/modules/network_intent.py | 803 ++++++++++++++++++++---------- 2 files changed, 579 insertions(+), 274 deletions(-) diff --git a/playbooks/network_intent.yml b/playbooks/network_intent.yml index bf3ae95ecf..b0c2d5484b 100644 --- a/playbooks/network_intent.yml +++ b/playbooks/network_intent.yml @@ -9,7 +9,7 @@ # - name: Create, update, delete global pool and reserve an ip pool - cisco.dnac.network_intent: + cisco.dnac.sample_module: dnac_host: "{{ dnac_host }}" dnac_port: "{{ dnac_port }}" dnac_username: "{{ dnac_username }}" @@ -22,23 +22,61 @@ - GlobalPoolDetails: settings: ippool: - - ipPoolName: Global_Pool + - ipPoolName: Global_Pool1 gateway: "" #use this for updating IpAddressSpace: IPv4 #required when we are creating - ipPoolCidr: 90.0.0.0/8 #required when we are creating - type: generic + ipPoolCidr: 100.0.0.0/8 #required when we are creating + type: Generic dhcpServerIps: [] #use this for updating dnsServerIps: [] #use this for updating # prev_name: Global_Pool ReservePoolDetails: ipv6AddressSpace: false - ipv4GlobalPool: 90.0.0.0/8 + ipv4GlobalPool: 100.0.0.0/8 ipv4Prefix: true ipv4PrefixLength: 8 ipv4DnsServers: [] - name: IP_Pool_4 + name: IP_Pool_3 siteName: Global/Chennai/Trill slaacSupport: true # prev_name: IP_Pool_4 type: LAN + NetworkManagementDetails: + settings: + dhcpServer: + - 10.0.0.1 + dnsServer: + domainName: cisco.co + primaryIpAddress: 10.0.0.2 + secondaryIpAddress: 10.0.0.3 + # clientAndEndpoint_aaa: #works only if we system settigns is set + # # ipAddress: string #Mandatory for ISE, sec ip for AAA + # network: 10.0.0.9 + # protocol: RADIUS + # servers: AAA + # # sharedSecret: string #ISE + messageOfTheday: + bannerMessage: hello + retainExistingBanner: "true" + netflowcollector: + ipAddress: 10.0.0.4 + port: 443 + # network_aaa: #works only if we system settigns is set + # # ipAddress: string #Mandatory for ISE, sec ip for AAA + # network: 10.0.0.8 + # protocol: RADIUS + # servers: AAA + # # sharedSecret: string #ISE + ntpServer: + - 10.0.0.5 + snmpServer: + configureDnacIP: true + ipAddresses: + - 10.0.0.6 + syslogServer: + configureDnacIP: true + ipAddresses: + - 10.0.0.7 + timezone: GMT + siteName: Global/Chennai diff --git a/plugins/modules/network_intent.py b/plugins/modules/network_intent.py index be7515e897..32d1116a65 100644 --- a/plugins/modules/network_intent.py +++ b/plugins/modules/network_intent.py @@ -1,4 +1,5 @@ +# This module will work for global_pool, Reserve_ip_pool and network (under network it will not work for network_aaa and clientEndpoint_aaa) import copy @@ -30,6 +31,8 @@ def __init__(self, module): self.want = {} self.have_reserve = {} self.want_reserve = {} + self.have_net = {} + self.want_net = {} self.site_id = None self.validated = [] dnac_params = self.get_dnac_params(self.params) @@ -39,52 +42,62 @@ def __init__(self, module): self.result = dict(changed=False, diff=[], response=[], warnings=[]) - def get_state(self): return self.params.get("state") - def validate_input(self): - - temp_spec = dict( - IpAddressSpace = dict(required = False, type="string"), - dhcpServerIps = dict(required = False, type="list"), - dnsServerIps = dict(required = False, type="list"), - gateway = dict(required = False, type="string"), - ipPoolCidr = dict(required = False, type="string"), - ipPoolName = dict(required = False, type="string"), - name = dict(required = False, type="string"), - prev_name = dict(required = False, type="string"), - type = dict(required = False, type = "string", choices=["generic", "tunnel", "LAN", "WAN", "management", "service"]), - ipv6AddressSpace = dict(required = False, type = "string"), - ipv4GlobalPool = dict(required = False, type = "string"), - ipv4Prefix = dict(required = False, type = "string"), - ipv4PrefixLength = dict(required = False, type = "integer"), - ipv4GateWay = dict(required = False, type = "string"), - ipv4DhcpServers = dict(required = False, type = "list"), - ipv4DnsServers = dict(required =False, type = "list"), - ipv6GlobalPool = dict(required = False, type = "string"), - ipv6Prefix = dict(required = False, type = "string"), - ipv6PrefixLength = dict(required = False, type = "integer"), - ipv6GateWay = dict(required = False, type = "string"), - ipv6DhcpServers = dict(required = False, type = "list"), - ipv6DnsServers = dict(required = False, type = "list"), - ipv4TotalHost = dict(required = False, type = "integer"), - ipv6TotalHost = dict(required = False, type = "integer"), - slaacSupport = dict(required = False, type = "string"), - siteName = dict(required = False, type = "string") - - ) + temp_spec = { + "IpAddressSpace": {"required": False, "type": 'string'}, + "dhcpServerIps": {"required": False, "type": 'list'}, + "dnsServerIps": {"required": False, "type": 'list'}, + "gateway": {"required": False, "type": 'string'}, + "ipPoolCidr": {"required": False, "type": 'string'}, + "ipPoolName": {"required": False, "type": 'string'}, + "name": {"required": False, "type": 'string'}, + "prev_name": {"required": False, "type": 'string'}, + "type": {"required": False, "type": "string", \ + "choices": ["Generic", "tunnel", "LAN", "WAN", "management", "service"]}, + "ipv6AddressSpace": {"required": False, "type": 'string'}, + "ipv4GlobalPool": {"required": False, "type": 'string'}, + "ipv4Prefix": {"required": False, "type": 'string'}, + "ipv4PrefixLength": {"required": False, "type": 'string'}, + "ipv4GateWay": {"required": False, "type": 'string'}, + "ipv4DhcpServers": {"required": False, "type": 'list'}, + "ipv4DnsServers": {"required": False, "type": 'list'}, + "ipv6GlobalPool": {"required": False, "type": 'string'}, + "ipv6Prefix": {"required": False, "type": 'string'}, + "ipv6PrefixLength": {"required": False, "type": 'integer'}, + "ipv6GateWay": {"required": False, "type": 'string'}, + "ipv6DhcpServers": {"required": False, "type": 'list'}, + "ipv6DnsServers": {"required": False, "type": 'list'}, + "ipv4TotalHost": {"required": False, "type": 'integer'}, + "ipv6TotalHost": {"required": False, "type": 'integet'}, + "slaacSupport": {"required": False, "type": 'string'}, + "siteName": {"required": False, "type": 'string'}, + "dhcpServer": {"required": False, "type": 'list'}, + "domainName": {"required": False, "type": 'string'}, + "primaryIpAddress": {"required": False, "type": 'string'}, + "secondaryIpAddress": {"required": False, "type": 'string'} + } if self.config: msg = None temp = [] temp1 = [] + temp2 = [] # Validate template params - if self.config[0].get("GlobalPoolDetails") != None: + if self.config[0].get("GlobalPoolDetails") is not None: temp = self.config[0].get("GlobalPoolDetails").get("settings").get("ippool") - - if self.config[0].get("ReservePoolDetails") != None: + if self.config[0].get("ReservePoolDetails") is not None: temp1 = [self.config[0].get("ReservePoolDetails")] + if self.config[0].get("NetworkManagementDetails") is not None: + temp2.append(self.config[0].get("NetworkManagementDetails") \ + .get("settings").get("dhcpServer")) + temp2.append(self.config[0].get("NetworkManagementDetails") \ + .get("settings").get("dnsServer").get("domainName")) + temp2.append(self.config[0].get("NetworkManagementDetails") \ + .get("settings").get("dnsServer").get("primaryIpAddress")) + temp2.append(self.config[0].get("NetworkManagementDetails") \ + .get("settings").get("dnsServer").get("secondaryIpAddress")) temp = temp + temp1 valid_temp, invalid_params = validate_list_of_dicts( @@ -101,18 +114,16 @@ def validate_input(self): if self.log: log(str(valid_temp)) log(str(self.result)) -## log(str(self.validated)) log(str(self.validated)) - if self.params.get("config")[0].get("GlobalPoolDetails") != None: + if self.params.get("config")[0].get("GlobalPoolDetails") is not None: for temp in self.validated: log(str(temp)) - ## self.params.get("config")[0].get("GlobalPoolDetails").get("settings").get("ippool")[0] - if self.params.get("config")[0].get("GlobalPoolDetails").get("ipPoolName") != None: + if self.params.get("config")[0].get("GlobalPoolDetails") \ + .get("ipPoolName") is not None: msg = "missing required arguments: ipPoolName" self.module.fail_json(msg=msg) - def get_dnac_params(self, params): dnac_params = dict( dnac_host=params.get("dnac_host"), @@ -131,18 +142,17 @@ def requires_update(self, have, want, obj_params): requested_obj = want log(str(current_obj)) log(str(requested_obj)) - - + return any(not dnac_compare_equality(current_obj.get(dnac_param), - requested_obj.get(ansible_param)) + requested_obj.get(ansible_param)) for(dnac_param, ansible_param) in obj_params) def get_pool_id_from_name(self, pool_name): pool_id = None current_details = None + try: - response = self.dnac._exec( family = "network_settings", function = "get_global_pool", @@ -151,20 +161,20 @@ def get_pool_id_from_name(self, pool_name): if isinstance(response, dict): if "response" in response: response = response.get("response") - log(str(response)) + log(str(response)) current_details = get_dict_result(response, "ipPoolName", pool_name) log(str(current_details)) if current_details: pool_id = current_details.get("id") - + except: result = None return (pool_id, current_details) - + def get_res_id_from_name(self, res_name): - id = "" + _id = "" current_details = None try: response = self.dnac._exec( @@ -176,32 +186,32 @@ def get_res_id_from_name(self, res_name): if isinstance(response, dict): if "response" in response: response = response.get("response") - log(str(response)) + log(str(response)) current_details = get_dict_result(response, "groupName", res_name) log(str(current_details)) - id = current_details.get("id") + _id = current_details.get("id") except: log("except") result = None - return id + return _id def get_current_pool(self, pool): log(str(pool)) - pool_values = dict( - settings = dict( - ippool = [dict( - dhcpServerIps = pool.get("dhcpServerIps"), - dnsServerIps = pool.get("dnsServerIps"), - ipPoolCidr = pool.get("ipPoolCidr"), - ipPoolName = pool.get("ipPoolName"), - type = pool.get("type"), - )] - ) - ) + pool_values = { + "settings": { + "ippool": [{ + "dhcpServerIps": pool.get("dhcpServerIps"), + "dnsServerIps": pool.get("dnsServerIps"), + "ipPoolCidr": pool.get("ipPoolCidr"), + "ipPoolName": pool.get("ipPoolName"), + "type": pool.get("type") + }] + } + } log(str(pool_values)) - if pool.get("ipv6") == False: + if pool.get("ipv6") is False: pool_values.get("settings").get("ippool")[0].update({"IpAddressSpace": "IPv4"}) log("ipv6 - false") else: @@ -210,7 +220,8 @@ def get_current_pool(self, pool): if not pool["gateways"]: pool_values.get("settings").get("ippool")[0].update({"gateway": ""}) else: - pool_values.get("settings").get("ippool")[0].update({"gateway": pool.get("gateways")[0]}) + pool_values.get("settings").get("ippool")[0] \ + .update({"gateway": pool.get("gateways")[0]}) return pool_values @@ -220,7 +231,7 @@ def get_current_res(self, res): res_values = dict( name = res.get("groupName"), site_id = res.get("siteId"), - ) + ) if len(res.get("ipPools")) == 1: res_values.update({"ipv4DhcpServers": res.get("ipPools")[0].get("dhcpServerIps")}) @@ -229,7 +240,7 @@ def get_current_res(self, res): res_values.update({"ipv6AddressSpace": "False"}) elif len(res.get("ipPools")) == 2: - if res.get("ipPools")[0].get("ipv6") == False: + if res.get("ipPools")[0].get("ipv6") is False: res_values.update({"ipv4DhcpServers": res.get("ipPools")[0].get("dhcpServerIps")}) res_values.update({"ipv4DnsServers": res.get("ipPools")[0].get("dnsServerIps")}) res_values.update({"ipv4GateWay": res.get("ipPools")[0].get("gateways")[0]}) @@ -238,7 +249,7 @@ def get_current_res(self, res): res_values.update({"ipv4DnsServers": res.get("ipPools")[1].get("dnsServerIps")}) res_values.update({"ipv4GateWay": res.get("ipPools")[1].get("gateways")[0]}) - elif res.get("ipPools")[1].get("ipv6") == False: + elif res.get("ipPools")[1].get("ipv6") is False: res_values.update({"ipv4DhcpServers": res.get("ipPools")[1].get("dhcpServerIps")}) res_values.update({"ipv4DnsServers": res.get("ipPools")[1].get("dnsServerIps")}) res_values.update({"ipv4GateWay": res.get("ipPools")[1].get("gateways")[0]}) @@ -246,21 +257,87 @@ def get_current_res(self, res): res_values.update({"ipv4DhcpServers": res.get("ipPools")[0].get("dhcpServerIps")}) res_values.update({"ipv4DnsServers": res.get("ipPools")[0].get("dnsServerIps")}) res_values.update({"ipv4GateWay": res.get("ipPools")[0].get("gateways")[0]}) - + return res_values + + def get_current_net(self, site_id): + log(str(site_id)) + response = None + + try: + response = self.dnac._exec( + family="network_settings", + function='get_network', + params={"site_id": site_id} + ) + + except: + result = None + log(str(response)) + + if isinstance(response, dict): + if "response" in response: + response = response.get("response") + + dhcp_details = get_dict_result(response, "key", "dhcp.server") + dns_details = get_dict_result(response, "key", "dns.server") + snmp_details = get_dict_result(response, "key", "snmp.trap.receiver") + syslog_details = get_dict_result(response, "key", "syslog.server") + netflow_details = get_dict_result(response, "key", "netflow.collector") + ntpserver_details = get_dict_result(response, "key", "ntp.server") + timezone_details = get_dict_result(response, "key", "timezone.site") + messageoftheday_details = get_dict_result(response, "key", "device.banner") + + snmp_details + log(str(dhcp_details)) + log(str(dns_details)) + + net_values = { + "settings": { + "dhcpServer": dhcp_details.get("value"), + "dnsServer": { + "domainName": dns_details.get("value")[0].get("domainName"), + "primaryIpAddress": dns_details.get("value")[0].get("primaryIpAddress"), + "secondaryIpAddress": dns_details.get("value")[0].get("secondaryIpAddress") + }, + "snmpServer": { + "configureDnacIP": snmp_details.get("value")[0].get("configureDnacIP"), + "ipAddresses": snmp_details.get("value")[0].get("ipAddresses"), + }, + "syslogServer": { + "configureDnacIP": syslog_details.get("value")[0].get("configureDnacIP"), + "ipAddresses": syslog_details.get("value")[0].get("ipAddresses"), + }, + "netflowcollector": { + "ipAddress": netflow_details.get("value")[0].get("ipAddress"), + "port": netflow_details.get("value")[0].get("port"), + "configureDnacIP": netflow_details.get("value")[0].get("configureDnacIP"), + }, + "ntpServer": ntpserver_details.get("value"), + "timezone": timezone_details.get("value")[0], + "messageOfTheday": { + "bannerMessage": messageoftheday_details.get("value")[0].get("bannerMessage"), + "retainExistingBanner": messageoftheday_details.get("value")[0].get("retainExistingBanner"), + } + + + } + } + + return net_values + def get_site_id(self, site_name): response = {} _id = None - result = None try: response = self.dnac._exec( family="sites", function='get_site', params={"name":site_name}, ) - + except: result = None log(str(response)) @@ -285,27 +362,32 @@ def pool_exists(self): #get it from validated - name = self.params.get("config")[0].get("GlobalPoolDetails").get("settings").get("ippool")[0].get("ipPoolName") + name = self.params.get("config")[0].get("GlobalPoolDetails") \ + .get("settings").get("ippool")[0].get("ipPoolName") try: - + response = self.dnac._exec( family = "network_settings", function = "get_global_pool", ) - log(str(response)) + log(str(response)) if isinstance(response, dict): if "response" in response: response = response.get("response") - + current_details = get_dict_result(response, "ipPoolName", name) log(str(current_details)) if current_details: pool_exists = True pool_id = current_details.get("id") - elif self.config[0].get("GlobalPoolDetails").get("settings").get("ippool")[0].get("prev_name") != None: + elif self.config[0].get("GlobalPoolDetails").get("settings") \ + .get("ippool")[0].get("prev_name") is not None: + pool_id = None - (pool_id, current_details) = self.get_pool_id_from_name(self.config[0].get("GlobalPoolDetails").get("settings").get("ippool")[0].get("prev_name")) - if pool_id == None: + (pool_id, current_details) = self.get_pool_id_from_name(self.config[0]. \ + get("GlobalPoolDetails").get("settings").get("ippool")[0].get("prev_name")) + + if pool_id is None: msg = "Prev name doesn't exist\n" self.module.fail_json(msg=msg) pool_exists = True @@ -331,7 +413,7 @@ def res_exists(self): site_name = self.params.get("config")[0].get("ReservePoolDetails").get("siteName") log(str(site_name)) - if site_name != None: + if site_name is not None: site_id = self.get_site_id(site_name) self.site_id = site_id @@ -343,7 +425,7 @@ def res_exists(self): msg = "Mandatory Parameter siteName required\n" self.module.fail_json(msg=msg) _id = self.get_res_id_from_name(prev_name) - + log(str(_id)) try: response = self.dnac._exec( @@ -358,15 +440,8 @@ def res_exists(self): if _id: current_details = get_dict_result(response, "id", _id) - elif name: - current_details = get_dict_result(response, "groupName", name) - # o_id = current_details.get("id") - - - - # if name and _id and _id != o_id: - # msg = "Name and Id does belong to the same object\n" - # self.module.fail_json(msg=msg) + elif name: + current_details = get_dict_result(response, "groupName", name) log(str(current_details)) @@ -376,7 +451,7 @@ def res_exists(self): res_details = self.get_current_res(current_details) except Exception: result = None - + log(str(res_details)) log(str(res_id)) return (res_exists, res_details, res_id) @@ -386,14 +461,15 @@ def get_have(self): pool_exists = False pool_details = None pool_id = None - have = dict() + res_exists = False res_details = None res_id = None - have_reserve = dict() + #checking if the pool is already exists or not - if self.params.get("config")[0].get("GlobalPoolDetails") != None: + if self.params.get("config")[0].get("GlobalPoolDetails") is not None: + have = {} (pool_exists, pool_details, pool_id) = self.pool_exists() if self.log: @@ -404,17 +480,17 @@ def get_have(self): have["pool_exists"] = pool_exists have["pool_details"] = pool_details log(str(pool_details)) - - + self.have = have - - if self.params.get("config")[0].get("ReservePoolDetails") != None: + + if self.params.get("config")[0].get("ReservePoolDetails") is not None: + have_reserve = {} (res_exists, res_details, res_id) = self.res_exists() if self.log: - log("Reservation Exists: " + str(res_exists) + "\n Reserved Pool: " + str(res_details)) - - + log("Reservation Exists: " + str(res_exists) \ + + "\n Reserved Pool: " + str(res_details)) + if res_exists: have_reserve["res_exists"] = res_exists have_reserve["res_id"] = res_id @@ -423,125 +499,189 @@ def get_have(self): have_reserve.get("res_details").update({"ipv6AddressSpace": False}) elif have_reserve.get("res_details").get("ipv6AddressSpace") == "True": have_reserve.get("res_details").update({"ipv6AddressSpace": True}) - + self.have_reserve = have_reserve - + if self.params.get("config")[0].get("NetworkManagementDetails") is not None: + + have_net = {} + site_name = self.params.get("config")[0].get("NetworkManagementDetails").get("siteName") + + if site_name is None: + self.module.fail_json(msg="Mandatory Parameter siteName missings", response=[]) + + site_id_net = self.get_site_id(site_name) + + if site_id_net is None: + self.module.fail_json(msg="Invalid siteName", response=[]) + + have_net["site_id"] = site_id_net + have_net["net_details"] = self.get_current_net(site_id_net) + + self.have_net = have_net + + def get_want(self): - if self.params.get("config")[0].get("GlobalPoolDetails") != None: + if self.params.get("config")[0].get("GlobalPoolDetails") is not None: want = {} - IpAddressSpace = self.params.get("config")[0].get("GlobalPoolDetails").get("settings").get("ippool")[0] - dhcpServerIps = self.params.get("config")[0].get("GlobalPoolDetails").get("settings").get("ippool")[0] - dnsServerIps = self.params.get("config")[0].get("GlobalPoolDetails").get("settings").get("ippool")[0] - gateway = self.params.get("config")[0].get("GlobalPoolDetails").get("settings").get("ippool")[0] - ipPoolCidr = self.params.get("config")[0].get("GlobalPoolDetails").get("settings").get("ippool")[0] - ipPoolName = self.params.get("config")[0].get("GlobalPoolDetails").get("settings").get("ippool")[0] - _type = self.params.get("config")[0].get("GlobalPoolDetails").get("settings").get("ippool")[0] - - want = dict( - settings = dict( - ippool = [dict( - IpAddressSpace = IpAddressSpace.get("IpAddressSpace"), - dhcpServerIps = dhcpServerIps.get("dhcpServerIps"), - dnsServerIps = dnsServerIps.get("dnsServerIps"), - gateway = gateway.get("gateway"), - ipPoolCidr = ipPoolCidr.get("ipPoolCidr"), - ipPoolName = ipPoolName.get("ipPoolName"), - type = _type.get("type"), - )] - ) - ) + IpAddressSpace = self.params.get("config")[0] \ + .get("GlobalPoolDetails").get("settings").get("ippool")[0] + dhcpServerIps = self.params.get("config")[0] \ + .get("GlobalPoolDetails").get("settings").get("ippool")[0] + dnsServerIps = self.params.get("config")[0] \ + .get("GlobalPoolDetails").get("settings").get("ippool")[0] + gateway = self.params.get("config")[0] \ + .get("GlobalPoolDetails").get("settings").get("ippool")[0] + ipPoolCidr = self.params.get("config")[0] \ + .get("GlobalPoolDetails").get("settings").get("ippool")[0] + ipPoolName = self.params.get("config")[0] \ + .get("GlobalPoolDetails").get("settings").get("ippool")[0] + _type = self.params.get("config")[0] \ + .get("GlobalPoolDetails").get("settings").get("ippool")[0] + + want = { + "settings": { + "ippool": [{ + "IpAddressSpace": IpAddressSpace.get("IpAddressSpace"), + "dhcpServerIps": dhcpServerIps.get("dhcpServerIps"), + "dnsServerIps": dnsServerIps.get("dnsServerIps"), + "gateway": gateway.get("gateway"), + "ipPoolCidr": ipPoolCidr.get("ipPoolCidr"), + "ipPoolName": ipPoolName.get("ipPoolName"), + "type": _type.get("type"), + }] + } + } log(str(self.have)) if not self.have.get("pool_exists"): - if want.get("settings").get("ippool")[0].get("dhcpServerIps") == None: + if want.get("settings").get("ippool")[0].get("dhcpServerIps") is None: want.get("settings").get("ippool")[0].update({"dhcpServerIps": []}) - if want.get("settings").get("ippool")[0].get("dnsServerIps") == None: + if want.get("settings").get("ippool")[0].get("dnsServerIps") is None: want.get("settings").get("ippool")[0].update({"dnsServerIps": []}) - if want.get("settings").get("ippool")[0].get("IpAddressSpace") == None: + if want.get("settings").get("ippool")[0].get("IpAddressSpace") is None: want.get("settings").get("ippool")[0].update({"IpAddressSpace": ""}) - if want.get("settings").get("ippool")[0].get("gateway") == None: + if want.get("settings").get("ippool")[0].get("gateway") is None: want.get("settings").get("ippool")[0].update({"gateway": ""}) - if want.get("settings").get("ippool")[0].get("type") == None: - want.get("settings").get("ippool")[0].update({"type": "generic"}) + if want.get("settings").get("ippool")[0].get("type") is None: + want.get("settings").get("ippool")[0].update({"type": "Generic"}) - else: - if self.have.get("pool_details").get("settings").get("ippool")[0].get("IpAddressSpace") == "IPv4": + if self.have.get("pool_details").get("settings") \ + .get("ippool")[0].get("IpAddressSpace") == "IPv4": + want.get("settings").get("ippool")[0].update({"IpAddressSpace": "IPv4"}) log("true") - elif self.have.get("pool_details").get("settings").get("ippool")[0].get("IpAddressSpace") == "Ipv6": + + elif self.have.get("pool_details").get("settings") \ + .get("ippool")[0].get("IpAddressSpace") == "Ipv6": + want.get("settings").get("ippool")[0].update({"IpAddressSpace": "IPv6"}) log("false") - ## want.get("settings").get("ippool")[0].update({"IpAddressSpace": "IPv6"}) - want.get("settings").get("ippool")[0].update({"type": self.have.get("pool_details").get("settings").get("ippool")[0].get("ipPoolType")}) - want.get("settings").get("ippool")[0].update({"ipPoolCidr": self.have.get("pool_details").get("settings").get("ippool")[0].get("ipPoolCidr")}) - - if want.get("settings").get("ippool")[0].get("dhcpServerIps") == None and self.have.get("pool_details").get("settings").get("ippool")[0].get("dhcpServerIps") != None: - want.get("settings").get("ippool")[0].update({"dhcpServerIps": self.have.get("pool_details").get("settings").get("ippool")[0].get("dhcpServerIps")}) - if want.get("settings").get("ippool")[0].get("dnsServerIps") == None and self.have.get("pool_details").get("settings").get("ippool")[0].get("dnsServerIps") != None: - want.get("settings").get("ippool")[0].update({"dnsServerIps": self.have.get("pool_details").get("settings").get("ippool")[0].get("dnsServerIps")}) - if want.get("settings").get("ippool")[0].get("gateway") == None and self.have.get("pool_details").get("settings").get("ippool")[0].get("gateway") != None: - want.get("settings").get("ippool")[0].update({"gateway": self.have.get("pool_details").get("settings").get("ippool")[0].get("gateway")}) - - + + want.get("settings").get("ippool")[0].update({"type": self.have. \ + get("pool_details").get("settings").get("ippool")[0].get("ipPoolType")}) + want.get("settings").get("ippool")[0].update({"ipPoolCidr": \ + self.have.get("pool_details").get("settings") \ + .get("ippool")[0].get("ipPoolCidr")}) + + if want.get("settings").get("ippool")[0].get("dhcpServerIps") is None and \ + self.have.get("pool_details").get("settings") \ + .get("ippool")[0].get("dhcpServerIps") is not None: + want.get("settings").get("ippool")[0].update({"dhcpServerIps": \ + self.have.get("pool_details").get("settings") \ + .get("ippool")[0].get("dhcpServerIps")}) + + if want.get("settings").get("ippool")[0].get("dnsServerIps") is None and \ + self.have.get("pool_details").get("settings") \ + .get("ippool")[0].get("dnsServerIps") is not None: + + want.get("settings").get("ippool")[0].update({"dnsServerIps": \ + self.have.get("pool_details").get("settings") \ + .get("ippool")[0].get("dnsServerIps")}) + + if want.get("settings").get("ippool")[0].get("gateway") is None and \ + self.have.get("pool_details").get("settings") \ + .get("ippool")[0].get("gateway") is not None: + + want.get("settings").get("ippool")[0].update({"gateway": \ + self.have.get("pool_details").get("settings") \ + .get("ippool")[0].get("gateway")}) + log(str(want)) self.want = want - if self.params.get("config")[0].get("ReservePoolDetails") != None: - - want_reserve = dict( - name = self.params.get("config")[0].get("ReservePoolDetails").get("name"), - type = self.params.get("config")[0].get("ReservePoolDetails").get("type"), - ipv6AddressSpace = self.params.get("config")[0].get("ReservePoolDetails").get("ipv6AddressSpace"), - ipv4GlobalPool = self.params.get("config")[0].get("ReservePoolDetails").get("ipv4GlobalPool"), - ipv4Prefix = self.params.get("config")[0].get("ReservePoolDetails").get("ipv4Prefix"), - ipv4PrefixLength = self.params.get("config")[0].get("ReservePoolDetails").get("ipv4PrefixLength"), - ipv4GateWay = self.params.get("config")[0].get("ReservePoolDetails").get("ipv4GateWay"), - ipv4DhcpServers = self.params.get("config")[0].get("ReservePoolDetails").get("ipv4DhcpServers"), - ipv4DnsServers = self.params.get("config")[0].get("ReservePoolDetails").get("ipv4DnsServers"), - ipv6GlobalPool = self.params.get("config")[0].get("ReservePoolDetails").get("ipv6GlobalPool"), - ipv6Prefix = self.params.get("config")[0].get("ReservePoolDetails").get("ipv6Prefix"), - ipv6PrefixLength = self.params.get("config")[0].get("ReservePoolDetails").get("ipv6PrefixLength"), - ipv6GateWay = self.params.get("config")[0].get("ReservePoolDetails").get("ipv6GateWay"), - ipv6DhcpServers = self.params.get("config")[0].get("ReservePoolDetails").get("ipv6DhcpServers"), - ipv6DnsServers = self.params.get("config")[0].get("ReservePoolDetails").get("ipv6DnsServers"), - ipv4TotalHost = self.params.get("config")[0].get("ReservePoolDetails").get("ipv4TotalHost"), - ipv6TotalHost = self.params.get("config")[0].get("ReservePoolDetails").get("ipv6TotalHost") - ) + if self.params.get("config")[0].get("ReservePoolDetails") is not None: + + want_reserve = { + "name": self.params.get("config")[0].get("ReservePoolDetails").get("name"), + "type": self.params.get("config")[0].get("ReservePoolDetails").get("type"), + "ipv6AddressSpace": self.params.get("config")[0] \ + .get("ReservePoolDetails").get("ipv6AddressSpace"), + "ipv4GlobalPool": self.params.get("config")[0] \ + .get("ReservePoolDetails").get("ipv4GlobalPool"), + "ipv4Prefix": self.params.get("config")[0] \ + .get("ReservePoolDetails").get("ipv4Prefix"), + "ipv4PrefixLength": self.params.get("config")[0] \ + .get("ReservePoolDetails").get("ipv4PrefixLength"), + "ipv4GateWay": self.params.get("config")[0] \ + .get("ReservePoolDetails").get("ipv4GateWay"), + "ipv4DhcpServers": self.params.get("config")[0] \ + .get("ReservePoolDetails").get("ipv4DhcpServers"), + "ipv4DnsServers": self.params.get("config")[0] \ + .get("ReservePoolDetails").get("ipv4DnsServers"), + "ipv6GlobalPool": self.params.get("config")[0] \ + .get("ReservePoolDetails").get("ipv6GlobalPool"), + "ipv6Prefix": self.params.get("config")[0] \ + .get("ReservePoolDetails").get("ipv6Prefix"), + "ipv6PrefixLength": self.params.get("config")[0] \ + .get("ReservePoolDetails").get("ipv6PrefixLength"), + "ipv6GateWay": self.params.get("config")[0] \ + .get("ReservePoolDetails").get("ipv6GateWay"), + "ipv6DhcpServers": self.params.get("config")[0] \ + .get("ReservePoolDetails").get("ipv6DhcpServers"), + "ipv6DnsServers": self.params.get("config")[0] \ + .get("ReservePoolDetails").get("ipv6DnsServers"), + "ipv4TotalHost": self.params.get("config")[0] \ + .get("ReservePoolDetails").get("ipv4TotalHost"), + "ipv6TotalHost": self.params.get("config")[0] \ + .get("ReservePoolDetails").get("ipv6TotalHost") + } log(str(self.have_reserve)) if not self.have_reserve: - if want_reserve.get("type") == None: - want_reserve.update({"type": generic}) - if want_reserve.get("ipv4GateWay") == None: + if want_reserve.get("type") is None: + want_reserve.update({"type": "Generic"}) + if want_reserve.get("ipv4GateWay") is None: want_reserve.update({"ipv4GateWay": ""}) - if want_reserve.get("ipv4DhcpServers") == None: + if want_reserve.get("ipv4DhcpServers") is None: want_reserve.update({"ipv4DhcpServers": []}) - if want_reserve.get("ipv4DnsServers") == None: + if want_reserve.get("ipv4DnsServers") is None: want_reserve.update({"ipv4DnsServers": []}) - if want_reserve.get("ipv6AddressSpace") == None: - want_reserve.update({"ipv6AddressSpace": False}) - if want_reserve.get("slaacSupport") == None: - want_reserve.update({"slaacSupport": True}) - if want_reserve.get("ipv4TotalHost") == None: + if want_reserve.get("ipv6AddressSpace") is None: + want_reserve.update({"ipv6AddressSpace": False}) + if want_reserve.get("slaacSupport") is None: + want_reserve.update({"slaacSupport": True}) + if want_reserve.get("ipv4TotalHost") is None: del want_reserve['ipv4TotalHost'] - if want_reserve.get("ipv6Prefix") == None and want_reserve.get("ipv6AddressSpace") == True: + if want_reserve.get("ipv6Prefix") is None and \ + want_reserve.get("ipv6AddressSpace") is True: + want_reserve.update({"ipv6Prefix": True}) else: del want_reserve['ipv6Prefix'] - if want_reserve.get("ipv6AddressSpace") == False: - if want_reserve.get("ipv6GlobalPool") == None: + if want_reserve.get("ipv6AddressSpace") is False: + if want_reserve.get("ipv6GlobalPool") is None: del want_reserve['ipv6GlobalPool'] - if want_reserve.get("ipv6PrefixLength") == None: + if want_reserve.get("ipv6PrefixLength") is None: del want_reserve['ipv6PrefixLength'] - if want_reserve.get("ipv6GateWay") == None: + if want_reserve.get("ipv6GateWay") is None: del want_reserve['ipv6GateWay'] - if want_reserve.get("ipv6DhcpServers") == None: + if want_reserve.get("ipv6DhcpServers") is None: del want_reserve['ipv6DhcpServers'] - if want_reserve.get("ipv6DnsServers") == None: + if want_reserve.get("ipv6DnsServers") is None: del want_reserve['ipv6DnsServers'] - if want_reserve.get("ipv6TotalHost") == None: + if want_reserve.get("ipv6TotalHost") is None: del want_reserve['ipv6TotalHost'] else: @@ -550,10 +690,60 @@ def get_want(self): del want_reserve['ipv4Prefix'] del want_reserve['ipv4PrefixLength'] del want_reserve['ipv4TotalHost'] - # want_reserve.update({"ipv6AddressSpace": "False"}) self.want_reserve = want_reserve + if self.params.get("config")[0].get("NetworkManagementDetails") is not None: + log(str(self.params)) + want_net = { + "settings": { + "dhcpServer": self.params.get("config")[0].get("NetworkManagementDetails") \ + .get("settings").get("dhcpServer"), + "dnsServer": { + "domainName": self.params.get("config")[0].get("NetworkManagementDetails") \ + .get("settings").get("dnsServer").get("domainName"), + "primaryIpAddress": self.params.get("config")[0] \ + .get("NetworkManagementDetails").get("settings") \ + .get("dnsServer").get("primaryIpAddress"), + "secondaryIpAddress": self.params.get("config")[0] \ + .get("NetworkManagementDetails").get("settings") \ + .get("dnsServer").get("secondaryIpAddress") + }, + "snmpServer": { + "configureDnacIP": self.params.get("config")[0].get("NetworkManagementDetails") \ + .get("settings").get("snmpServer").get("configureDnacIP"), + "ipAddresses": self.params.get("config")[0].get("NetworkManagementDetails") \ + .get("settings").get("snmpServer").get("ipAddresses") + }, + "syslogServer": { + "configureDnacIP": self.params.get("config")[0].get("NetworkManagementDetails") \ + .get("settings").get("syslogServer").get("configureDnacIP"), + "ipAddresses": self.params.get("config")[0].get("NetworkManagementDetails") \ + .get("settings").get("syslogServer").get("ipAddresses") + }, + "netflowcollector": { + "ipAddress": self.params.get("config")[0].get("NetworkManagementDetails") \ + .get("settings").get("netflowcollector").get("ipAddress"), + "port": self.params.get("config")[0].get("NetworkManagementDetails") \ + .get("settings").get("netflowcollector").get("port"), + "configureDnacIP": self.params.get("config")[0].get("NetworkManagementDetails") \ + .get("settings").get("netflowcollector").get("configureDnacIP") + }, + "ntpServer": self.params.get("config")[0].get("NetworkManagementDetails") \ + .get("settings").get("ntpServer"), + "timezone": self.params.get("config")[0].get("NetworkManagementDetails") \ + .get("settings").get("timezone"), + "messageOfTheday": { + "bannerMessage": self.params.get("config")[0].get("NetworkManagementDetails") \ + .get("settings").get("messageOfTheday").get("bannerMessage"), + "retainExistingBanner": self.params.get("config")[0].get("NetworkManagementDetails") \ + .get("settings").get("messageOfTheday").get("retainExistingBanner") + } + + } + } + + self.want_net = want_net def get_execution_details(self, execid): response = None @@ -566,16 +756,17 @@ def get_execution_details(self, execid): if self.log: log(str(response)) - if response and isinstance(response, dict): - return response - + return response def get_diff_merge(self): - if self.params.get("config")[0].get("GlobalPoolDetails") != None: + if self.params.get("config")[0].get("GlobalPoolDetails") is not None: + + if not self.params.get("config")[0].get("GlobalPoolDetails") \ + .get("settings").get("ippool")[0].get("ipPoolName"): - if not self.params.get("config")[0].get("GlobalPoolDetails").get("settings").get("ippool")[0].get("ipPoolName"): msg = "Mandatory Parameter ipPoolName required\n" self.module.fail_json(msg=msg) + pool_updated = False pool_created = False @@ -585,40 +776,48 @@ def get_diff_merge(self): ("settings", "settings"), ] if self.requires_update(self.have.get("pool_details"), self.want, obj_params): - log("Pool update requires") + log("Pool requires update") #Pool Exists pool_params = copy.deepcopy(self.want) - pool_params.get("settings").get("ippool")[0].update({"id": self.have.get("pool_id")}) + pool_params.get("settings").get("ippool")[0] \ + .update({"id": self.have.get("pool_id")}) log(str(self.want)) log(str(pool_params)) del pool_params["settings"]["ippool"][0]["IpAddressSpace"] del pool_params["settings"]["ippool"][0]["ipPoolCidr"] del pool_params["settings"]["ippool"][0]["type"] - if pool_params.get("settings").get("ippool")[0].get("dhcpServerIps") == None: - pool_params.get("settings").get("ippool")[0].update({"dhcpServerIps" : self.have.get("pool_details").get("settings").get("ippool")[0].get("dhcpServerIps")}) - if pool_params.get("settings").get("ippool")[0].get("dnsServerIps") == None: - pool_params.get("settings").get("ippool")[0].update({"dnsServerIps" : self.have.get("pool_details").get("settings").get("ippool")[0].get("dnsServerIps")}) - if pool_params.get("settings").get("ippool")[0].get("gateway") == None: - pool_params.get("settings").get("ippool")[0].update({"gateway" : self.have.get("pool_details").get("settings").get("ippool")[0].get("gateway")}) - + if pool_params.get("settings").get("ippool")[0].get("dhcpServerIps") is None: + pool_params.get("settings").get("ippool")[0].update({"dhcpServerIps" : \ + self.have.get("pool_details").get("settings") \ + .get("ippool")[0].get("dhcpServerIps")}) + if pool_params.get("settings").get("ippool")[0].get("dnsServerIps") is None: + pool_params.get("settings").get("ippool")[0].update({"dnsServerIps" : \ + self.have.get("pool_details").get("settings") \ + .get("ippool")[0].get("dnsServerIps")}) + if pool_params.get("settings").get("ippool")[0].get("gateway") is None: + pool_params.get("settings").get("ippool")[0].update({"gateway" : \ + self.have.get("pool_details").get("settings") \ + .get("ippool")[0].get("gateway")}) + log(str(pool_params)) log(str(self.have)) response = self.dnac._exec( family = "network_settings", function = "update_global_pool", params = pool_params, - op_modifies = True, ) - + pool_updated = True log(str(pool_updated)) else: log("Pool doesn't requires an update") - self.result["response"] = self.have.get("settings") - self.result["msg"] = "Pool doesn't requires an update" - self.module.exit_json(**self.result) + log(str(self.have)) + log(str(self.result)) + self.result['response'] = self.have.get("settings") + self.result['msg'] = "Pool doesn't requires an update" + # self.module.exit_json(**self.result) else: #creating New Pool @@ -628,12 +827,11 @@ def get_diff_merge(self): family="network_settings", function="create_global_pool", params = pool_params, - op_modifies = True, ) - log("PoolCreated") + log("PoolCreated") log(str(response)) pool_created = True - + if pool_created or pool_updated: if response and isinstance(response, dict): executionid = response.get("executionId") @@ -654,19 +852,23 @@ def get_diff_merge(self): if pool_updated: log("Pool Updated Successfully") self.result['msg'] = "Pool Updated Successfully" - self.result['response'].update({"Id": self.have.get("pool_details").get("id")}) - + self.result['response'].update({"Id": \ + self.have.get("pool_details").get("id")}) + elif pool_created: log("Pool Created Successfully") (pool_exists, pool_details, pool_id) = self.pool_exists() self.result['response'].update({"Id": pool_id}) + self.result['response'].update({"Pool Exists": pool_exists}) + self.result['response'].update({"Pool Details": pool_details}) self.result['msg'] = "Pool Created Successfully" else: log("Pool doesn't need a update") self.result['msg'] = "Pool doesn't requires an update" - self.result['response'].update({"Id": self.have.get("pool_details").get("id")}) + self.result['response'].update({"Id": \ + self.have.get("pool_details").get("id")}) - if self.params.get("config")[0].get("ReservePoolDetails") != None: + if self.params.get("config")[0].get("ReservePoolDetails") is not None: res_updated = False res_created = False @@ -691,14 +893,14 @@ def get_diff_merge(self): ("slaacSupport", "slaacSupport") ] - if self.requires_update(self.have_reserve.get("res_details"), self.want_reserve, obj_params): - log("Pool update requires") + if self.requires_update(self.have_reserve.get("res_details"), \ + self.want_reserve, obj_params): + + log("Network requires update") #Pool Exists log(str(self.have_reserve)) log(str(self.want_reserve)) - # if not self.site_id: - # self.module.fail_json(msg="Mandatory parameter siteName not present or invalid", response=[]) res_params = copy.deepcopy(self.want_reserve) res_params.update({"site_id": self.site_id}) res_params.update({"id": self.have_reserve.get("res_id")}) @@ -708,22 +910,26 @@ def get_diff_merge(self): params=res_params, ) - log("Reservation Updated") + log("Reservation Updated") log(str(response)) res_updated = True - + else: log("Reserved ip subpool doesn't requires an update") - self.result["response"] = self.have.get("ReservePoolDetails") + self.result["response"] = self.have_reserve self.result["msg"] = "Reserved ip subpool doesn't requires an update" - self.module.exit_json(**self.result) + # self.module.exit_json(**self.result) else: #creating New Pool res_params = self.want_reserve log(str(res_params)) - if not self.want_reserve.get("name") or not self.want_reserve.get("ipv4GlobalPool") or not self.want_reserve.get("ipv4PrefixLength") or not self.site_id: - self.module.fail_json(msg="missing parameter name or ipv4GlobalPool or ipv4PrefixLength or siteName", response=[]) + if not self.want_reserve.get("name") or \ + not self.want_reserve.get("ipv4GlobalPool") or \ + not self.want_reserve.get("ipv4PrefixLength") or not self.site_id: + + self.module.fail_json(msg="missing parameter name or \ + ipv4GlobalPool or ipv4PrefixLength or siteName", response=[]) res_params.update({"site_id": self.site_id}) log(str(res_params)) @@ -732,7 +938,7 @@ def get_diff_merge(self): function="reserve_ip_subpool", params=res_params, ) - log("Reservation Created") + log("Reservation Created") log(str(response)) res_created = True @@ -756,21 +962,84 @@ def get_diff_merge(self): if res_updated: log("Reserved Ip Subpool Updated Successfully") self.result['msg'] = "Reserved Ip Subpool Updated Successfully" - self.result['response'].update({"Reservation details": self.have.get("res_details")}) - + self.result['response'].update({"Reservation details": \ + self.have.get("res_details")}) + elif res_created: log("Ip Subpool Reservation Created Successfully") (res_exists, res_details, res_id) = self.res_exists() - self.result['response'].update({"Reservation details": self.have.get("res_details")}) + self.result['response'].update({"Reservation Id": res_id}) + self.result['response'].update({"Reservation Exists": res_exists}) + self.result['response'].update({"Reservation details": res_details}) self.result['msg'] = "Ip Subpool Reservation Created Successfully" else: log("Ip Subpool Reservation doesn't need a update") self.result['msg'] = "Ip Subpool Reservation doesn't requires an update" - self.result['response'].update({"Reservation details": self.have.get("res_details")}) + self.result['response'].update({"Reservation details": \ + self.have.get("res_details")}) + if self.params.get("config")[0].get("NetworkManagementDetails") is not None: - def get_id_by_name(self, name): - id = None + net_updated = False + if self.have_net: + log("entered") + obj_params = [ + ("settings", "settings"), + ("siteName", "siteName") + ] + if self.requires_update(self.have_net.get("net_details"), self.want_net, obj_params): + log("Network update requires") + #Pool Exists + log(str(self.have_net)) + log(str(self.want_net)) + + res_params = copy.deepcopy(self.want_net) + res_params.update({"site_id": self.have_net.get("site_id")}) + response = self.dnac._exec( + family="network_settings", + function='update_network', + params=res_params, + ) + + log("Network Updated") + log(str(response)) + net_updated = True + + else: + log("Network doesn't need an update") + self.result["response"] = self.have_net + self.result["msg"] = "Network doesn't need an update" + self.module.exit_json(**self.result) + + if net_updated: + if response and isinstance(response, dict): + executionid = response.get("executionId") + + while True: + execution_details = self.get_execution_details(executionid) + if execution_details.get("status") == "SUCCESS": + self.result['changed'] = True + self.result['response'] = execution_details + break + + elif execution_details.get("bapiError"): + + self.module.fail_json(msg=execution_details.get("bapiError"), + response=execution_details) + break + + if net_updated: + log("Network Updated Successfully") + self.result['msg'] = "Network Updated Successfully" + self.result['response'] = self.want_net + + else: + log("Pool doesn't need a update") + self.result['msg'] = "Pool doesn't requires an update" + self.result['response'] = self.have_net + + def get_res_id_by_name(self, name): + _id = None try: response = self.dnac._exec( family="network_settings", @@ -785,35 +1054,35 @@ def get_id_by_name(self, name): response = response.get("response") log(str(response)) + current_details = get_dict_result(response, "groupName", name) + if current_details: + _id = current_details.get("id") - current_details = get_dict_result(response, "groupName", name) - if current_details: - id = current_details.get("id") - except: result = None - return id + return _id def get_diff_delete(self): - - if self.params.get("config")[0].get("ReservePoolDetails") != None: + + if self.params.get("config")[0].get("ReservePoolDetails") is not None: res_exists = self.have_reserve.get("res_exists") log(str(res_exists)) - id = None + _id = None if self.want_reserve.get("name"): log(str(self.want_reserve.get("name"))) - id = self.get_id_by_name(self.want_reserve.get("name")) - log(str(id)) + _id = self.get_res_id_by_name(self.want_reserve.get("name")) + log(str(_id)) if res_exists: - if not id: - self.module.fail_json(msg="missing or incorrect parameter reserved pool name", response=[]) + if not _id: + self.module.fail_json(msg="missing or \ + incorrect parameter reserved pool name", response=[]) log(str(self.have_reserve.get("res_id"))) response = self.dnac._exec( family="network_settings", function="release_reserve_ip_subpool", - params={"id": id}, + params={"id": _id}, ) if response and isinstance(response, dict): @@ -825,17 +1094,15 @@ def get_diff_delete(self): self.result['response'] = execution_details log(str(response)) self.result['msg'] = "Ip subpool reservation released successfully" - break elif execution_details.get("bapiError"): self.module.fail_json(msg=execution_details.get("bapiError"), response=execution_details) - break else: self.module.fail_json(msg="Reserved Ip Subpool Not Found", response=[]) - if self.params.get("config")[0].get("GlobalPoolDetails") != None: + if self.params.get("config")[0].get("GlobalPoolDetails") is not None: pool_exists = self.have.get("pool_exists") if pool_exists: @@ -853,56 +1120,56 @@ def get_diff_delete(self): self.result['changed'] = True self.result['response'] = execution_details log(str(response)) - self.result['response'].update({"Id": self.have.get("pool_details").get("id")}) self.result['msg'] = "Pool deleted successfully" - break elif execution_details.get("bapiError"): self.module.fail_json(msg=execution_details.get("bapiError"), response=execution_details) - break else: self.module.fail_json(msg="Pool Not Found", response=[]) - - + + if self.params.get("config")[0].get("NetworkManagementDetails") is not None: + + self.module.fail_json(msg="No operation available for Delete Network", response=[]) + def main(): """main entry point for module execution""" - element_spec = dict( - dnac_host=dict(required=True, type="str"), - dnac_port=dict(type="str", default="443"), - dnac_username=dict(type="str", default="admin", aliases=["user"]), - dnac_password=dict(type="str", no_log=True), - dnac_verify=dict(type="bool", default="True"), - dnac_version=dict(type="str", default="2.2.3.3"), - dnac_debug=dict(type="bool", default=False), - dnac_log=dict(type="bool", default=False), - validate_response_schema=dict(type="bool", default=True), - config=dict(required=True, type="list", elements="dict"), - state=dict(default="merged", choices=["merged", "deleted"]), - ) + element_spec ={ + "dnac_host": {"required": True, "type": 'str'}, + "dnac_port": {"type": 'str', "default": '443'}, + "dnac_username": {"type": 'str', "default": 'admin', "aliases": ['user']}, + "dnac_password": {"type": 'str', "no_log": True}, + "dnac_verify": {"type": 'bool', "default": 'True'}, + "dnac_version": {"type": 'str', "default": '2.2.3.3'}, + "dnac_debug": {"type": 'bool', "default": False}, + "dnac_log": {"type": 'bool', "default": False}, + "validate_response_schema": {"type": 'bool', "default": True}, + "config": {"required": True, "type": 'list', "elements": 'dict'}, + "state": {"default": 'merged', "choices": ['merged', 'deleted']}, + } module = AnsibleModule(argument_spec=element_spec, supports_check_mode=False) - + dnac_network = DnacNetwork(module) - + state = dnac_network.get_state() dnac_network.validate_input() - + dnac_network.get_have() dnac_network.get_want() - + if state == "merged": dnac_network.get_diff_merge() - + elif state == "deleted": dnac_network.get_diff_delete() log(str(dnac_network.result)) - + module.exit_json(**dnac_network.result) - + if __name__ == "__main__": main() From af34046e8fdf454c0835a88975cac35091e2cd1d Mon Sep 17 00:00:00 2001 From: Muthu Rakesh <114211490+MUTHU-RAKESH-27@users.noreply.github.com> Date: Thu, 13 Jul 2023 17:47:59 +0530 Subject: [PATCH 05/13] Update network_intent.yml - Module Name --- playbooks/network_intent.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/playbooks/network_intent.yml b/playbooks/network_intent.yml index b0c2d5484b..e144efc628 100644 --- a/playbooks/network_intent.yml +++ b/playbooks/network_intent.yml @@ -9,7 +9,7 @@ # - name: Create, update, delete global pool and reserve an ip pool - cisco.dnac.sample_module: + cisco.dnac.network_intent: dnac_host: "{{ dnac_host }}" dnac_port: "{{ dnac_port }}" dnac_username: "{{ dnac_username }}" From 3c4ed492b31ca3260d308600486df40f80b6f83c Mon Sep 17 00:00:00 2001 From: akabhask Date: Mon, 21 Aug 2023 00:10:19 +0530 Subject: [PATCH 06/13] Changes to create and delete project and other bug fixes --- plugins/modules/template_intent.py | 790 +++++++++++++++++++---------- 1 file changed, 516 insertions(+), 274 deletions(-) diff --git a/plugins/modules/template_intent.py b/plugins/modules/template_intent.py index 8a42f9271b..98ca8ce16f 100644 --- a/plugins/modules/template_intent.py +++ b/plugins/modules/template_intent.py @@ -1,13 +1,12 @@ #!/usr/bin/python # -*- coding: utf-8 -*- - # Copyright (c) 2022, Cisco Systems # GNU General Public License v3.0+ (see LICENSE or https://www.gnu.org/licenses/gpl-3.0.txt) - +"""Ansible module to perform operations on project and templates in DNAC.""" from __future__ import absolute_import, division, print_function __metaclass__ = type -__author__ = ("Madhan Sankaranarayanan, Rishita Chowdhary") +__author__ = ['Madhan Sankaranarayanan, Rishita Chowdhary'] DOCUMENTATION = r""" --- @@ -52,7 +51,7 @@ description: Description of template. type: str deviceTypes: - description: Configuration Template Create's deviceTypes. + description: deviceTypes on which templates would be applied. type: list elements: dict suboptions: @@ -78,10 +77,11 @@ description: Name of template. type: str projectName: - description: Project name. + description: Name of the project under which templates are managed. type: str + required: true rollbackTemplateParams: - description: Configuration Template Create's rollbackTemplateParams. + description: Params required for template rollback. type: list elements: dict suboptions: @@ -277,7 +277,7 @@ description: Description of template. type: str deviceTypes: - description: Configuration Template Create's deviceTypes. + description: Configuration Template Create's deviceTypes. This field is mandatory to create a new template. suboptions: productFamily: description: Device family. @@ -306,7 +306,7 @@ description: Latest versioned template time. type: int templateName: - description: Name of template. + description: Name of template. This field is mandatory to create a new template. type: str parentTemplateId: description: Parent templateID. @@ -405,7 +405,7 @@ type: list elements: dict softwareType: - description: Applicable device software type. + description: Applicable device software type. This field is mandatory to create a new template. type: str softwareVariant: description: Applicable device software variant. @@ -649,6 +649,7 @@ """ import copy +from ansible.module_utils.basic import AnsibleModule from ansible_collections.cisco.dnac.plugins.module_utils.dnac import ( DNACSDK, validate_list_of_dicts, @@ -656,212 +657,355 @@ get_dict_result, dnac_compare_equality, ) -from ansible.module_utils.basic import AnsibleModule class DnacTemplate: - + """Class containing member attributes for template intent module""" def __init__(self, module): self.module = module self.params = module.params self.config = copy.deepcopy(module.params.get("config")) - self.have_create = {} + self.have_create_project = {} + self.have_create_template = {} self.want_create = {} self.validated = [] + self.msg = "" + self.status = "success" + self.accepted_languages = ["JINJA", "VELOCITY"] dnac_params = self.get_dnac_params(self.params) - log(str(dnac_params)) self.dnac = DNACSDK(params=dnac_params) - self.log = dnac_params.get("dnac_log") + self.dnac_log = dnac_params.get("dnac_log") + self.log(str(dnac_params)) + self.result = {"changed": False, "diff": [], "response": [], "warnings": []} + + def log(self, message): + """Log messages into dnac.log file""" - self.result = dict(changed=False, diff=[], response=[], warnings=[]) + if self.dnac_log: + message = self.__class__.__name__ + " " + message + log(message) - def get_state(self): - return self.params.get("state") + def check_return_status(self, api_name): + """API to check the return status value and exit/fail the module""" + + self.log(f"API:{api_name}, msg:{self.msg}, status: {self.status}") + if "failed" in self.status: + self.module.fail_json(msg=self.msg, response=[]) + elif "exited" in self.status: + self.module.exit_json(**self.result) + elif "invalid" in self.status: + self.module.fail_json(msg=self.msg, response=[]) def validate_input(self): - temp_spec = dict( - tags=dict(type="list"), - author=dict(type="str"), - composite=dict(type="bool"), - containingTemplates=dict(type="list"), - createTime=dict(type="int"), - customParamsOrder=dict(type="bool"), - description=dict(type="str"), - deviceTypes=dict(type="list", elements='dict'), - failurePolicy=dict(type="str"), - id=dict(type="str"), - language=dict(type="str"), - lastUpdateTime=dict(type="int"), - latestVersionTime=dict(type="int"), - name=dict(type="str"), - parentTemplateId=dict(type="str"), - projectId=dict(type="str"), - projectName=dict(required=True, type="str"), - rollbackTemplateContent=dict(type="str"), - rollbackTemplateParams=dict(type="list"), - softwareType=dict(type="str"), - softwareVariant=dict(type="str"), - softwareVersion=dict(type="str"), - templateContent=dict(type="str"), - templateParams=dict(type="list"), - templateName=dict(required=True, type='str'), - validationErrors=dict(type="dict"), - version=dict(type="str"), - versionDescription=dict(type='str'), - ) + """Validate the fields provided in the playbook""" + + temp_spec = {'tags': {'type': 'list'}, + 'author': {'type': 'str'}, + 'composite': {'type': 'bool'}, + 'containingTemplates': {'type': 'list'}, + 'createTime': {'type': 'int'}, + 'customParamsOrder': {'type': 'bool'}, + 'description': {'type': 'str'}, + 'deviceTypes': {'type': 'list', 'elements': 'dict'}, + 'failurePolicy': {'type': 'str'}, + 'id': {'type': 'str'}, + 'language': {'type': 'str'}, + 'lastUpdateTime': {'type': 'int'}, + 'latestVersionTime': {'type': 'int'}, + 'name': {'type': 'str'}, + 'parentTemplateId': {'type': 'str'}, + 'projectId': {'type': 'str'}, + 'projectName': {'required': True, 'type': 'str'}, + 'rollbackTemplateContent': {'type': 'str'}, + 'rollbackTemplateParams': {'type': 'list'}, + 'softwareType': {'type': 'str'}, + 'softwareVariant': {'type': 'str'}, + 'softwareVersion': {'type': 'str'}, + 'templateContent': {'type': 'str'}, + 'templateParams': {'type': 'list'}, + 'templateName': {'type': 'str'}, + 'validationErrors': {'type': 'dict'}, + 'version': {'type': 'str'}, + 'versionDescription': {'type': 'str'} + } if self.config: - msg = None # Validate template params valid_temp, invalid_params = validate_list_of_dicts( self.config, temp_spec ) - if invalid_params: - msg = "Invalid parameters in playbook: {0}".format( - "\n".join(invalid_params) - ) - self.module.fail_json(msg=msg) + self.msg = "Invalid parameters in playbook: {0}".format( + "\n".join(invalid_params)) + self.status = "failed" + return self self.validated = valid_temp + self.log(str(valid_temp)) - if self.log: - log(str(valid_temp)) - log(str(self.validated)) - - if self.params.get("state") == "merged": - for temp in self.validated: - if not temp.get("language") or not temp.get("deviceTypes") \ - or not temp.get("softwareType"): - msg = "missing required arguments: language or deviceTypes or softwareType" - self.module.fail_json(msg=msg) - if not (temp.get("language").lower() == "velocity" or - temp.get("language").lower() == "jinja"): - msg = "Invalid parameters in playbook: {0} : Invalid choice provided".format( - "".join(temp.get("language"))) - self.module.fail_json(msg=msg) + self.msg = "Successfully validated input" + self.status = "success" + return self def get_dnac_params(self, params): - dnac_params = dict( - dnac_host=params.get("dnac_host"), - dnac_port=params.get("dnac_port"), - dnac_username=params.get("dnac_username"), - dnac_password=params.get("dnac_password"), - dnac_verify=params.get("dnac_verify"), - dnac_debug=params.get("dnac_debug"), - dnac_log=params.get("dnac_log") - ) + """Store the DNAC parameters from the playbook""" + + dnac_params = {"dnac_host": params.get('dnac_host'), + "dnac_port": params.get('dnac_port'), + "dnac_username": params.get("dnac_username"), + "dnac_password": params.get("dnac_password"), + "dnac_verify": params.get("dnac_verify"), + "dnac_debug": params.get("dnac_debug"), + "dnac_log": params.get("dnac_log") + } return dnac_params def get_template_params(self, params): - temp_params = dict( - tags=params.get("template_tag"), - author=params.get("author"), - composite=params.get("composite"), - containingTemplates=params.get("containingTemplates"), - createTime=params.get("createTime"), - customParamsOrder=params.get("customParamsOrder"), - description=params.get("template_description"), - deviceTypes=params.get("deviceTypes"), - failurePolicy=params.get("failurePolicy"), - id=params.get("templateId"), - language=params.get("language").upper(), - lastUpdateTime=params.get("lastUpdateTime"), - latestVersionTime=params.get("latestVersionTime"), - name=params.get("templateName"), - parentTemplateId=params.get("parentTemplateId"), - projectId=params.get("projectId"), - projectName=params.get("projectName"), - rollbackTemplateContent=params.get("rollbackTemplateContent"), - rollbackTemplateParams=params.get("rollbackTemplateParams"), - softwareType=params.get("softwareType"), - softwareVariant=params.get("softwareVariant"), - softwareVersion=params.get("softwareVersion"), - templateContent=params.get("templateContent"), - templateParams=params.get("templateParams"), - validationErrors=params.get("validationErrors"), - version=params.get("version"), - project_id=params.get("projectId"), - ) + """Store template parameters from the playbook for template processing in DNAC""" + + temp_params = { + "tags": params.get("template_tag"), + "author": params.get("author"), + "composite": params.get("composite"), + "containingTemplates": params.get("containingTemplates"), + "createTime": params.get("createTime"), + "customParamsOrder": params.get("customParamsOrder"), + "description": params.get("template_description"), + "deviceTypes": params.get("deviceTypes"), + "failurePolicy": params.get("failurePolicy"), + "id": params.get("templateId"), + "language": params.get("language").upper(), + "lastUpdateTime": params.get("lastUpdateTime"), + "latestVersionTime": params.get("latestVersionTime"), + "name": params.get("templateName"), + "parentTemplateId": params.get("parentTemplateId"), + "projectId": params.get("projectId"), + "projectName": params.get("projectName"), + "rollbackTemplateContent": params.get("rollbackTemplateContent"), + "rollbackTemplateParams": params.get("rollbackTemplateParams"), + "softwareType": params.get("softwareType"), + "softwareVariant": params.get("softwareVariant"), + "softwareVersion": params.get("softwareVersion"), + "templateContent": params.get("templateContent"), + "templateParams": params.get("templateParams"), + "validationErrors": params.get("validationErrors"), + "version": params.get("version"), + "project_id": params.get("projectId"), + } return temp_params - def get_template(self): - result = None - - for temp in self.validated: - items = self.dnac._exec( - family="configuration_templates", - function="get_template_details", - params={"template_id": temp.get("templateId")} - ) - - if items: - result = items + def get_template(self, template_config): + """Get the template needed for updation or creation""" - if self.log: - log(str(items)) + result = None + items = self.dnac._exec( + family="configuration_templates", + function="get_template_details", + params={"template_id": template_config.get("templateId")} + ) + if items: + result = items + self.log(str(items)) self.result['response'] = items return result - def get_have(self): - prev_template = None - template_exists = False - have_create = {} - - # Get available templates. Filter templates based on provided projectName - for temp in self.validated: - template_list = self.dnac._exec( - family="configuration_templates", - function='gets_the_templates_available', - params={"project_names": temp.get("projectName")}, - ) - # API execution error returns a dict - if template_list and isinstance(template_list, list): - template_details = get_dict_result(template_list, 'name', temp.get("templateName")) - - if template_details: - temp["templateId"] = template_details.get("templateId") - have_create["templateId"] = template_details.get("templateId") - prev_template = self.get_template() - - if self.log: - log(str(prev_template)) - - template_exists = prev_template is not None and isinstance(prev_template, dict) - else: - self.module.fail_json(msg="Project Not Found", response=[]) + def get_have_project(self, template_config): + """Get the current project related information from DNAC""" + + have_create_project = {} + given_project_name = template_config.get("projectName") + template_available = None + + # Check if project exists. + project_details = self.get_project_details(template_config.get("projectName")) + # DNAC returns project details even if the substring matches. + # Hence check the projectName retrieved from DNAC. + if not (project_details and isinstance(project_details, list)): + self.log("Project not found, need to create new project in DNAC") + return None + + fetched_project_name = project_details[0].get('name') + if fetched_project_name != given_project_name: + self.log("Project name provided is not exact match in DNAC DB") + return None + + template_available = project_details[0].get('templates') + have_create_project["project_found"] = True + have_create_project["id"] = project_details[0].get("id") + have_create_project["isDeletable"] = project_details[0].get("isDeletable") + + self.have_create_project = have_create_project + return template_available + + def get_have_template(self, template_config, template_available): + """Get the current template related information from DNAC""" + project_name = template_config.get("projectName") + template_name = template_config.get("templateName") + template = None + have_create_template = {} + + have_create_template["isCommitPending"] = False + have_create_template["template_found"] = False + + template_details = get_dict_result(template_available, + "name", + template_name) + # Check if specified template in playbook is available + if not template_details: + self.log(f"Template {template_name} not found in project {project_name}") + self.msg = "Found template : {template_name} missing, new template to be created" + self.status = "success" + return self + + template_config["templateId"] = template_details.get("id") + have_create_template["id"] = template_details.get("id") + # Get available templates which are committed under the project + template_list = self.dnac._exec( + family="configuration_templates", + function="gets_the_templates_available", + params={"project_names": template_config.get("projectName")}, + ) + have_create_template["isCommitPending"] = True + # This check will fail if specified template is there not committed in dnac + if template_list and isinstance(template_list, list): + template_info = get_dict_result(template_list, + "name", + template_name) + if template_info: + template = self.get_template(template_config) + have_create_template["template"] = template + have_create_template["isCommitPending"] = False + have_create_template["template_found"] = template is not None \ + and isinstance(template, dict) + self.log(f"Template {template_name} is found and template " + f"details are :{str(template)}") + + # There are committed templates in the project but the + # one specified in the playbook may not be committed + self.log(f"Commit pending for template name {template_name}" + f" is {have_create_template.get('isCommitPending')}") + + self.have_create_template = have_create_template + self.msg = "Successfully collected all template parameters from dnac for comparison" + self.status = "success" + return self + + def get_have(self, template_config): + """Get the current project and template details from DNAC""" + + template_available = self.get_have_project(template_config) + if template_available: + self.get_have_template(template_config, template_available) + + self.msg = "Successfully collected all project and template \ + parameters from dnac for comparison" + self.status = "success" + return self + + def get_project_details(self, project_name): + """Get the details of specific project name provided""" + + items = self.dnac._exec( + family="configuration_templates", + function='get_projects', + op_modifies=True, + params={"name": project_name}, + ) + return items - have_create['template'] = prev_template - have_create['template_found'] = template_exists - self.have_create = have_create + def get_want(self, template_config): + """Get all the template and project related information from playbook + that is needed to be created in DNAC""" - def get_want(self): want_create = {} + template_params = self.get_template_params(template_config) + version_comments = template_config.get("versionDescription") - for temp in self.validated: - template_params = self.get_template_params(temp) - version_comments = temp.get("versionDescription") - - if self.params.get("state") == "merged" and \ - not self.have_create.get("template_found"): - # ProjectId is required for creating a new template. - # Store it with other template parameters. - items = self.dnac._exec( - family="configuration_templates", - function='get_projects', - params={"name": temp.get("projectName")}, - ) - template_params["projectId"] = items[0].get("id") - template_params["project_id"] = items[0].get("id") + if self.params.get("state") == "merged": + self.update_mandatory_parameters(template_params) want_create["template_params"] = template_params want_create["comments"] = version_comments self.want_create = want_create + self.msg = "Successfully collected all parameters from playbook \ + for comparison" + self.status = "success" + return self + + def create_project_or_template(self, is_create_project=False): + """Call DNAC API to create project or template based on the input provided""" + + creation_id = None + created = False + template_params = self.want_create.get("template_params") + + if is_create_project: + params_key = {"name": template_params.get('projectName')} + name = f"project: {template_params.get('projectName')}" + validation_string = "Successfully created project" + creation_value = "create_project" + else: + params_key = template_params + name = f"template: {template_params.get('templateName')}" + validation_string = "Successfully created template" + creation_value = "create_template" + + response = self.dnac._exec( + family="configuration_templates", + function=creation_value, + op_modifies=True, + params=params_key, + ) + if not isinstance(response, dict): + self.log("Response not in dictionary format.") + return creation_id, created + + task_id = response.get("response").get("taskId") + if not task_id: + self.log("Task id not found") + return creation_id, created + + while not created: + task_details = self.get_task_details(task_id) + if not task_details: + self.log(f"Failed to get task details for taskid: {task_id}") + return creation_id, created + + self.log(f"task_details: {task_details}") + if task_details.get("isError"): + self.log(f"isError set to true for taskid: {task_id}") + return creation_id, created + + if validation_string not in task_details.get("progress"): + self.log(f"progress set to {task_details.get('progress')} " + f"for taskid: {task_id}") + continue + + creation_id = task_details.get("data") + if not creation_id: + self.log(f"data is not found for taskid: {task_id}") + continue + + created = True + if is_create_project: + # ProjectId is required for creating a new template. + # Store it with other template parameters. + template_params["projectId"] = creation_id + template_params["project_id"] = creation_id + + self.log(f"New {name} created with id {creation_id}") + return creation_id, created def requires_update(self): - current_obj = self.have_create.get("template") + """Check if the template config given requires update.""" + + if self.have_create_template.get("isCommitPending"): + self.log("Template is in saved state and needs to be updated and committed") + return True + + current_obj = self.have_create_template.get("template") requested_obj = self.want_create.get("template_params") obj_params = [ ("tags", "tags", ""), @@ -896,163 +1040,261 @@ def requires_update(self): requested_obj.get(ansible_param)) for (dnac_param, ansible_param, default) in obj_params) - def get_task_details(self, id): + def get_task_details(self, task_id): + """Check if the task performed is sucessfull or not""" + result = None response = self.dnac._exec( family="task", - function='get_task_by_id', - params={"task_id": id}, + function="get_task_by_id", + params={"task_id": task_id}, ) - if self.log: - log(str(response)) - + self.log(str(response)) if isinstance(response, dict): result = response.get("response") return result - def get_diff_merge(self): + def update_mandatory_parameters(self, template_params): + """Update parameters which are mandatory for creating a template""" + + # Mandate fields required for creating a new template. + # Store it with other template parameters. + template_params["projectId"] = self.have_create_project.get("id") + template_params["project_id"] = self.have_create_project.get("id") + # Update language,deviceTypes and softwareType if not provided for existing template. + if not template_params.get("language"): + template_params["language"] = self.have_create_template.get('template') \ + .get('language') + if not template_params.get("deviceTypes"): + template_params["deviceTypes"] = self.have_create_template.get('template') \ + .get('deviceTypes') + if not template_params.get("softwareType"): + template_params["softwareType"] = self.have_create_template.get('template') \ + .get('softwareType') + + def validate_input_merge(self, template_exists): + """Validate input after getting all the parameters from DNAC. + "If mandate like deviceTypes, softwareType and language " + "already present in DNAC for a template." + "It is not required to be provided in playbook, " + "but if it is new creation error will be thrown to provide these fields.""" + + template_params = self.want_create.get("template_params") + language = template_params.get("language").upper() + if language: + if language not in self.accepted_languages: + self.msg = f"Invalid value language {language} ." \ + f"Accepted language values are {self.accepted_languages}" + self.status = "failed" + return self + else: + template_params["language"] = "JINJA" + + if not template_exists: + if not template_params.get("deviceTypes") \ + or not template_params.get("softwareType"): + self.msg = "DeviceTypes and SoftwareType are required arguments to create Templates" + self.status = "failed" + return self + + self.msg = "Input validated for merging" + self.status = "success" + return self + + def get_diff_merge(self, template_config): + """Update/Create templates and projects in DNAC with fields provided in DNAC""" + + is_project_found = self.have_create_project.get("project_found") + is_template_found = self.have_create_template.get("template_found") + template_params = self.want_create.get("template_params") template_id = None - template_ceated = False template_updated = False - template_exists = self.have_create.get("template_found") - if template_exists: + if not is_project_found: + project_id, project_created = self.create_project_or_template(is_create_project=True) + if project_created: + self.log(f"project created with projectId : {project_id}") + else: + self.status = "failed" + self.msg = "Project creation failed" + return self + + self.validate_input_merge(is_template_found).check_return_status("validate_input_merge") + if is_template_found: if self.requires_update(): response = self.dnac._exec( family="configuration_templates", function="update_template", - params=self.want_create.get("template_params"), + params=template_params, op_modifies=True, ) template_updated = True - template_id = self.have_create.get("templateId") - - if self.log: - log("Updating Existing Template") + template_id = self.have_create_template.get("id") + self.log("Updating Existing Template") else: # Template does not need update - self.result['response'] = self.have_create.get("template") + self.result['response'] = self.have_create_template.get("template") self.result['msg'] = "Template does not need update" - self.module.exit_json(**self.result) + self.status = "exited" + return self else: - response = self.dnac._exec( - family="configuration_templates", - function='create_template', - op_modifies=True, - params=self.want_create.get("template_params"), - ) + if template_params.get("name"): + template_id, template_updated = self.create_project_or_template() + else: + self.msg = "missing required arguments: TemplateName" + self.status = "failed" + return self - if self.log: - log("Template created. Get template_id for versioning") - if isinstance(response, dict): - create_error = False - task_details = {} - task_id = response.get("response").get("taskId") - - if task_id: - while (True): - task_details = self.get_task_details(task_id) - if task_details and task_details.get("isError"): - create_error = True - break - - if task_details and ("Successfully created template" in task_details.get("progress")): - break - if not create_error: - template_id = task_details.get("data") - if template_id: - template_created = True - - if template_updated or template_created: + if template_updated: # Template needs to be versioned - version_params = dict( - comments=self.want_create.get("comments"), - templateId=template_id - ) + version_params = { + "comments": self.want_create.get("comments"), + "templateId": template_id + } response = self.dnac._exec( family="configuration_templates", - function='version_template', + function="version_template", op_modifies=True, params=version_params ) task_details = {} task_id = response.get("response").get("taskId") - - if task_id: - task_details = self.get_task_details(task_id) - self.result['changed'] = True - self.result['msg'] = task_details.get('progress') - self.result['diff'] = self.validated - if self.log: - log(str(task_details)) + if not task_id: + self.msg = "Task id not found" + self.status = "failed" + return self + task_details = self.get_task_details(task_id) + self.result['changed'] = True + self.result['msg'] = task_details.get('progress') + self.result['diff'] = template_config + self.log(str(task_details)) self.result['response'] = task_details if task_details else response if not self.result.get('msg'): - self.result['msg'] = "Error while versioning the template" + self.msg = "Error while versioning the template" + self.status = "failed" + return self - def get_diff_delete(self): - template_exists = self.have_create.get("template_found") + self.msg = "Successfully completed merged state execution" + self.status = "success" + return self - if template_exists: - response = self.dnac._exec( - family="configuration_templates", - function="deletes_the_template", - params={"template_id": self.have_create.get("templateId")}, - ) - task_details = {} - task_id = response.get("response").get("taskId") + def delete_project_or_template(self, template_config, is_delete_project=False): + """Call DNAC API to delete project or template with provided inputs""" - if task_id: - task_details = self.get_task_details(task_id) - self.result['changed'] = True - self.result['msg'] = task_details.get('progress') - self.result['diff'] = self.validated + template_params = self.want_create.get("template_params") - if self.log: - log(str(task_details)) + if is_delete_project: + params_key = {"project_id": self.have_create_project.get("id")} + deletion_value = "deletes_the_project" + name = f"project: {template_params.get('projectName')}" + else: + params_key = {"template_id": self.have_create_template.get("id")} + deletion_value = "deletes_the_template" + name = f"templateName: {template_params.get('templateName')}" - self.result['response'] = task_details if task_details else response + response = self.dnac._exec( + family="configuration_templates", + function=deletion_value, + params=params_key, + ) + + task_id = response.get("response").get("taskId") + if task_id: + task_details = self.get_task_details(task_id) + self.result['changed'] = True + self.result['msg'] = task_details.get('progress') + self.result['diff'] = template_config + self.log(str(task_details)) + self.result['response'] = task_details if task_details else response if not self.result['msg']: - self.result['msg'] = "Error while deleting template" + self.result['msg'] = "Error while deleting {name} : " + self.status = "failed" + return self + + self.msg = f"Successfully deleted {name} " + self.status = "success" + return self + + def get_diff_delete(self, template_config): + """Delete projects or templates in DNAC with fields provided in playbook.""" + + is_template_found = self.have_create_template.get("template_found") + is_project_found = self.have_create_project.get("project_found") + template_params = self.want_create.get("template_params") + + if not is_project_found: + self.msg = "Project not found, provide valid projectName" + self.status = "failed" + return self + + if template_params.get("name"): + if is_template_found: + self.delete_project_or_template(template_config) + else: + self.msg = "Invalid template Name under project" + self.status = "failed" + return self else: - self.module.fail_json(msg="Template not found", response=[]) + self.log("Template is empty, deleting the project") + is_project_deletable = self.have_create_project.get("isDeletable") + if is_project_deletable: + self.delete_project_or_template(template_config, is_delete_project=True) + else: + self.msg = "Project is not deletable" + self.status = "failed" + return self + + self.msg = "Successfully completed delete state execution" + self.status = "success" + return self + + def reset_values(self): + """Reset all neccessary attributes to default values""" + + self.have_create_project.clear() + self.have_create_template.clear() + self.want_create.clear() def main(): - """ main entry point for module execution - """ - - element_spec = dict( - dnac_host=dict(required=True, type='str'), - dnac_port=dict(type='str', default='443'), - dnac_username=dict(type='str', default='admin', aliases=["user"]), - dnac_password=dict(type='str', no_log=True), - dnac_verify=dict(type='bool', default='True'), - dnac_version=dict(type="str", default="2.2.3.3"), - dnac_debug=dict(type='bool', default=False), - dnac_log=dict(type='bool', default=False), - validate_response_schema=dict(type="bool", default=True), - config=dict(required=True, type='list', elements='dict'), - state=dict( - default='merged', - choices=['merged', 'deleted']), - ) + """ main entry point for module execution""" + + element_spec = {'dnac_host': {'required': True, 'type': 'str'}, + 'dnac_port': {'type': 'str', 'default': '443'}, + 'dnac_username': {'type': 'str', 'default': 'admin', 'aliases': ['user']}, + 'dnac_password': {'type': 'str', 'no_log': True}, + 'dnac_verify': {'type': 'bool', 'default': 'True'}, + 'dnac_version': {'type': 'str', 'default': '2.2.3.3'}, + 'dnac_debug': {'type': 'bool', 'default': False}, + 'dnac_log': {'type': 'bool', 'default': False}, + 'validate_response_schema': {'type': 'bool', 'default': True}, + 'config': {'required': True, 'type': 'list', 'elements': 'dict'}, + 'state': {'default': 'merged', 'choices': ['merged', 'deleted']} + } + module = AnsibleModule(argument_spec=element_spec, supports_check_mode=False) dnac_template = DnacTemplate(module) - dnac_template.validate_input() - state = dnac_template.get_state() - dnac_template.get_have() - dnac_template.get_want() - - if state == "merged": - dnac_template.get_diff_merge() - - elif state == "deleted": - dnac_template.get_diff_delete() + dnac_template.validate_input().check_return_status("validate_input") + state = dnac_template.params.get("state") + + for template_config in dnac_template.validated: + dnac_template.reset_values() + dnac_template.get_have(template_config).check_return_status("get_have") + dnac_template.get_want(template_config).check_return_status("get_want") + + if state == "merged": + dnac_template.get_diff_merge(template_config).check_return_status("get_diff_merge") + elif state == "deleted": + dnac_template.get_diff_delete(template_config).check_return_status("get_diff_delete") + else: + dnac_template.status = "invalid" + dnac_template.msg = f"State {state} is invalid" + dnac_template.check_return_status("main") module.exit_json(**dnac_template.result) From be078512971137a825c7c1c32b745735e3129733 Mon Sep 17 00:00:00 2001 From: akabhask Date: Mon, 28 Aug 2023 14:52:01 +0530 Subject: [PATCH 07/13] adding project description support --- plugins/modules/template_intent.py | 160 +++++++++++++++++------------ 1 file changed, 92 insertions(+), 68 deletions(-) diff --git a/plugins/modules/template_intent.py b/plugins/modules/template_intent.py index 98ca8ce16f..1dd1427e63 100644 --- a/plugins/modules/template_intent.py +++ b/plugins/modules/template_intent.py @@ -80,6 +80,9 @@ description: Name of the project under which templates are managed. type: str required: true + projectDescription: + description: Description of the project created. + type: str rollbackTemplateParams: description: Params required for template rollback. type: list @@ -317,6 +320,9 @@ projectName: description: Project name. type: str + projectDescription: + description: Project Description. + type: str rollbackTemplateContent: description: Rollback template content. type: str @@ -582,6 +588,7 @@ parentTemplateId: string projectId: string projectName: string + projectDescription: string rollbackTemplateContent: string softwareType: string softwareVariant: string @@ -602,7 +609,7 @@ """ RETURN = r""" -#Case_1: Successful creation/updation/deletion of template +# Case_1: Successful creation/updation/deletion of template/project response_1: description: A dictionary with versioning details of the template as returned by the DNAC Python SDK returned: always @@ -625,7 +632,7 @@ "msg": String } -#Case_2: Error while deleting a template or when given project is not found +# Case_2: Error while deleting a template or when given project is not found response_2: description: A list with the response returned by the Cisco DNAC Python SDK returned: always @@ -636,7 +643,7 @@ "msg": String } -#Case_3: Given template already exists and requires no udpate +# Case_3: Given template already exists and requires no update response_3: description: A dictionary with the exisiting template deatails as returned by the Cisco DNAC Python SDK returned: always @@ -668,12 +675,15 @@ def __init__(self, module): self.have_create_project = {} self.have_create_template = {} self.want_create = {} - self.validated = [] + self.validated_config = [] self.msg = "" self.status = "success" self.accepted_languages = ["JINJA", "VELOCITY"] dnac_params = self.get_dnac_params(self.params) self.dnac = DNACSDK(params=dnac_params) + self.dnac_apply = {'exec': self.dnac._exec} + self.get_diff_state_apply = {'merged': self.get_diff_merged, + 'deleted': self.get_diff_deleted} self.dnac_log = dnac_params.get("dnac_log") self.log(str(dnac_params)) self.result = {"changed": False, "diff": [], "response": [], "warnings": []} @@ -699,6 +709,11 @@ def check_return_status(self, api_name): def validate_input(self): """Validate the fields provided in the playbook""" + if not self.config: + self.msg = "config not available in playbook for validattion" + self.status = "success" + return self + temp_spec = {'tags': {'type': 'list'}, 'author': {'type': 'str'}, 'composite': {'type': 'bool'}, @@ -716,6 +731,7 @@ def validate_input(self): 'parentTemplateId': {'type': 'str'}, 'projectId': {'type': 'str'}, 'projectName': {'required': True, 'type': 'str'}, + 'projectDescription': {'type': 'str'}, 'rollbackTemplateContent': {'type': 'str'}, 'rollbackTemplateParams': {'type': 'list'}, 'softwareType': {'type': 'str'}, @@ -728,21 +744,18 @@ def validate_input(self): 'version': {'type': 'str'}, 'versionDescription': {'type': 'str'} } + # Validate template params + valid_temp, invalid_params = validate_list_of_dicts( + self.config, temp_spec + ) + if invalid_params: + self.msg = "Invalid parameters in playbook: {0}".format( + "\n".join(invalid_params)) + self.status = "failed" + return self - if self.config: - # Validate template params - valid_temp, invalid_params = validate_list_of_dicts( - self.config, temp_spec - ) - if invalid_params: - self.msg = "Invalid parameters in playbook: {0}".format( - "\n".join(invalid_params)) - self.status = "failed" - return self - - self.validated = valid_temp - self.log(str(valid_temp)) - + self.validated_config = valid_temp + self.log(str(valid_temp)) self.msg = "Successfully validated input" self.status = "success" return self @@ -750,8 +763,8 @@ def validate_input(self): def get_dnac_params(self, params): """Store the DNAC parameters from the playbook""" - dnac_params = {"dnac_host": params.get('dnac_host'), - "dnac_port": params.get('dnac_port'), + dnac_params = {"dnac_host": params.get("dnac_host"), + "dnac_port": params.get("dnac_port"), "dnac_username": params.get("dnac_username"), "dnac_password": params.get("dnac_password"), "dnac_verify": params.get("dnac_verify"), @@ -760,6 +773,14 @@ def get_dnac_params(self, params): } return dnac_params + def get_project_params(self, params): + """Store project parameters from the playbook for template processing in DNAC""" + + project_params = {"name": params.get("projectName"), + "description": params.get("projectDescription") + } + return project_params + def get_template_params(self, params): """Store template parameters from the playbook for template processing in DNAC""" @@ -794,14 +815,14 @@ def get_template_params(self, params): } return temp_params - def get_template(self, template_config): + def get_template(self, config): """Get the template needed for updation or creation""" result = None - items = self.dnac._exec( + items = self.dnac_apply['exec']( family="configuration_templates", function="get_template_details", - params={"template_id": template_config.get("templateId")} + params={"template_id": config.get("templateId")} ) if items: result = items @@ -810,15 +831,15 @@ def get_template(self, template_config): self.result['response'] = items return result - def get_have_project(self, template_config): + def get_have_project(self, config): """Get the current project related information from DNAC""" have_create_project = {} - given_project_name = template_config.get("projectName") + given_project_name = config.get("projectName") template_available = None # Check if project exists. - project_details = self.get_project_details(template_config.get("projectName")) + project_details = self.get_project_details(config.get("projectName")) # DNAC returns project details even if the substring matches. # Hence check the projectName retrieved from DNAC. if not (project_details and isinstance(project_details, list)): @@ -838,10 +859,11 @@ def get_have_project(self, template_config): self.have_create_project = have_create_project return template_available - def get_have_template(self, template_config, template_available): + def get_have_template(self, config, template_available): """Get the current template related information from DNAC""" - project_name = template_config.get("projectName") - template_name = template_config.get("templateName") + + project_name = config.get("projectName") + template_name = config.get("templateName") template = None have_create_template = {} @@ -858,13 +880,13 @@ def get_have_template(self, template_config, template_available): self.status = "success" return self - template_config["templateId"] = template_details.get("id") + config["templateId"] = template_details.get("id") have_create_template["id"] = template_details.get("id") # Get available templates which are committed under the project - template_list = self.dnac._exec( + template_list = self.dnac_apply['exec']( family="configuration_templates", function="gets_the_templates_available", - params={"project_names": template_config.get("projectName")}, + params={"project_names": config.get("projectName")}, ) have_create_template["isCommitPending"] = True # This check will fail if specified template is there not committed in dnac @@ -873,7 +895,7 @@ def get_have_template(self, template_config, template_available): "name", template_name) if template_info: - template = self.get_template(template_config) + template = self.get_template(config) have_create_template["template"] = template have_create_template["isCommitPending"] = False have_create_template["template_found"] = template is not None \ @@ -891,12 +913,12 @@ def get_have_template(self, template_config, template_available): self.status = "success" return self - def get_have(self, template_config): + def get_have(self, config): """Get the current project and template details from DNAC""" - template_available = self.get_have_project(template_config) + template_available = self.get_have_project(config) if template_available: - self.get_have_template(template_config, template_available) + self.get_have_template(config, template_available) self.msg = "Successfully collected all project and template \ parameters from dnac for comparison" @@ -906,7 +928,7 @@ def get_have(self, template_config): def get_project_details(self, project_name): """Get the details of specific project name provided""" - items = self.dnac._exec( + items = self.dnac_apply['exec']( family="configuration_templates", function='get_projects', op_modifies=True, @@ -914,18 +936,20 @@ def get_project_details(self, project_name): ) return items - def get_want(self, template_config): + def get_want(self, config): """Get all the template and project related information from playbook that is needed to be created in DNAC""" want_create = {} - template_params = self.get_template_params(template_config) - version_comments = template_config.get("versionDescription") + template_params = self.get_template_params(config) + project_params = self.get_project_params(config) + version_comments = config.get("versionDescription") if self.params.get("state") == "merged": self.update_mandatory_parameters(template_params) want_create["template_params"] = template_params + want_create["project_params"] = project_params want_create["comments"] = version_comments self.want_create = want_create @@ -940,19 +964,20 @@ def create_project_or_template(self, is_create_project=False): creation_id = None created = False template_params = self.want_create.get("template_params") + project_params = self.want_create.get("project_params") if is_create_project: - params_key = {"name": template_params.get('projectName')} + params_key = project_params name = f"project: {template_params.get('projectName')}" validation_string = "Successfully created project" creation_value = "create_project" else: params_key = template_params - name = f"template: {template_params.get('templateName')}" + name = f"template: {template_params.get('name')}" validation_string = "Successfully created template" creation_value = "create_template" - response = self.dnac._exec( + response = self.dnac_apply['exec']( family="configuration_templates", function=creation_value, op_modifies=True, @@ -1044,7 +1069,7 @@ def get_task_details(self, task_id): """Check if the task performed is sucessfull or not""" result = None - response = self.dnac._exec( + response = self.dnac_apply['exec']( family="task", function="get_task_by_id", params={"task_id": task_id}, @@ -1103,7 +1128,7 @@ def validate_input_merge(self, template_exists): self.status = "success" return self - def get_diff_merge(self, template_config): + def get_diff_merged(self, config): """Update/Create templates and projects in DNAC with fields provided in DNAC""" is_project_found = self.have_create_project.get("project_found") @@ -1124,7 +1149,7 @@ def get_diff_merge(self, template_config): self.validate_input_merge(is_template_found).check_return_status("validate_input_merge") if is_template_found: if self.requires_update(): - response = self.dnac._exec( + response = self.dnac_apply['exec']( family="configuration_templates", function="update_template", params=template_params, @@ -1153,7 +1178,7 @@ def get_diff_merge(self, template_config): "comments": self.want_create.get("comments"), "templateId": template_id } - response = self.dnac._exec( + response = self.dnac_apply['exec']( family="configuration_templates", function="version_template", op_modifies=True, @@ -1168,7 +1193,7 @@ def get_diff_merge(self, template_config): task_details = self.get_task_details(task_id) self.result['changed'] = True self.result['msg'] = task_details.get('progress') - self.result['diff'] = template_config + self.result['diff'] = config self.log(str(task_details)) self.result['response'] = task_details if task_details else response @@ -1181,7 +1206,7 @@ def get_diff_merge(self, template_config): self.status = "success" return self - def delete_project_or_template(self, template_config, is_delete_project=False): + def delete_project_or_template(self, config, is_delete_project=False): """Call DNAC API to delete project or template with provided inputs""" template_params = self.want_create.get("template_params") @@ -1195,18 +1220,17 @@ def delete_project_or_template(self, template_config, is_delete_project=False): deletion_value = "deletes_the_template" name = f"templateName: {template_params.get('templateName')}" - response = self.dnac._exec( + response = self.dnac_apply['exec']( family="configuration_templates", function=deletion_value, params=params_key, ) - task_id = response.get("response").get("taskId") if task_id: task_details = self.get_task_details(task_id) self.result['changed'] = True self.result['msg'] = task_details.get('progress') - self.result['diff'] = template_config + self.result['diff'] = config self.log(str(task_details)) self.result['response'] = task_details if task_details else response @@ -1219,7 +1243,7 @@ def delete_project_or_template(self, template_config, is_delete_project=False): self.status = "success" return self - def get_diff_delete(self, template_config): + def get_diff_deleted(self, config): """Delete projects or templates in DNAC with fields provided in playbook.""" is_template_found = self.have_create_template.get("template_found") @@ -1233,7 +1257,7 @@ def get_diff_delete(self, template_config): if template_params.get("name"): if is_template_found: - self.delete_project_or_template(template_config) + self.delete_project_or_template(config) else: self.msg = "Invalid template Name under project" self.status = "failed" @@ -1242,7 +1266,7 @@ def get_diff_delete(self, template_config): self.log("Template is empty, deleting the project") is_project_deletable = self.have_create_project.get("isDeletable") if is_project_deletable: - self.delete_project_or_template(template_config, is_delete_project=True) + self.delete_project_or_template(config, is_delete_project=True) else: self.msg = "Project is not deletable" self.status = "failed" @@ -1281,20 +1305,20 @@ def main(): dnac_template = DnacTemplate(module) dnac_template.validate_input().check_return_status("validate_input") state = dnac_template.params.get("state") - - for template_config in dnac_template.validated: + if state == "merged": + get_diff_state_api = "get_diff_merged" + elif state == "deleted": + get_diff_state_api = "get_diff_deleted" + else: + dnac_template.status = "invalid" + dnac_template.msg = f"State {state} is invalid" + dnac_template.check_return_status("main") + + for config in dnac_template.validated_config: dnac_template.reset_values() - dnac_template.get_have(template_config).check_return_status("get_have") - dnac_template.get_want(template_config).check_return_status("get_want") - - if state == "merged": - dnac_template.get_diff_merge(template_config).check_return_status("get_diff_merge") - elif state == "deleted": - dnac_template.get_diff_delete(template_config).check_return_status("get_diff_delete") - else: - dnac_template.status = "invalid" - dnac_template.msg = f"State {state} is invalid" - dnac_template.check_return_status("main") + dnac_template.get_have(config).check_return_status("get_have") + dnac_template.get_want(config).check_return_status("get_want") + dnac_template.get_diff_state_apply[state](config).check_return_status(get_diff_state_api) module.exit_json(**dnac_template.result) From 8ac93fb59db82b98eee4652093b0ff1fbb891b38 Mon Sep 17 00:00:00 2001 From: akabhask Date: Tue, 29 Aug 2023 23:56:10 +0530 Subject: [PATCH 08/13] Moving generic api's to library and optimising intent modules --- plugins/module_utils/dnac.py | 78 +++++++++++++++++++++- plugins/modules/template_intent.py | 103 +++++------------------------ 2 files changed, 94 insertions(+), 87 deletions(-) diff --git a/plugins/module_utils/dnac.py b/plugins/module_utils/dnac.py index e9d61527de..8c1c8081e5 100644 --- a/plugins/module_utils/dnac.py +++ b/plugins/module_utils/dnac.py @@ -21,13 +21,87 @@ else: LOGGING_IN_STANDARD = True import os.path +import copy import datetime import inspect +class DnacBase: + """Class contains members which can be reused for all intent modules""" + def __init__(self, module): + self.module = module + self.params = module.params + self.config = copy.deepcopy(module.params.get("config")) + self.have_create = {} + self.want_create = {} + self.validated_config = [] + self.msg = "" + self.status = "success" + dnac_params = self.get_dnac_params(self.params) + self.dnac = DNACSDK(params=dnac_params) + self.dnac_apply = {'exec': self.dnac._exec} + self.get_diff_state_apply = {'merged': self.get_diff_merged, + 'deleted': self.get_diff_deleted} + self.dnac_log = dnac_params.get("dnac_log") + self.log(str(dnac_params)) + self.supported_states = ["merged", "deleted"] + self.result = {"changed": False, "diff": [], "response": [], "warnings": []} + + def log(self, message, frameIncrement = 0): + """Log messages into dnac.log file""" + + if self.dnac_log: + message = "Module: " + self.__class__.__name__ + ", " + message + log(message, (1 + frameIncrement)) + + def check_return_status(self): + """API to check the return status value and exit/fail the module""" + + self.log(f"status: {self.status}, msg:{self.msg}", frameIncrement = 1) + if "failed" in self.status: + self.module.fail_json(msg=self.msg, response=[]) + elif "exited" in self.status: + self.module.exit_json(**self.result) + elif "invalid" in self.status: + self.module.fail_json(msg=self.msg, response=[]) + + def get_dnac_params(self, params): + """Store the DNAC parameters from the playbook""" + + dnac_params = {"dnac_host": params.get("dnac_host"), + "dnac_port": params.get("dnac_port"), + "dnac_username": params.get("dnac_username"), + "dnac_password": params.get("dnac_password"), + "dnac_verify": params.get("dnac_verify"), + "dnac_debug": params.get("dnac_debug"), + "dnac_log": params.get("dnac_log") + } + return dnac_params + + def get_task_details(self, task_id): + """Check if the task performed is sucessfull or not""" -def log(msg): + result = None + response = self.dnac_apply['exec']( + family="task", + function="get_task_by_id", + params={"task_id": task_id}, + ) + + self.log(str(response)) + if isinstance(response, dict): + result = response.get("response") + + return result + + def reset_values(self): + """Reset all neccessary attributes to default values""" + + self.have_create.clear() + self.want_create.clear() + +def log(msg, frameIncrement = 0): with open('dnac.log', 'a') as of: - callerframerecord = inspect.stack()[1] + callerframerecord = inspect.stack()[1 + frameIncrement] frame = callerframerecord[0] info = inspect.getframeinfo(frame) d = datetime.datetime.now().replace(microsecond=0).isoformat() diff --git a/plugins/modules/template_intent.py b/plugins/modules/template_intent.py index 1dd1427e63..09c01bf3c2 100644 --- a/plugins/modules/template_intent.py +++ b/plugins/modules/template_intent.py @@ -655,56 +655,22 @@ } """ -import copy from ansible.module_utils.basic import AnsibleModule from ansible_collections.cisco.dnac.plugins.module_utils.dnac import ( - DNACSDK, + DnacBase, validate_list_of_dicts, - log, get_dict_result, dnac_compare_equality, ) -class DnacTemplate: +class DnacTemplate(DnacBase): """Class containing member attributes for template intent module""" def __init__(self, module): - self.module = module - self.params = module.params - self.config = copy.deepcopy(module.params.get("config")) + super().__init__(module) self.have_create_project = {} self.have_create_template = {} - self.want_create = {} - self.validated_config = [] - self.msg = "" - self.status = "success" self.accepted_languages = ["JINJA", "VELOCITY"] - dnac_params = self.get_dnac_params(self.params) - self.dnac = DNACSDK(params=dnac_params) - self.dnac_apply = {'exec': self.dnac._exec} - self.get_diff_state_apply = {'merged': self.get_diff_merged, - 'deleted': self.get_diff_deleted} - self.dnac_log = dnac_params.get("dnac_log") - self.log(str(dnac_params)) - self.result = {"changed": False, "diff": [], "response": [], "warnings": []} - - def log(self, message): - """Log messages into dnac.log file""" - - if self.dnac_log: - message = self.__class__.__name__ + " " + message - log(message) - - def check_return_status(self, api_name): - """API to check the return status value and exit/fail the module""" - - self.log(f"API:{api_name}, msg:{self.msg}, status: {self.status}") - if "failed" in self.status: - self.module.fail_json(msg=self.msg, response=[]) - elif "exited" in self.status: - self.module.exit_json(**self.result) - elif "invalid" in self.status: - self.module.fail_json(msg=self.msg, response=[]) def validate_input(self): """Validate the fields provided in the playbook""" @@ -760,19 +726,6 @@ def validate_input(self): self.status = "success" return self - def get_dnac_params(self, params): - """Store the DNAC parameters from the playbook""" - - dnac_params = {"dnac_host": params.get("dnac_host"), - "dnac_port": params.get("dnac_port"), - "dnac_username": params.get("dnac_username"), - "dnac_password": params.get("dnac_password"), - "dnac_verify": params.get("dnac_verify"), - "dnac_debug": params.get("dnac_debug"), - "dnac_log": params.get("dnac_log") - } - return dnac_params - def get_project_params(self, params): """Store project parameters from the playbook for template processing in DNAC""" @@ -839,16 +792,16 @@ def get_have_project(self, config): template_available = None # Check if project exists. - project_details = self.get_project_details(config.get("projectName")) + project_details = self.get_project_details(given_project_name) # DNAC returns project details even if the substring matches. # Hence check the projectName retrieved from DNAC. if not (project_details and isinstance(project_details, list)): - self.log("Project not found, need to create new project in DNAC") + self.log(f"Project: {given_project_name} not found, need to create new project in DNAC") return None fetched_project_name = project_details[0].get('name') if fetched_project_name != given_project_name: - self.log("Project name provided is not exact match in DNAC DB") + self.log(f"Project {given_project_name} provided is not exact match in DNAC DB") return None template_available = project_details[0].get('templates') @@ -876,7 +829,7 @@ def get_have_template(self, config, template_available): # Check if specified template in playbook is available if not template_details: self.log(f"Template {template_name} not found in project {project_name}") - self.msg = "Found template : {template_name} missing, new template to be created" + self.msg = "Template : {template_name} missing, new template to be created" self.status = "success" return self @@ -989,7 +942,7 @@ def create_project_or_template(self, is_create_project=False): task_id = response.get("response").get("taskId") if not task_id: - self.log("Task id not found") + self.log(f"Task id {task_id} not found") return creation_id, created while not created: @@ -1065,22 +1018,6 @@ def requires_update(self): requested_obj.get(ansible_param)) for (dnac_param, ansible_param, default) in obj_params) - def get_task_details(self, task_id): - """Check if the task performed is sucessfull or not""" - - result = None - response = self.dnac_apply['exec']( - family="task", - function="get_task_by_id", - params={"task_id": task_id}, - ) - - self.log(str(response)) - if isinstance(response, dict): - result = response.get("response") - - return result - def update_mandatory_parameters(self, template_params): """Update parameters which are mandatory for creating a template""" @@ -1146,7 +1083,7 @@ def get_diff_merged(self, config): self.msg = "Project creation failed" return self - self.validate_input_merge(is_template_found).check_return_status("validate_input_merge") + self.validate_input_merge(is_template_found).check_return_status() if is_template_found: if self.requires_update(): response = self.dnac_apply['exec']( @@ -1187,7 +1124,7 @@ def get_diff_merged(self, config): task_details = {} task_id = response.get("response").get("taskId") if not task_id: - self.msg = "Task id not found" + self.msg = f"Task id: {task_id} not found" self.status = "failed" return self task_details = self.get_task_details(task_id) @@ -1249,9 +1186,10 @@ def get_diff_deleted(self, config): is_template_found = self.have_create_template.get("template_found") is_project_found = self.have_create_project.get("project_found") template_params = self.want_create.get("template_params") + projectName = template_params.get('projectName') if not is_project_found: - self.msg = "Project not found, provide valid projectName" + self.msg = f"Project {projectName} provide valid projectName" self.status = "failed" return self @@ -1299,26 +1237,21 @@ def main(): 'config': {'required': True, 'type': 'list', 'elements': 'dict'}, 'state': {'default': 'merged', 'choices': ['merged', 'deleted']} } - module = AnsibleModule(argument_spec=element_spec, supports_check_mode=False) dnac_template = DnacTemplate(module) - dnac_template.validate_input().check_return_status("validate_input") + dnac_template.validate_input().check_return_status() state = dnac_template.params.get("state") - if state == "merged": - get_diff_state_api = "get_diff_merged" - elif state == "deleted": - get_diff_state_api = "get_diff_deleted" - else: + if state not in dnac_template.supported_states: dnac_template.status = "invalid" dnac_template.msg = f"State {state} is invalid" - dnac_template.check_return_status("main") + dnac_template.check_return_status() for config in dnac_template.validated_config: dnac_template.reset_values() - dnac_template.get_have(config).check_return_status("get_have") - dnac_template.get_want(config).check_return_status("get_want") - dnac_template.get_diff_state_apply[state](config).check_return_status(get_diff_state_api) + dnac_template.get_have(config).check_return_status() + dnac_template.get_want(config).check_return_status() + dnac_template.get_diff_state_apply[state](config).check_return_status() module.exit_json(**dnac_template.result) From 2b301295317f7aa657aea2f6e348a99feb6d4486 Mon Sep 17 00:00:00 2001 From: Madhan Date: Thu, 31 Aug 2023 17:21:27 +0530 Subject: [PATCH 09/13] Delete network_intent.py Deleting the file from the main branch. --- plugins/modules/network_intent.py | 1175 ----------------------------- 1 file changed, 1175 deletions(-) delete mode 100644 plugins/modules/network_intent.py diff --git a/plugins/modules/network_intent.py b/plugins/modules/network_intent.py deleted file mode 100644 index 32d1116a65..0000000000 --- a/plugins/modules/network_intent.py +++ /dev/null @@ -1,1175 +0,0 @@ - -# This module will work for global_pool, Reserve_ip_pool and network (under network it will not work for network_aaa and clientEndpoint_aaa) - -import copy - -try: - from ansible_collections.ansible.utils.plugins.module_utils.common.argspec_validate import ( - AnsibleArgSpecValidator, - ) -except ImportError: - ANSIBLE_UTILS_IS_INSTALLED = False -else: - ANSIBLE_UTILS_IS_INSTALLED = True -from ansible_collections.cisco.dnac.plugins.module_utils.dnac import ( - DNACSDK, - dnac_argument_spec, - validate_list_of_dicts, - log, - get_dict_result, - dnac_compare_equality, -) -from ansible.module_utils.basic import AnsibleModule - - -class DnacNetwork: - def __init__(self, module): - self.module = module - self.params = module.params - self.config = copy.deepcopy(module.params.get("config")) - self.have = {} - self.want = {} - self.have_reserve = {} - self.want_reserve = {} - self.have_net = {} - self.want_net = {} - self.site_id = None - self.validated = [] - dnac_params = self.get_dnac_params(self.params) - log(str(dnac_params)) - self.dnac = DNACSDK(params=dnac_params) - self.log = dnac_params.get("dnac_log") - - self.result = dict(changed=False, diff=[], response=[], warnings=[]) - - def get_state(self): - return self.params.get("state") - - def validate_input(self): - temp_spec = { - "IpAddressSpace": {"required": False, "type": 'string'}, - "dhcpServerIps": {"required": False, "type": 'list'}, - "dnsServerIps": {"required": False, "type": 'list'}, - "gateway": {"required": False, "type": 'string'}, - "ipPoolCidr": {"required": False, "type": 'string'}, - "ipPoolName": {"required": False, "type": 'string'}, - "name": {"required": False, "type": 'string'}, - "prev_name": {"required": False, "type": 'string'}, - "type": {"required": False, "type": "string", \ - "choices": ["Generic", "tunnel", "LAN", "WAN", "management", "service"]}, - "ipv6AddressSpace": {"required": False, "type": 'string'}, - "ipv4GlobalPool": {"required": False, "type": 'string'}, - "ipv4Prefix": {"required": False, "type": 'string'}, - "ipv4PrefixLength": {"required": False, "type": 'string'}, - "ipv4GateWay": {"required": False, "type": 'string'}, - "ipv4DhcpServers": {"required": False, "type": 'list'}, - "ipv4DnsServers": {"required": False, "type": 'list'}, - "ipv6GlobalPool": {"required": False, "type": 'string'}, - "ipv6Prefix": {"required": False, "type": 'string'}, - "ipv6PrefixLength": {"required": False, "type": 'integer'}, - "ipv6GateWay": {"required": False, "type": 'string'}, - "ipv6DhcpServers": {"required": False, "type": 'list'}, - "ipv6DnsServers": {"required": False, "type": 'list'}, - "ipv4TotalHost": {"required": False, "type": 'integer'}, - "ipv6TotalHost": {"required": False, "type": 'integet'}, - "slaacSupport": {"required": False, "type": 'string'}, - "siteName": {"required": False, "type": 'string'}, - "dhcpServer": {"required": False, "type": 'list'}, - "domainName": {"required": False, "type": 'string'}, - "primaryIpAddress": {"required": False, "type": 'string'}, - "secondaryIpAddress": {"required": False, "type": 'string'} - } - if self.config: - msg = None - temp = [] - temp1 = [] - temp2 = [] - # Validate template params - if self.config[0].get("GlobalPoolDetails") is not None: - temp = self.config[0].get("GlobalPoolDetails").get("settings").get("ippool") - if self.config[0].get("ReservePoolDetails") is not None: - temp1 = [self.config[0].get("ReservePoolDetails")] - if self.config[0].get("NetworkManagementDetails") is not None: - temp2.append(self.config[0].get("NetworkManagementDetails") \ - .get("settings").get("dhcpServer")) - temp2.append(self.config[0].get("NetworkManagementDetails") \ - .get("settings").get("dnsServer").get("domainName")) - temp2.append(self.config[0].get("NetworkManagementDetails") \ - .get("settings").get("dnsServer").get("primaryIpAddress")) - temp2.append(self.config[0].get("NetworkManagementDetails") \ - .get("settings").get("dnsServer").get("secondaryIpAddress")) - - temp = temp + temp1 - valid_temp, invalid_params = validate_list_of_dicts( - temp, temp_spec - ) - if invalid_params: - msg = "Invalid parameters in playbook: {0}".format( - "\n".join(invalid_params) - ) - self.module.fail_json(msg=msg) - log(str(invalid_params)) - self.validated = valid_temp - - if self.log: - log(str(valid_temp)) - log(str(self.result)) - - log(str(self.validated)) - if self.params.get("config")[0].get("GlobalPoolDetails") is not None: - for temp in self.validated: - log(str(temp)) - if self.params.get("config")[0].get("GlobalPoolDetails") \ - .get("ipPoolName") is not None: - msg = "missing required arguments: ipPoolName" - self.module.fail_json(msg=msg) - - def get_dnac_params(self, params): - dnac_params = dict( - dnac_host=params.get("dnac_host"), - dnac_port=params.get("dnac_port"), - dnac_username=params.get("dnac_username"), - dnac_password=params.get("dnac_password"), - dnac_verify=params.get("dnac_verify"), - dnac_debug=params.get("dnac_debug"), - dnac_log=params.get("dnac_log"), - ) - return dnac_params - - - def requires_update(self, have, want, obj_params): - current_obj = have - requested_obj = want - log(str(current_obj)) - log(str(requested_obj)) - - return any(not dnac_compare_equality(current_obj.get(dnac_param), - requested_obj.get(ansible_param)) - for(dnac_param, ansible_param) in obj_params) - - - def get_pool_id_from_name(self, pool_name): - pool_id = None - current_details = None - - try: - response = self.dnac._exec( - family = "network_settings", - function = "get_global_pool", - ) - - if isinstance(response, dict): - if "response" in response: - response = response.get("response") - log(str(response)) - current_details = get_dict_result(response, "ipPoolName", pool_name) - log(str(current_details)) - if current_details: - pool_id = current_details.get("id") - - except: - result = None - - return (pool_id, current_details) - - - def get_res_id_from_name(self, res_name): - _id = "" - current_details = None - try: - response = self.dnac._exec( - family="network_settings", - function="get_reserve_ip_subpool", - params={"site_id": self.site_id} - ) - - if isinstance(response, dict): - if "response" in response: - response = response.get("response") - log(str(response)) - current_details = get_dict_result(response, "groupName", res_name) - log(str(current_details)) - - _id = current_details.get("id") - except: - log("except") - result = None - return _id - - - def get_current_pool(self, pool): - log(str(pool)) - pool_values = { - "settings": { - "ippool": [{ - "dhcpServerIps": pool.get("dhcpServerIps"), - "dnsServerIps": pool.get("dnsServerIps"), - "ipPoolCidr": pool.get("ipPoolCidr"), - "ipPoolName": pool.get("ipPoolName"), - "type": pool.get("type") - }] - } - } - log(str(pool_values)) - if pool.get("ipv6") is False: - pool_values.get("settings").get("ippool")[0].update({"IpAddressSpace": "IPv4"}) - log("ipv6 - false") - else: - pool_values.get("settings").get("ippool")[0].update({"IpAddressSpace": "IPv6"}) - log("ipv6 - true") - if not pool["gateways"]: - pool_values.get("settings").get("ippool")[0].update({"gateway": ""}) - else: - pool_values.get("settings").get("ippool")[0] \ - .update({"gateway": pool.get("gateways")[0]}) - - return pool_values - - - def get_current_res(self, res): - log(str(res)) - res_values = dict( - name = res.get("groupName"), - site_id = res.get("siteId"), - ) - - if len(res.get("ipPools")) == 1: - res_values.update({"ipv4DhcpServers": res.get("ipPools")[0].get("dhcpServerIps")}) - res_values.update({"ipv4DnsServers": res.get("ipPools")[0].get("dnsServerIps")}) - res_values.update({"ipv4GateWay": res.get("ipPools")[0].get("gateways")[0]}) - res_values.update({"ipv6AddressSpace": "False"}) - - elif len(res.get("ipPools")) == 2: - if res.get("ipPools")[0].get("ipv6") is False: - res_values.update({"ipv4DhcpServers": res.get("ipPools")[0].get("dhcpServerIps")}) - res_values.update({"ipv4DnsServers": res.get("ipPools")[0].get("dnsServerIps")}) - res_values.update({"ipv4GateWay": res.get("ipPools")[0].get("gateways")[0]}) - res_values.update({"ipv6AddressSpace": "True"}) - res_values.update({"ipv4DhcpServers": res.get("ipPools")[1].get("dhcpServerIps")}) - res_values.update({"ipv4DnsServers": res.get("ipPools")[1].get("dnsServerIps")}) - res_values.update({"ipv4GateWay": res.get("ipPools")[1].get("gateways")[0]}) - - elif res.get("ipPools")[1].get("ipv6") is False: - res_values.update({"ipv4DhcpServers": res.get("ipPools")[1].get("dhcpServerIps")}) - res_values.update({"ipv4DnsServers": res.get("ipPools")[1].get("dnsServerIps")}) - res_values.update({"ipv4GateWay": res.get("ipPools")[1].get("gateways")[0]}) - res_values.update({"ipv6AddressSpace": "True"}) - res_values.update({"ipv4DhcpServers": res.get("ipPools")[0].get("dhcpServerIps")}) - res_values.update({"ipv4DnsServers": res.get("ipPools")[0].get("dnsServerIps")}) - res_values.update({"ipv4GateWay": res.get("ipPools")[0].get("gateways")[0]}) - - return res_values - - - def get_current_net(self, site_id): - log(str(site_id)) - response = None - - try: - response = self.dnac._exec( - family="network_settings", - function='get_network', - params={"site_id": site_id} - ) - - except: - result = None - log(str(response)) - - if isinstance(response, dict): - if "response" in response: - response = response.get("response") - - dhcp_details = get_dict_result(response, "key", "dhcp.server") - dns_details = get_dict_result(response, "key", "dns.server") - snmp_details = get_dict_result(response, "key", "snmp.trap.receiver") - syslog_details = get_dict_result(response, "key", "syslog.server") - netflow_details = get_dict_result(response, "key", "netflow.collector") - ntpserver_details = get_dict_result(response, "key", "ntp.server") - timezone_details = get_dict_result(response, "key", "timezone.site") - messageoftheday_details = get_dict_result(response, "key", "device.banner") - - snmp_details - log(str(dhcp_details)) - log(str(dns_details)) - - net_values = { - "settings": { - "dhcpServer": dhcp_details.get("value"), - "dnsServer": { - "domainName": dns_details.get("value")[0].get("domainName"), - "primaryIpAddress": dns_details.get("value")[0].get("primaryIpAddress"), - "secondaryIpAddress": dns_details.get("value")[0].get("secondaryIpAddress") - }, - "snmpServer": { - "configureDnacIP": snmp_details.get("value")[0].get("configureDnacIP"), - "ipAddresses": snmp_details.get("value")[0].get("ipAddresses"), - }, - "syslogServer": { - "configureDnacIP": syslog_details.get("value")[0].get("configureDnacIP"), - "ipAddresses": syslog_details.get("value")[0].get("ipAddresses"), - }, - "netflowcollector": { - "ipAddress": netflow_details.get("value")[0].get("ipAddress"), - "port": netflow_details.get("value")[0].get("port"), - "configureDnacIP": netflow_details.get("value")[0].get("configureDnacIP"), - }, - "ntpServer": ntpserver_details.get("value"), - "timezone": timezone_details.get("value")[0], - "messageOfTheday": { - "bannerMessage": messageoftheday_details.get("value")[0].get("bannerMessage"), - "retainExistingBanner": messageoftheday_details.get("value")[0].get("retainExistingBanner"), - } - - - } - } - - return net_values - - def get_site_id(self, site_name): - - response = {} - _id = None - try: - response = self.dnac._exec( - family="sites", - function='get_site', - params={"name":site_name}, - ) - - except: - result = None - log(str(response)) - if not response: - log("Invalid site name or site not present") - self.result["response"] = [] - self.result["msg"] = "Invalid site name or site not present" - self.module.fail_json(**self.result) - else: - _id = response.get("response")[0].get("id") - log(str(_id)) - - return _id - - - def pool_exists(self): - pool_exists = False - pool_details = {} - pool_id = None - response = None - name = None - - #get it from validated - - name = self.params.get("config")[0].get("GlobalPoolDetails") \ - .get("settings").get("ippool")[0].get("ipPoolName") - try: - - response = self.dnac._exec( - family = "network_settings", - function = "get_global_pool", - ) - log(str(response)) - if isinstance(response, dict): - if "response" in response: - response = response.get("response") - - current_details = get_dict_result(response, "ipPoolName", name) - log(str(current_details)) - if current_details: - pool_exists = True - pool_id = current_details.get("id") - elif self.config[0].get("GlobalPoolDetails").get("settings") \ - .get("ippool")[0].get("prev_name") is not None: - - pool_id = None - (pool_id, current_details) = self.get_pool_id_from_name(self.config[0]. \ - get("GlobalPoolDetails").get("settings").get("ippool")[0].get("prev_name")) - - if pool_id is None: - msg = "Prev name doesn't exist\n" - self.module.fail_json(msg=msg) - pool_exists = True - current_details = get_dict_result(response, "id", pool_id) - log(str(current_details)) - pool_details = self.get_current_pool(current_details) - except Exception: - result = None - - log(str(pool_details)) - log(str(pool_id)) - return (pool_exists, pool_details, pool_id) - - - def res_exists(self): - current_details = None - res_exists = False - res_details = None - res_id = None - response = None - site_name = None - _id = "" - site_name = self.params.get("config")[0].get("ReservePoolDetails").get("siteName") - log(str(site_name)) - - if site_name is not None: - site_id = self.get_site_id(site_name) - self.site_id = site_id - - name = self.config[0].get("ReservePoolDetails").get("name") - prev_name = self.config[0].get("ReservePoolDetails").get("prev_name") - - if prev_name: - if not self.params.get("config")[0].get("ReservePoolDetails").get("siteName"): - msg = "Mandatory Parameter siteName required\n" - self.module.fail_json(msg=msg) - _id = self.get_res_id_from_name(prev_name) - - log(str(_id)) - try: - response = self.dnac._exec( - family="network_settings", - function="get_reserve_ip_subpool", - params={"siteId":self.site_id} - ) - if isinstance(response, dict): - if "response" in response: - response = response.get("response") - log(str(response)) - - if _id: - current_details = get_dict_result(response, "id", _id) - elif name: - current_details = get_dict_result(response, "groupName", name) - - log(str(current_details)) - - if current_details: - res_exists = True - res_id = current_details.get("id") - res_details = self.get_current_res(current_details) - except Exception: - result = None - - log(str(res_details)) - log(str(res_id)) - return (res_exists, res_details, res_id) - - - def get_have(self): - pool_exists = False - pool_details = None - pool_id = None - - res_exists = False - res_details = None - res_id = None - - #checking if the pool is already exists or not - - if self.params.get("config")[0].get("GlobalPoolDetails") is not None: - have = {} - (pool_exists, pool_details, pool_id) = self.pool_exists() - - if self.log: - log("pool Exists: " + str(pool_exists) + "\n Current Site: " + str(pool_details)) - - if pool_exists: - have["pool_id"] = pool_id - have["pool_exists"] = pool_exists - have["pool_details"] = pool_details - log(str(pool_details)) - - self.have = have - - if self.params.get("config")[0].get("ReservePoolDetails") is not None: - have_reserve = {} - (res_exists, res_details, res_id) = self.res_exists() - - if self.log: - log("Reservation Exists: " + str(res_exists) \ - + "\n Reserved Pool: " + str(res_details)) - - if res_exists: - have_reserve["res_exists"] = res_exists - have_reserve["res_id"] = res_id - have_reserve["res_details"] = res_details - if have_reserve.get("res_details").get("ipv6AddressSpace") == "False": - have_reserve.get("res_details").update({"ipv6AddressSpace": False}) - elif have_reserve.get("res_details").get("ipv6AddressSpace") == "True": - have_reserve.get("res_details").update({"ipv6AddressSpace": True}) - - - self.have_reserve = have_reserve - - if self.params.get("config")[0].get("NetworkManagementDetails") is not None: - - have_net = {} - site_name = self.params.get("config")[0].get("NetworkManagementDetails").get("siteName") - - if site_name is None: - self.module.fail_json(msg="Mandatory Parameter siteName missings", response=[]) - - site_id_net = self.get_site_id(site_name) - - if site_id_net is None: - self.module.fail_json(msg="Invalid siteName", response=[]) - - have_net["site_id"] = site_id_net - have_net["net_details"] = self.get_current_net(site_id_net) - - self.have_net = have_net - - - def get_want(self): - if self.params.get("config")[0].get("GlobalPoolDetails") is not None: - want = {} - IpAddressSpace = self.params.get("config")[0] \ - .get("GlobalPoolDetails").get("settings").get("ippool")[0] - dhcpServerIps = self.params.get("config")[0] \ - .get("GlobalPoolDetails").get("settings").get("ippool")[0] - dnsServerIps = self.params.get("config")[0] \ - .get("GlobalPoolDetails").get("settings").get("ippool")[0] - gateway = self.params.get("config")[0] \ - .get("GlobalPoolDetails").get("settings").get("ippool")[0] - ipPoolCidr = self.params.get("config")[0] \ - .get("GlobalPoolDetails").get("settings").get("ippool")[0] - ipPoolName = self.params.get("config")[0] \ - .get("GlobalPoolDetails").get("settings").get("ippool")[0] - _type = self.params.get("config")[0] \ - .get("GlobalPoolDetails").get("settings").get("ippool")[0] - - want = { - "settings": { - "ippool": [{ - "IpAddressSpace": IpAddressSpace.get("IpAddressSpace"), - "dhcpServerIps": dhcpServerIps.get("dhcpServerIps"), - "dnsServerIps": dnsServerIps.get("dnsServerIps"), - "gateway": gateway.get("gateway"), - "ipPoolCidr": ipPoolCidr.get("ipPoolCidr"), - "ipPoolName": ipPoolName.get("ipPoolName"), - "type": _type.get("type"), - }] - } - } - log(str(self.have)) - if not self.have.get("pool_exists"): - if want.get("settings").get("ippool")[0].get("dhcpServerIps") is None: - want.get("settings").get("ippool")[0].update({"dhcpServerIps": []}) - if want.get("settings").get("ippool")[0].get("dnsServerIps") is None: - want.get("settings").get("ippool")[0].update({"dnsServerIps": []}) - if want.get("settings").get("ippool")[0].get("IpAddressSpace") is None: - want.get("settings").get("ippool")[0].update({"IpAddressSpace": ""}) - if want.get("settings").get("ippool")[0].get("gateway") is None: - want.get("settings").get("ippool")[0].update({"gateway": ""}) - if want.get("settings").get("ippool")[0].get("type") is None: - want.get("settings").get("ippool")[0].update({"type": "Generic"}) - - else: - if self.have.get("pool_details").get("settings") \ - .get("ippool")[0].get("IpAddressSpace") == "IPv4": - - want.get("settings").get("ippool")[0].update({"IpAddressSpace": "IPv4"}) - log("true") - - elif self.have.get("pool_details").get("settings") \ - .get("ippool")[0].get("IpAddressSpace") == "Ipv6": - - want.get("settings").get("ippool")[0].update({"IpAddressSpace": "IPv6"}) - log("false") - - want.get("settings").get("ippool")[0].update({"type": self.have. \ - get("pool_details").get("settings").get("ippool")[0].get("ipPoolType")}) - want.get("settings").get("ippool")[0].update({"ipPoolCidr": \ - self.have.get("pool_details").get("settings") \ - .get("ippool")[0].get("ipPoolCidr")}) - - if want.get("settings").get("ippool")[0].get("dhcpServerIps") is None and \ - self.have.get("pool_details").get("settings") \ - .get("ippool")[0].get("dhcpServerIps") is not None: - want.get("settings").get("ippool")[0].update({"dhcpServerIps": \ - self.have.get("pool_details").get("settings") \ - .get("ippool")[0].get("dhcpServerIps")}) - - if want.get("settings").get("ippool")[0].get("dnsServerIps") is None and \ - self.have.get("pool_details").get("settings") \ - .get("ippool")[0].get("dnsServerIps") is not None: - - want.get("settings").get("ippool")[0].update({"dnsServerIps": \ - self.have.get("pool_details").get("settings") \ - .get("ippool")[0].get("dnsServerIps")}) - - if want.get("settings").get("ippool")[0].get("gateway") is None and \ - self.have.get("pool_details").get("settings") \ - .get("ippool")[0].get("gateway") is not None: - - want.get("settings").get("ippool")[0].update({"gateway": \ - self.have.get("pool_details").get("settings") \ - .get("ippool")[0].get("gateway")}) - - log(str(want)) - self.want = want - - if self.params.get("config")[0].get("ReservePoolDetails") is not None: - - want_reserve = { - "name": self.params.get("config")[0].get("ReservePoolDetails").get("name"), - "type": self.params.get("config")[0].get("ReservePoolDetails").get("type"), - "ipv6AddressSpace": self.params.get("config")[0] \ - .get("ReservePoolDetails").get("ipv6AddressSpace"), - "ipv4GlobalPool": self.params.get("config")[0] \ - .get("ReservePoolDetails").get("ipv4GlobalPool"), - "ipv4Prefix": self.params.get("config")[0] \ - .get("ReservePoolDetails").get("ipv4Prefix"), - "ipv4PrefixLength": self.params.get("config")[0] \ - .get("ReservePoolDetails").get("ipv4PrefixLength"), - "ipv4GateWay": self.params.get("config")[0] \ - .get("ReservePoolDetails").get("ipv4GateWay"), - "ipv4DhcpServers": self.params.get("config")[0] \ - .get("ReservePoolDetails").get("ipv4DhcpServers"), - "ipv4DnsServers": self.params.get("config")[0] \ - .get("ReservePoolDetails").get("ipv4DnsServers"), - "ipv6GlobalPool": self.params.get("config")[0] \ - .get("ReservePoolDetails").get("ipv6GlobalPool"), - "ipv6Prefix": self.params.get("config")[0] \ - .get("ReservePoolDetails").get("ipv6Prefix"), - "ipv6PrefixLength": self.params.get("config")[0] \ - .get("ReservePoolDetails").get("ipv6PrefixLength"), - "ipv6GateWay": self.params.get("config")[0] \ - .get("ReservePoolDetails").get("ipv6GateWay"), - "ipv6DhcpServers": self.params.get("config")[0] \ - .get("ReservePoolDetails").get("ipv6DhcpServers"), - "ipv6DnsServers": self.params.get("config")[0] \ - .get("ReservePoolDetails").get("ipv6DnsServers"), - "ipv4TotalHost": self.params.get("config")[0] \ - .get("ReservePoolDetails").get("ipv4TotalHost"), - "ipv6TotalHost": self.params.get("config")[0] \ - .get("ReservePoolDetails").get("ipv6TotalHost") - } - - log(str(self.have_reserve)) - if not self.have_reserve: - if want_reserve.get("type") is None: - want_reserve.update({"type": "Generic"}) - if want_reserve.get("ipv4GateWay") is None: - want_reserve.update({"ipv4GateWay": ""}) - if want_reserve.get("ipv4DhcpServers") is None: - want_reserve.update({"ipv4DhcpServers": []}) - if want_reserve.get("ipv4DnsServers") is None: - want_reserve.update({"ipv4DnsServers": []}) - if want_reserve.get("ipv6AddressSpace") is None: - want_reserve.update({"ipv6AddressSpace": False}) - if want_reserve.get("slaacSupport") is None: - want_reserve.update({"slaacSupport": True}) - if want_reserve.get("ipv4TotalHost") is None: - del want_reserve['ipv4TotalHost'] - if want_reserve.get("ipv6Prefix") is None and \ - want_reserve.get("ipv6AddressSpace") is True: - - want_reserve.update({"ipv6Prefix": True}) - else: - del want_reserve['ipv6Prefix'] - if want_reserve.get("ipv6AddressSpace") is False: - if want_reserve.get("ipv6GlobalPool") is None: - del want_reserve['ipv6GlobalPool'] - if want_reserve.get("ipv6PrefixLength") is None: - del want_reserve['ipv6PrefixLength'] - if want_reserve.get("ipv6GateWay") is None: - del want_reserve['ipv6GateWay'] - if want_reserve.get("ipv6DhcpServers") is None: - del want_reserve['ipv6DhcpServers'] - if want_reserve.get("ipv6DnsServers") is None: - del want_reserve['ipv6DnsServers'] - if want_reserve.get("ipv6TotalHost") is None: - del want_reserve['ipv6TotalHost'] - - else: - del want_reserve['type'] - del want_reserve['ipv4GlobalPool'] - del want_reserve['ipv4Prefix'] - del want_reserve['ipv4PrefixLength'] - del want_reserve['ipv4TotalHost'] - - self.want_reserve = want_reserve - - if self.params.get("config")[0].get("NetworkManagementDetails") is not None: - log(str(self.params)) - want_net = { - "settings": { - "dhcpServer": self.params.get("config")[0].get("NetworkManagementDetails") \ - .get("settings").get("dhcpServer"), - "dnsServer": { - "domainName": self.params.get("config")[0].get("NetworkManagementDetails") \ - .get("settings").get("dnsServer").get("domainName"), - "primaryIpAddress": self.params.get("config")[0] \ - .get("NetworkManagementDetails").get("settings") \ - .get("dnsServer").get("primaryIpAddress"), - "secondaryIpAddress": self.params.get("config")[0] \ - .get("NetworkManagementDetails").get("settings") \ - .get("dnsServer").get("secondaryIpAddress") - }, - "snmpServer": { - "configureDnacIP": self.params.get("config")[0].get("NetworkManagementDetails") \ - .get("settings").get("snmpServer").get("configureDnacIP"), - "ipAddresses": self.params.get("config")[0].get("NetworkManagementDetails") \ - .get("settings").get("snmpServer").get("ipAddresses") - }, - "syslogServer": { - "configureDnacIP": self.params.get("config")[0].get("NetworkManagementDetails") \ - .get("settings").get("syslogServer").get("configureDnacIP"), - "ipAddresses": self.params.get("config")[0].get("NetworkManagementDetails") \ - .get("settings").get("syslogServer").get("ipAddresses") - }, - "netflowcollector": { - "ipAddress": self.params.get("config")[0].get("NetworkManagementDetails") \ - .get("settings").get("netflowcollector").get("ipAddress"), - "port": self.params.get("config")[0].get("NetworkManagementDetails") \ - .get("settings").get("netflowcollector").get("port"), - "configureDnacIP": self.params.get("config")[0].get("NetworkManagementDetails") \ - .get("settings").get("netflowcollector").get("configureDnacIP") - }, - "ntpServer": self.params.get("config")[0].get("NetworkManagementDetails") \ - .get("settings").get("ntpServer"), - "timezone": self.params.get("config")[0].get("NetworkManagementDetails") \ - .get("settings").get("timezone"), - "messageOfTheday": { - "bannerMessage": self.params.get("config")[0].get("NetworkManagementDetails") \ - .get("settings").get("messageOfTheday").get("bannerMessage"), - "retainExistingBanner": self.params.get("config")[0].get("NetworkManagementDetails") \ - .get("settings").get("messageOfTheday").get("retainExistingBanner") - } - - } - } - - self.want_net = want_net - - def get_execution_details(self, execid): - response = None - response = self.dnac._exec( - family="task", - function='get_business_api_execution_details', - params={"execution_id": execid} - ) - - if self.log: - log(str(response)) - - return response - - def get_diff_merge(self): - if self.params.get("config")[0].get("GlobalPoolDetails") is not None: - - if not self.params.get("config")[0].get("GlobalPoolDetails") \ - .get("settings").get("ippool")[0].get("ipPoolName"): - - msg = "Mandatory Parameter ipPoolName required\n" - self.module.fail_json(msg=msg) - - pool_updated = False - pool_created = False - - if self.have.get("pool_exists"): - log("entered") - obj_params = [ - ("settings", "settings"), - ] - if self.requires_update(self.have.get("pool_details"), self.want, obj_params): - log("Pool requires update") - #Pool Exists - pool_params = copy.deepcopy(self.want) - pool_params.get("settings").get("ippool")[0] \ - .update({"id": self.have.get("pool_id")}) - log(str(self.want)) - log(str(pool_params)) - del pool_params["settings"]["ippool"][0]["IpAddressSpace"] - del pool_params["settings"]["ippool"][0]["ipPoolCidr"] - del pool_params["settings"]["ippool"][0]["type"] - - if pool_params.get("settings").get("ippool")[0].get("dhcpServerIps") is None: - pool_params.get("settings").get("ippool")[0].update({"dhcpServerIps" : \ - self.have.get("pool_details").get("settings") \ - .get("ippool")[0].get("dhcpServerIps")}) - if pool_params.get("settings").get("ippool")[0].get("dnsServerIps") is None: - pool_params.get("settings").get("ippool")[0].update({"dnsServerIps" : \ - self.have.get("pool_details").get("settings") \ - .get("ippool")[0].get("dnsServerIps")}) - if pool_params.get("settings").get("ippool")[0].get("gateway") is None: - pool_params.get("settings").get("ippool")[0].update({"gateway" : \ - self.have.get("pool_details").get("settings") \ - .get("ippool")[0].get("gateway")}) - - log(str(pool_params)) - log(str(self.have)) - response = self.dnac._exec( - family = "network_settings", - function = "update_global_pool", - params = pool_params, - ) - - pool_updated = True - log(str(pool_updated)) - - else: - log("Pool doesn't requires an update") - log(str(self.have)) - log(str(self.result)) - self.result['response'] = self.have.get("settings") - self.result['msg'] = "Pool doesn't requires an update" - # self.module.exit_json(**self.result) - - else: - #creating New Pool - pool_params = self.want - log(str(pool_params)) - response = self.dnac._exec( - family="network_settings", - function="create_global_pool", - params = pool_params, - ) - log("PoolCreated") - log(str(response)) - pool_created = True - - if pool_created or pool_updated: - if response and isinstance(response, dict): - executionid = response.get("executionId") - - while True: - execution_details = self.get_execution_details(executionid) - if execution_details.get("status") == "SUCCESS": - self.result['changed'] = True - self.result['response'] = execution_details - break - - elif execution_details.get("bapiError"): - - self.module.fail_json(msg=execution_details.get("bapiError"), - response=execution_details) - break - - if pool_updated: - log("Pool Updated Successfully") - self.result['msg'] = "Pool Updated Successfully" - self.result['response'].update({"Id": \ - self.have.get("pool_details").get("id")}) - - elif pool_created: - log("Pool Created Successfully") - (pool_exists, pool_details, pool_id) = self.pool_exists() - self.result['response'].update({"Id": pool_id}) - self.result['response'].update({"Pool Exists": pool_exists}) - self.result['response'].update({"Pool Details": pool_details}) - self.result['msg'] = "Pool Created Successfully" - else: - log("Pool doesn't need a update") - self.result['msg'] = "Pool doesn't requires an update" - self.result['response'].update({"Id": \ - self.have.get("pool_details").get("id")}) - - if self.params.get("config")[0].get("ReservePoolDetails") is not None: - - res_updated = False - res_created = False - log(str(self.have_reserve.get("res_details"))) - log(str(self.want_reserve)) - if self.have_reserve: - log("entered") - obj_params = [ - ("name", "name"), - ("type", "type"), - ("ipv6AddressSpace", "ipv6AddressSpace"), - ("ipv4GlobalPool", "ipv4GlobalPool"), - ("ipv4Prefix", "ipv4Prefix"), - ("ipv4PrefixLength", "ipv4PrefixLength"), - ("ipv4GateWay", "ipv4GateWay"), - ("ipv4DhcpServers", "ipv4DhcpServers"), - ("ipv4DnsServers", "ipv4DnsServers"), - ("ipv6GateWay", "ipv6GateWay"), - ("ipv6DhcpServers", "ipv6DhcpServers"), - ("ipv6DnsServers", "ipv6DnsServers"), - ("ipv4TotalHost", "ipv4TotalHost"), - ("slaacSupport", "slaacSupport") - ] - - if self.requires_update(self.have_reserve.get("res_details"), \ - self.want_reserve, obj_params): - - log("Network requires update") - #Pool Exists - log(str(self.have_reserve)) - log(str(self.want_reserve)) - - res_params = copy.deepcopy(self.want_reserve) - res_params.update({"site_id": self.site_id}) - res_params.update({"id": self.have_reserve.get("res_id")}) - response = self.dnac._exec( - family="network_settings", - function="update_reserve_ip_subpool", - params=res_params, - ) - - log("Reservation Updated") - log(str(response)) - res_updated = True - - else: - log("Reserved ip subpool doesn't requires an update") - self.result["response"] = self.have_reserve - self.result["msg"] = "Reserved ip subpool doesn't requires an update" - # self.module.exit_json(**self.result) - - else: - #creating New Pool - res_params = self.want_reserve - log(str(res_params)) - if not self.want_reserve.get("name") or \ - not self.want_reserve.get("ipv4GlobalPool") or \ - not self.want_reserve.get("ipv4PrefixLength") or not self.site_id: - - self.module.fail_json(msg="missing parameter name or \ - ipv4GlobalPool or ipv4PrefixLength or siteName", response=[]) - - res_params.update({"site_id": self.site_id}) - log(str(res_params)) - response = self.dnac._exec( - family="network_settings", - function="reserve_ip_subpool", - params=res_params, - ) - log("Reservation Created") - log(str(response)) - res_created = True - - if res_created or res_updated: - if response and isinstance(response, dict): - executionid = response.get("executionId") - - while True: - execution_details = self.get_execution_details(executionid) - if execution_details.get("status") == "SUCCESS": - self.result['changed'] = True - self.result['response'] = execution_details - break - - elif execution_details.get("bapiError"): - - self.module.fail_json(msg=execution_details.get("bapiError"), - response=execution_details) - break - - if res_updated: - log("Reserved Ip Subpool Updated Successfully") - self.result['msg'] = "Reserved Ip Subpool Updated Successfully" - self.result['response'].update({"Reservation details": \ - self.have.get("res_details")}) - - elif res_created: - log("Ip Subpool Reservation Created Successfully") - (res_exists, res_details, res_id) = self.res_exists() - self.result['response'].update({"Reservation Id": res_id}) - self.result['response'].update({"Reservation Exists": res_exists}) - self.result['response'].update({"Reservation details": res_details}) - self.result['msg'] = "Ip Subpool Reservation Created Successfully" - else: - log("Ip Subpool Reservation doesn't need a update") - self.result['msg'] = "Ip Subpool Reservation doesn't requires an update" - self.result['response'].update({"Reservation details": \ - self.have.get("res_details")}) - - if self.params.get("config")[0].get("NetworkManagementDetails") is not None: - - net_updated = False - if self.have_net: - log("entered") - obj_params = [ - ("settings", "settings"), - ("siteName", "siteName") - ] - if self.requires_update(self.have_net.get("net_details"), self.want_net, obj_params): - log("Network update requires") - #Pool Exists - log(str(self.have_net)) - log(str(self.want_net)) - - res_params = copy.deepcopy(self.want_net) - res_params.update({"site_id": self.have_net.get("site_id")}) - response = self.dnac._exec( - family="network_settings", - function='update_network', - params=res_params, - ) - - log("Network Updated") - log(str(response)) - net_updated = True - - else: - log("Network doesn't need an update") - self.result["response"] = self.have_net - self.result["msg"] = "Network doesn't need an update" - self.module.exit_json(**self.result) - - if net_updated: - if response and isinstance(response, dict): - executionid = response.get("executionId") - - while True: - execution_details = self.get_execution_details(executionid) - if execution_details.get("status") == "SUCCESS": - self.result['changed'] = True - self.result['response'] = execution_details - break - - elif execution_details.get("bapiError"): - - self.module.fail_json(msg=execution_details.get("bapiError"), - response=execution_details) - break - - if net_updated: - log("Network Updated Successfully") - self.result['msg'] = "Network Updated Successfully" - self.result['response'] = self.want_net - - else: - log("Pool doesn't need a update") - self.result['msg'] = "Pool doesn't requires an update" - self.result['response'] = self.have_net - - def get_res_id_by_name(self, name): - _id = None - try: - response = self.dnac._exec( - family="network_settings", - function="get_reserve_ip_subpool", - params={"siteId":self.site_id}, - ) - - log(str(response)) - - if isinstance(response, dict): - if "response" in response: - response = response.get("response") - log(str(response)) - - current_details = get_dict_result(response, "groupName", name) - if current_details: - _id = current_details.get("id") - - except: - result = None - - return _id - - - def get_diff_delete(self): - - if self.params.get("config")[0].get("ReservePoolDetails") is not None: - res_exists = self.have_reserve.get("res_exists") - log(str(res_exists)) - _id = None - if self.want_reserve.get("name"): - log(str(self.want_reserve.get("name"))) - _id = self.get_res_id_by_name(self.want_reserve.get("name")) - log(str(_id)) - if res_exists: - if not _id: - self.module.fail_json(msg="missing or \ - incorrect parameter reserved pool name", response=[]) - log(str(self.have_reserve.get("res_id"))) - response = self.dnac._exec( - family="network_settings", - function="release_reserve_ip_subpool", - params={"id": _id}, - ) - - if response and isinstance(response, dict): - executionid = response.get("executionId") - while True: - execution_details = self.get_execution_details(executionid) - if execution_details.get("status") == "SUCCESS": - self.result['changed'] = True - self.result['response'] = execution_details - log(str(response)) - self.result['msg'] = "Ip subpool reservation released successfully" - - elif execution_details.get("bapiError"): - self.module.fail_json(msg=execution_details.get("bapiError"), - response=execution_details) - - else: - self.module.fail_json(msg="Reserved Ip Subpool Not Found", response=[]) - - if self.params.get("config")[0].get("GlobalPoolDetails") is not None: - pool_exists = self.have.get("pool_exists") - - if pool_exists: - response = self.dnac._exec( - family="network_settings", - function="delete_global_ip_pool", - params={"id": self.have.get("pool_id")}, - ) - - if response and isinstance(response, dict): - executionid = response.get("executionId") - while True: - execution_details = self.get_execution_details(executionid) - if execution_details.get("status") == "SUCCESS": - self.result['changed'] = True - self.result['response'] = execution_details - log(str(response)) - self.result['msg'] = "Pool deleted successfully" - - elif execution_details.get("bapiError"): - self.module.fail_json(msg=execution_details.get("bapiError"), - response=execution_details) - - else: - self.module.fail_json(msg="Pool Not Found", response=[]) - - if self.params.get("config")[0].get("NetworkManagementDetails") is not None: - - self.module.fail_json(msg="No operation available for Delete Network", response=[]) - - -def main(): - """main entry point for module execution""" - - element_spec ={ - "dnac_host": {"required": True, "type": 'str'}, - "dnac_port": {"type": 'str', "default": '443'}, - "dnac_username": {"type": 'str', "default": 'admin', "aliases": ['user']}, - "dnac_password": {"type": 'str', "no_log": True}, - "dnac_verify": {"type": 'bool', "default": 'True'}, - "dnac_version": {"type": 'str', "default": '2.2.3.3'}, - "dnac_debug": {"type": 'bool', "default": False}, - "dnac_log": {"type": 'bool', "default": False}, - "validate_response_schema": {"type": 'bool', "default": True}, - "config": {"required": True, "type": 'list', "elements": 'dict'}, - "state": {"default": 'merged', "choices": ['merged', 'deleted']}, - } - - module = AnsibleModule(argument_spec=element_spec, supports_check_mode=False) - - dnac_network = DnacNetwork(module) - - state = dnac_network.get_state() - dnac_network.validate_input() - - dnac_network.get_have() - dnac_network.get_want() - - if state == "merged": - dnac_network.get_diff_merge() - - elif state == "deleted": - dnac_network.get_diff_delete() - log(str(dnac_network.result)) - - module.exit_json(**dnac_network.result) - - -if __name__ == "__main__": - main() From a94547b2c374149c5b3c6df1a87a989e655af01f Mon Sep 17 00:00:00 2001 From: Madhan Date: Thu, 31 Aug 2023 17:22:22 +0530 Subject: [PATCH 10/13] Delete network_intent.yml Deleting network_intent playbook, will be added later --- playbooks/network_intent.yml | 82 ------------------------------------ 1 file changed, 82 deletions(-) delete mode 100644 playbooks/network_intent.yml diff --git a/playbooks/network_intent.yml b/playbooks/network_intent.yml deleted file mode 100644 index e144efc628..0000000000 --- a/playbooks/network_intent.yml +++ /dev/null @@ -1,82 +0,0 @@ -- hosts: dnac_servers - vars_files: - - credentials_245.yml - gather_facts: no - connection: local - tasks: -# -# Project Info Section -# - - - name: Create, update, delete global pool and reserve an ip pool - cisco.dnac.network_intent: - dnac_host: "{{ dnac_host }}" - dnac_port: "{{ dnac_port }}" - dnac_username: "{{ dnac_username }}" - dnac_password: "{{ dnac_password }}" - dnac_verify: "{{ dnac_verify }}" - dnac_debug: "{{ dnac_debug }}" - dnac_log: True - state: merged - config: - - GlobalPoolDetails: - settings: - ippool: - - ipPoolName: Global_Pool1 - gateway: "" #use this for updating - IpAddressSpace: IPv4 #required when we are creating - ipPoolCidr: 100.0.0.0/8 #required when we are creating - type: Generic - dhcpServerIps: [] #use this for updating - dnsServerIps: [] #use this for updating - # prev_name: Global_Pool - ReservePoolDetails: - ipv6AddressSpace: false - ipv4GlobalPool: 100.0.0.0/8 - ipv4Prefix: true - ipv4PrefixLength: 8 - ipv4DnsServers: [] - name: IP_Pool_3 - siteName: Global/Chennai/Trill - slaacSupport: true - # prev_name: IP_Pool_4 - type: LAN - NetworkManagementDetails: - settings: - dhcpServer: - - 10.0.0.1 - dnsServer: - domainName: cisco.co - primaryIpAddress: 10.0.0.2 - secondaryIpAddress: 10.0.0.3 - # clientAndEndpoint_aaa: #works only if we system settigns is set - # # ipAddress: string #Mandatory for ISE, sec ip for AAA - # network: 10.0.0.9 - # protocol: RADIUS - # servers: AAA - # # sharedSecret: string #ISE - messageOfTheday: - bannerMessage: hello - retainExistingBanner: "true" - netflowcollector: - ipAddress: 10.0.0.4 - port: 443 - # network_aaa: #works only if we system settigns is set - # # ipAddress: string #Mandatory for ISE, sec ip for AAA - # network: 10.0.0.8 - # protocol: RADIUS - # servers: AAA - # # sharedSecret: string #ISE - ntpServer: - - 10.0.0.5 - snmpServer: - configureDnacIP: true - ipAddresses: - - 10.0.0.6 - syslogServer: - configureDnacIP: true - ipAddresses: - - 10.0.0.7 - timezone: GMT - siteName: Global/Chennai - From 2f7d9a0928b9225cfead422bf196ff6b9e62c461 Mon Sep 17 00:00:00 2001 From: akabhask Date: Thu, 31 Aug 2023 20:10:47 +0530 Subject: [PATCH 11/13] ansible-test error fixes --- plugins/module_utils/dnac.py | 8 +-- plugins/modules/template_intent.py | 82 +++++++++++++++--------------- 2 files changed, 46 insertions(+), 44 deletions(-) diff --git a/plugins/module_utils/dnac.py b/plugins/module_utils/dnac.py index 8c1c8081e5..46f157e879 100644 --- a/plugins/module_utils/dnac.py +++ b/plugins/module_utils/dnac.py @@ -25,6 +25,7 @@ import datetime import inspect + class DnacBase: """Class contains members which can be reused for all intent modules""" def __init__(self, module): @@ -46,7 +47,7 @@ def __init__(self, module): self.supported_states = ["merged", "deleted"] self.result = {"changed": False, "diff": [], "response": [], "warnings": []} - def log(self, message, frameIncrement = 0): + def log(self, message, frameIncrement=0): """Log messages into dnac.log file""" if self.dnac_log: @@ -56,7 +57,7 @@ def log(self, message, frameIncrement = 0): def check_return_status(self): """API to check the return status value and exit/fail the module""" - self.log(f"status: {self.status}, msg:{self.msg}", frameIncrement = 1) + self.log("status: {0}, msg:{1}".format(self.status, self.msg), frameIncrement=1) if "failed" in self.status: self.module.fail_json(msg=self.msg, response=[]) elif "exited" in self.status: @@ -99,7 +100,8 @@ def reset_values(self): self.have_create.clear() self.want_create.clear() -def log(msg, frameIncrement = 0): + +def log(msg, frameIncrement=0): with open('dnac.log', 'a') as of: callerframerecord = inspect.stack()[1 + frameIncrement] frame = callerframerecord[0] diff --git a/plugins/modules/template_intent.py b/plugins/modules/template_intent.py index 09c01bf3c2..d713eae46b 100644 --- a/plugins/modules/template_intent.py +++ b/plugins/modules/template_intent.py @@ -796,12 +796,12 @@ def get_have_project(self, config): # DNAC returns project details even if the substring matches. # Hence check the projectName retrieved from DNAC. if not (project_details and isinstance(project_details, list)): - self.log(f"Project: {given_project_name} not found, need to create new project in DNAC") + self.log("Project: {0} not found, need to create new project in DNAC".format(given_project_name)) return None fetched_project_name = project_details[0].get('name') if fetched_project_name != given_project_name: - self.log(f"Project {given_project_name} provided is not exact match in DNAC DB") + self.log("Project {0} provided is not exact match in DNAC DB".format(given_project_name)) return None template_available = project_details[0].get('templates') @@ -828,8 +828,8 @@ def get_have_template(self, config, template_available): template_name) # Check if specified template in playbook is available if not template_details: - self.log(f"Template {template_name} not found in project {project_name}") - self.msg = "Template : {template_name} missing, new template to be created" + self.log("Template {0} not found in project {1}".format(template_name, project_name)) + self.msg = "Template : {0} missing, new template to be created".format(template_name) self.status = "success" return self @@ -853,13 +853,13 @@ def get_have_template(self, config, template_available): have_create_template["isCommitPending"] = False have_create_template["template_found"] = template is not None \ and isinstance(template, dict) - self.log(f"Template {template_name} is found and template " - f"details are :{str(template)}") + self.log("Template {0} is found and template " + "details are :{1}".format(template_name, str(template))) # There are committed templates in the project but the # one specified in the playbook may not be committed - self.log(f"Commit pending for template name {template_name}" - f" is {have_create_template.get('isCommitPending')}") + self.log("Commit pending for template name {0}" + " is {1}".format(template_name, have_create_template.get('isCommitPending'))) self.have_create_template = have_create_template self.msg = "Successfully collected all template parameters from dnac for comparison" @@ -906,8 +906,8 @@ def get_want(self, config): want_create["comments"] = version_comments self.want_create = want_create - self.msg = "Successfully collected all parameters from playbook \ - for comparison" + self.msg = "Successfully collected all parameters from playbook " + \ + "for comparison" self.status = "success" return self @@ -921,12 +921,12 @@ def create_project_or_template(self, is_create_project=False): if is_create_project: params_key = project_params - name = f"project: {template_params.get('projectName')}" + name = "project: {0}".format(project_params.get('name')) validation_string = "Successfully created project" creation_value = "create_project" else: params_key = template_params - name = f"template: {template_params.get('name')}" + name = "template: {0}".format(template_params.get('name')) validation_string = "Successfully created template" creation_value = "create_template" @@ -942,28 +942,28 @@ def create_project_or_template(self, is_create_project=False): task_id = response.get("response").get("taskId") if not task_id: - self.log(f"Task id {task_id} not found") + self.log("Task id {0} not found".format(task_id)) return creation_id, created while not created: task_details = self.get_task_details(task_id) if not task_details: - self.log(f"Failed to get task details for taskid: {task_id}") + self.log("Failed to get task details for taskid: {0}".format(task_id)) return creation_id, created - self.log(f"task_details: {task_details}") + self.log("task_details: {0}".format(task_details)) if task_details.get("isError"): - self.log(f"isError set to true for taskid: {task_id}") + self.log("isError set to true for taskid: {0}".format(task_id)) return creation_id, created if validation_string not in task_details.get("progress"): - self.log(f"progress set to {task_details.get('progress')} " - f"for taskid: {task_id}") + self.log("progress set to {0} " + "for taskid: {1}".format(task_details.get('progress'), task_id)) continue creation_id = task_details.get("data") if not creation_id: - self.log(f"data is not found for taskid: {task_id}") + self.log("data is not found for taskid: {0}".format(task_id)) continue created = True @@ -973,7 +973,7 @@ def create_project_or_template(self, is_create_project=False): template_params["projectId"] = creation_id template_params["project_id"] = creation_id - self.log(f"New {name} created with id {creation_id}") + self.log("New {0} created with id {1}".format(name, creation_id)) return creation_id, created def requires_update(self): @@ -1047,8 +1047,9 @@ def validate_input_merge(self, template_exists): language = template_params.get("language").upper() if language: if language not in self.accepted_languages: - self.msg = f"Invalid value language {language} ." \ - f"Accepted language values are {self.accepted_languages}" + self.msg = "Invalid value language {0} ." \ + "Accepted language values are {1}" \ + .format(self.accepted_languages, language) self.status = "failed" return self else: @@ -1069,20 +1070,19 @@ def get_diff_merged(self, config): """Update/Create templates and projects in DNAC with fields provided in DNAC""" is_project_found = self.have_create_project.get("project_found") - is_template_found = self.have_create_template.get("template_found") - template_params = self.want_create.get("template_params") - template_id = None - template_updated = False - if not is_project_found: project_id, project_created = self.create_project_or_template(is_create_project=True) if project_created: - self.log(f"project created with projectId : {project_id}") + self.log("project created with projectId : {0}".format(project_id)) else: self.status = "failed" self.msg = "Project creation failed" return self + is_template_found = self.have_create_template.get("template_found") + template_params = self.want_create.get("template_params") + template_id = None + template_updated = False self.validate_input_merge(is_template_found).check_return_status() if is_template_found: if self.requires_update(): @@ -1124,7 +1124,7 @@ def get_diff_merged(self, config): task_details = {} task_id = response.get("response").get("taskId") if not task_id: - self.msg = f"Task id: {task_id} not found" + self.msg = "Task id: {0} not found".format(task_id) self.status = "failed" return self task_details = self.get_task_details(task_id) @@ -1146,16 +1146,15 @@ def get_diff_merged(self, config): def delete_project_or_template(self, config, is_delete_project=False): """Call DNAC API to delete project or template with provided inputs""" - template_params = self.want_create.get("template_params") - if is_delete_project: params_key = {"project_id": self.have_create_project.get("id")} deletion_value = "deletes_the_project" - name = f"project: {template_params.get('projectName')}" + name = "project: {0}".format(config.get('projectName')) else: + template_params = self.want_create.get("template_params") params_key = {"template_id": self.have_create_template.get("id")} deletion_value = "deletes_the_template" - name = f"templateName: {template_params.get('templateName')}" + name = "templateName: {0}".format(template_params.get('templateName')) response = self.dnac_apply['exec']( family="configuration_templates", @@ -1176,32 +1175,33 @@ def delete_project_or_template(self, config, is_delete_project=False): self.status = "failed" return self - self.msg = f"Successfully deleted {name} " + self.msg = "Successfully deleted {0} ".format(name) self.status = "success" return self def get_diff_deleted(self, config): """Delete projects or templates in DNAC with fields provided in playbook.""" - is_template_found = self.have_create_template.get("template_found") is_project_found = self.have_create_project.get("project_found") - template_params = self.want_create.get("template_params") - projectName = template_params.get('projectName') + projectName = config.get("projectName") if not is_project_found: - self.msg = f"Project {projectName} provide valid projectName" + self.msg = "Project {0} is not found".format(projectName) self.status = "failed" return self + is_template_found = self.have_create_template.get("template_found") + template_params = self.want_create.get("template_params") + template_name = config.get("templateName") if template_params.get("name"): if is_template_found: self.delete_project_or_template(config) else: - self.msg = "Invalid template Name under project" + self.msg = "Invalid template {0} under project".format(template_name) self.status = "failed" return self else: - self.log("Template is empty, deleting the project") + self.log("Template Name is empty, deleting the project and its associated templates") is_project_deletable = self.have_create_project.get("isDeletable") if is_project_deletable: self.delete_project_or_template(config, is_delete_project=True) @@ -1244,7 +1244,7 @@ def main(): state = dnac_template.params.get("state") if state not in dnac_template.supported_states: dnac_template.status = "invalid" - dnac_template.msg = f"State {state} is invalid" + dnac_template.msg = "State {0} is invalid".format(state) dnac_template.check_return_status() for config in dnac_template.validated_config: From 47ef92b7bfc98218192043afe3c05f99c35b41b6 Mon Sep 17 00:00:00 2001 From: Arrokoth-byte Date: Thu, 14 Sep 2023 15:40:31 -0600 Subject: [PATCH 12/13] Updated different function names --- README.md | 2 +- changelogs/changelog.yaml | 11 ++++++++++- galaxy.yml | 2 +- playbooks/user_info.yml | 18 ++++++++++++++++++ plugins/action/role_permissions_info.py | 4 ++-- plugins/action/roles_info.py | 4 ++-- plugins/action/user.py | 12 ++++++------ plugins/action/user_info.py | 4 ++-- plugins/action/users_external_servers_info.py | 4 ++-- plugins/modules/role_permissions_info.py | 2 +- plugins/modules/roles_info.py | 2 +- plugins/modules/user.py | 4 ++-- plugins/modules/user_info.py | 2 +- plugins/modules/users_external_servers_info.py | 2 +- 14 files changed, 50 insertions(+), 23 deletions(-) create mode 100644 playbooks/user_info.yml diff --git a/README.md b/README.md index c9884f8327..593ebf175f 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ The following table shows the supported versions. | 2.2.2.3 | 3.3.1 | 2.3.3 | | 2.2.3.3 | 6.4.0 | 2.4.11 | | 2.3.3.0 | 6.6.4 | 2.5.5 | -| 2.3.5.3 | 6.7.4 | 2.6.0 | +| 2.3.5.3 | 6.7.5 | 2.6.0 | If your Ansible collection is older please consider updating it first. diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml index 488a79f5fa..3d5c956abb 100644 --- a/changelogs/changelog.yaml +++ b/changelogs/changelog.yaml @@ -703,4 +703,13 @@ releases: changes: release_summary: Updated sanity test. minor_changes: - - Updated test/sanity and remove unnecessary \ No newline at end of file + - Updated test/sanity and remove unnecessary + 6.7.5: + release_date: "2023-09-14" + changes: + release_summary: Updated different function names. + bugfixes: + - Updated from get_permissions_ap_i to get_permissions_api + - Updated from get_roles_ap_i to get_roles_api + - Updated from get_users_ap_i to get_users_api + - Updated from get_external_authentication_servers_ap_i to get_external_authentication_servers_api \ No newline at end of file diff --git a/galaxy.yml b/galaxy.yml index 016a7da845..07683c4ad4 100644 --- a/galaxy.yml +++ b/galaxy.yml @@ -1,7 +1,7 @@ --- namespace: cisco name: dnac -version: 6.7.4 +version: 6.7.5 readme: README.md authors: - Rafael Campos diff --git a/playbooks/user_info.yml b/playbooks/user_info.yml new file mode 100644 index 0000000000..da08c51c9b --- /dev/null +++ b/playbooks/user_info.yml @@ -0,0 +1,18 @@ +- hosts: dnac_servers + vars_files: + - credentials.yml + gather_facts: false + connection: local + tasks: + - name: Get all User + cisco.dnac.user_info: + dnac_host: "{{dnac_host}}" + dnac_username: "{{dnac_username}}" + dnac_password: "{{dnac_password}}" + dnac_verify: "{{dnac_verify}}" + dnac_port: "{{dnac_port}}" + dnac_version: "{{dnac_version}}" + dnac_debug: "{{dnac_debug}}" + #headers: "{{my_headers | from_json}}" + invokeSource: string + register: result \ No newline at end of file diff --git a/plugins/action/role_permissions_info.py b/plugins/action/role_permissions_info.py index 39728ba461..a1b758c744 100644 --- a/plugins/action/role_permissions_info.py +++ b/plugins/action/role_permissions_info.py @@ -78,8 +78,8 @@ def run(self, tmp=None, task_vars=None): dnac = DNACSDK(params=self._task.args) response = dnac.exec( - family="userand_roles", - function='get_permissions_ap_i', + family="user_and_roles", + function='get_permissions_api', params=self.get_object(self._task.args), ) self._result.update(dict(dnac_response=response)) diff --git a/plugins/action/roles_info.py b/plugins/action/roles_info.py index 380c9c6875..4283de11b0 100644 --- a/plugins/action/roles_info.py +++ b/plugins/action/roles_info.py @@ -78,8 +78,8 @@ def run(self, tmp=None, task_vars=None): dnac = DNACSDK(params=self._task.args) response = dnac.exec( - family="userand_roles", - function='get_roles_ap_i', + family="user_and_roles", + function='get_roles_api', params=self.get_object(self._task.args), ) self._result.update(dict(dnac_response=response)) diff --git a/plugins/action/user.py b/plugins/action/user.py index b9c8d5c4e3..1896e57ffb 100644 --- a/plugins/action/user.py +++ b/plugins/action/user.py @@ -91,8 +91,8 @@ def get_object_by_name(self, name): # NOTE: Does not have a get by name method, using get all try: items = self.dnac.exec( - family="userand_roles", - function="get_users_ap_i", + family="user_and_roles", + function="get_users_api", params=self.get_all_params(name=name), ) if isinstance(items, dict): @@ -148,8 +148,8 @@ def requires_update(self, current_obj): def create(self): result = self.dnac.exec( - family="userand_roles", - function="add_user_ap_i", + family="user_and_roles", + function="add_user_api", params=self.create_params(), op_modifies=True, ) @@ -160,8 +160,8 @@ def update(self): name = self.new_object.get("name") result = None result = self.dnac.exec( - family="userand_roles", - function="update_user_ap_i", + family="user_and_roles", + function="update_user_api", params=self.update_all_params(), op_modifies=True, ) diff --git a/plugins/action/user_info.py b/plugins/action/user_info.py index eb9ccc38e8..7a5906fcce 100644 --- a/plugins/action/user_info.py +++ b/plugins/action/user_info.py @@ -80,8 +80,8 @@ def run(self, tmp=None, task_vars=None): dnac = DNACSDK(params=self._task.args) response = dnac.exec( - family="userand_roles", - function='get_users_ap_i', + family="user_and_roles", + function='get_users_api', params=self.get_object(self._task.args), ) self._result.update(dict(dnac_response=response)) diff --git a/plugins/action/users_external_servers_info.py b/plugins/action/users_external_servers_info.py index 1436338cc6..b29ce6bb24 100644 --- a/plugins/action/users_external_servers_info.py +++ b/plugins/action/users_external_servers_info.py @@ -80,8 +80,8 @@ def run(self, tmp=None, task_vars=None): dnac = DNACSDK(params=self._task.args) response = dnac.exec( - family="userand_roles", - function='get_external_authentication_servers_ap_i', + family="user_and_roles", + function='get_external_authentication_servers_api', params=self.get_object(self._task.args), ) self._result.update(dict(dnac_response=response)) diff --git a/plugins/modules/role_permissions_info.py b/plugins/modules/role_permissions_info.py index 53d7a9b3ad..3f520a6972 100644 --- a/plugins/modules/role_permissions_info.py +++ b/plugins/modules/role_permissions_info.py @@ -28,7 +28,7 @@ link: https://developer.cisco.com/docs/dna-center/#!get-permissions-api notes: - SDK Method used are - userand_roles.UserandRoles.get_permissions_ap_i, + user_and_roles.UserandRoles.get_permissions_ap_i, - Paths used are get /dna/system/api/v1/role/permissions, diff --git a/plugins/modules/roles_info.py b/plugins/modules/roles_info.py index 279f9ed107..3e719be1a5 100644 --- a/plugins/modules/roles_info.py +++ b/plugins/modules/roles_info.py @@ -28,7 +28,7 @@ link: https://developer.cisco.com/docs/dna-center/#!get-roles-api notes: - SDK Method used are - userand_roles.UserandRoles.get_roles_ap_i, + user_and_roles.UserandRoles.get_roles_ap_i, - Paths used are get /dna/system/api/v1/roles, diff --git a/plugins/modules/user.py b/plugins/modules/user.py index 5bfdc9ced7..21769bb834 100644 --- a/plugins/modules/user.py +++ b/plugins/modules/user.py @@ -51,8 +51,8 @@ link: https://developer.cisco.com/docs/dna-center/#!update-user-api notes: - SDK Method used are - userand_roles.UserandRoles.add_user_ap_i, - userand_roles.UserandRoles.update_user_ap_i, + user_and_roles.UserandRoles.add_user_ap_i, + user_and_roles.UserandRoles.update_user_ap_i, - Paths used are post /dna/system/api/v1/user, diff --git a/plugins/modules/user_info.py b/plugins/modules/user_info.py index bb25c6659c..f00e1d66e4 100644 --- a/plugins/modules/user_info.py +++ b/plugins/modules/user_info.py @@ -32,7 +32,7 @@ link: https://developer.cisco.com/docs/dna-center/#!get-users-api notes: - SDK Method used are - userand_roles.UserandRoles.get_users_ap_i, + user_and_roles.UserandRoles.get_users_api, - Paths used are get /dna/system/api/v1/user, diff --git a/plugins/modules/users_external_servers_info.py b/plugins/modules/users_external_servers_info.py index 2360060adb..536f958c8d 100644 --- a/plugins/modules/users_external_servers_info.py +++ b/plugins/modules/users_external_servers_info.py @@ -32,7 +32,7 @@ link: https://developer.cisco.com/docs/dna-center/#!get-external-authentication-servers-api notes: - SDK Method used are - userand_roles.UserandRoles.get_external_authentication_servers_ap_i, + user_and_roles.UserandRoles.get_external_authentication_servers_ap_i, - Paths used are get /dna/system/api/v1/users/external-servers, From f8d86a31225dd030633b708ccfd95c72dece394c Mon Sep 17 00:00:00 2001 From: Arrokoth-byte Date: Mon, 25 Sep 2023 14:13:00 -0600 Subject: [PATCH 13/13] Release date updated --- changelogs/changelog.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/changelogs/changelog.yaml b/changelogs/changelog.yaml index 3d5c956abb..8f16937e35 100644 --- a/changelogs/changelog.yaml +++ b/changelogs/changelog.yaml @@ -705,7 +705,7 @@ releases: minor_changes: - Updated test/sanity and remove unnecessary 6.7.5: - release_date: "2023-09-14" + release_date: "2023-09-25" changes: release_summary: Updated different function names. bugfixes: