def assign_role(self): method = 'GET' inv_path = '/rest/control/fabrics/{}/inventory'.format(self.fabric) get_role = dcnm_send(self.module, method, inv_path) missing_fabric, not_ok = self.handle_response(get_role, 'query_dcnm') if missing_fabric or not_ok: msg1 = "Fabric {} not present on DCNM".format(self.fabric) msg2 = "Unable to find inventories under fabric: {}".format( self.fabric) self.module.fail_json(msg=msg1 if missing_fabric else msg2) if not get_role.get('DATA'): return for create in self.want_create: for role in get_role['DATA']: if not role['switchDbID']: msg = "Unable to get SWITCHDBID using getLanSwitchCredentials under fabric: {}".format( self.fabric) self.module.fail_json(msg=msg) if role['ipAddress'] == create["switches"][0]['ipaddr']: method = 'PUT' assign_path = '/fm/fmrest/topology/role/{}?newRole={}'.format( role['switchDbID'], create['role']) response = dcnm_send(self.module, method, assign_path) self.result['response'].append(response) fail, self.result['changed'] = self.handle_response( response, "create") if fail: self.failure(response)
def config_save(self): success = False no_of_tries = 3 for x in range(0, no_of_tries): # Get Fabric ID method = 'GET' fid_path = '/rest/control/fabrics/{}'.format(self.fabric) get_fid = dcnm_send(self.module, method, fid_path) missing_fabric, not_ok = self.handle_response( get_fid, 'create_dcnm') if not get_fid.get('DATA'): return if not get_fid['DATA']['id']: msg = "Unable to find id for fabric: {}".format(self.fabric) self.module.fail_json(msg=msg) fabric_id = get_fid['DATA']['id'] # config-save method = 'POST' path = '/rest/control/fabrics/{}'.format(self.fabric) save_path = path + '/config-save' response = dcnm_send(self.module, method, save_path) self.result['response'].append(response) fail, self.result['changed'] = self.handle_response( response, "create") if fail: self.failure(response) if response["RETURN_CODE"] != 200: # Get Fabric Errors method = 'GET' fiderr_path = '/rest/control/fabrics/{}/errors'.format( fabric_id) get_fiderr = dcnm_send(self.module, method, fiderr_path) missing_fabric, not_ok = self.handle_response( get_fiderr, 'query_dcnm') if missing_fabric or not_ok: msg1 = "Fabric {} not present on DCNM".format(self.fabric) msg2 = "Could not get any fabric errors for fabric: {}".format( self.fabric) self.module.fail_json(msg=msg1 if missing_fabric else msg2) else: time.sleep(5) success = True break if not success and x in range(0, no_of_tries - 1): time.sleep(600)
def push_to_remote(self, is_rollback=False): method = 'DELETE' if self.diff_delete: for name in self.diff_delete: delete_path = '/appcenter/Cisco/elasticservice/elasticservice-api/fabrics/{}/service-nodes/{}'.format( self.service_fabric, name) resp = dcnm_send(self.module, method, delete_path) self.result['response'].append(resp) fail, self.result['changed'] = self.handle_response( resp, "delete") if fail: if is_rollback: self.failed_to_rollback = True return self.failure(resp) method = 'POST' if self.diff_create: for create in self.diff_create: deploy_path = '/appcenter/Cisco/elasticservice/elasticservice-api/fabrics/{}/service-nodes'.format( self.service_fabric) resp = dcnm_send(self.module, method, deploy_path, json.dumps(create)) self.result['response'].append(resp) fail, self.result['changed'] = self.handle_response( resp, "create") if fail: if is_rollback: self.failed_to_rollback = True return self.failure(resp) method = 'PUT' if self.diff_replace: for replace in self.diff_replace: replace_path = '/appcenter/Cisco/elasticservice/elasticservice-api/fabrics/{}/service-nodes/{}'.format( self.service_fabric, replace['name']) resp = dcnm_send(self.module, method, replace_path, json.dumps(replace)) self.result['response'].append(resp) fail, self.result['changed'] = self.handle_response( resp, "create") if fail: if is_rollback: self.failed_to_rollback = True return self.failure(resp)
def dcnm_template_validate_template(self, template): path = "/rest/config/templates/validate" resp = dcnm_send(self.module, "POST", path, template["content"], "text") if resp and resp["RETURN_CODE"] == 200 and resp["MESSAGE"] == "OK": # DATA may have multiple dicts with different reports. Check all reports and ignore warnings. # If there are errors, take it as validation failure # resp['DATA'] may be a list in case of templates with no parameters. But for templates # with parameters resp['DATA'] will be a dict directly with 'status' as 'Template Validation Successful' if isinstance(resp['DATA'], list): for d in resp["DATA"]: if d.get("reportItemType", ' ').lower() == "error": self.result["response"].append(resp) return 0 return resp["RETURN_CODE"] elif isinstance(resp['DATA'], dict): if resp['DATA'].get( "status", ' ').lower() != "template validation successful": self.result["response"].append(resp) return 0 return resp["RETURN_CODE"] else: self.result["response"].append(resp) return 0 else: return 0
def dcnm_policy_create_policy(self, policy, command): path = "/rest/control/policies/bulk-create" json_payload = json.dumps(policy) retries = 0 while retries < 3: resp = dcnm_send(self.module, command, path, json_payload) if (resp.get("DATA", None) != None) and (resp["DATA"].get( "failureList", None) != None): if isinstance(resp["DATA"]["failureList"], list): fl = resp["DATA"]["failureList"][0] else: fl = resp["DATA"]["failureList"] if "is not unique" in fl["message"]: retries = retries + 1 continue else: break else: break self.result["response"].append(resp) return resp
def lancred_all_switches(self): # Get Fabric Inventory Details method = 'GET' lan_path = '/fm/fmrest/lanConfig/getLanSwitchCredentials' get_lan = dcnm_send(self.module, method, lan_path) missing_fabric, not_ok = self.handle_response(get_lan, 'query_dcnm') if missing_fabric or not_ok: msg1 = "Fabric {} not present on DCNM".format(self.fabric) msg2 = "Unable to getLanSwitchCredentials under fabric: {}".format( self.fabric) self.module.fail_json(msg=msg1 if missing_fabric else msg2) if not get_lan.get('DATA'): return for create in self.want_create: for lan in get_lan['DATA']: if not lan['switchDbID']: msg = "Unable to SWITCHDBID using getLanSwitchCredentials under fabric: {}".format( self.fabric) self.module.fail_json(msg=msg) if lan['ipAddress'] == create["switches"][0]['ipaddr']: set_lan = { "switchIds": lan['switchDbID'], "userName": create['username'], "password": create['password'], "v3Protocol": "0" } self.set_lancred_switch(set_lan)
def get_diff_query(self): query = [] method = 'GET' path = '/appcenter/Cisco/elasticservice/elasticservice-api/?attached-fabric={}'.format( self.fabric) snode_objects = dcnm_send(self.module, method, path) missing_fabric, not_ok = self.handle_response(snode_objects, 'query_dcnm') if missing_fabric or not_ok: msg1 = "Fabric {} not present on DCNM".format(self.fabric) msg2 = "Unable to find Service Node under fabric: {}".format( self.fabric) self.module.fail_json(msg=msg1 if missing_fabric else msg2) return if not snode_objects['DATA']: return if self.config: for want_c in self.want_create: for snode in snode_objects['DATA']: if want_c['name'] == snode['name']: query.append(snode) continue else: for snode in snode_objects['DATA']: query.append(snode) self.query = query
def dcnm_policy_save_and_deploy(self, snos): path = "/rest/control/fabrics/" + self.fabric + "/config-deploy/" for sn in snos: path = path + sn resp = dcnm_send(self.module, "POST", path, "") self.result["response"].append(resp)
def rediscover_switch(self, serial_num): method = 'POST' redisc_path = '/rest/control/fabrics/{}/inventory/rediscover/{}'.format( self.fabric, serial_num) response = dcnm_send(self.module, method, redisc_path) self.result['response'].append(response) fail, self.result['changed'] = self.handle_response(response, "create") if fail: self.failure(response)
def dcnm_template_get_template_info_from_dcnm(self, path, name): resp = dcnm_send(self.module, "GET", path) if (resp and resp["RETURN_CODE"] == 200 and resp["MESSAGE"] == "OK" and resp["DATA"]): if resp["DATA"]["name"] == name: return resp["DATA"] else: return []
def dcnm_policy_deploy_policy(self, policy): path = "/rest/control/policies/deploy" json_payload = json.dumps(policy) resp = dcnm_send(self.module, "POST", path, json_payload) self.result["response"].append(resp) return resp
def dcnm_template_create_template(self, template): payload = {} payload["content"] = template["content"] path = "/rest/config/templates/template" json_payload = json.dumps(payload) resp = dcnm_send(self.module, "POST", path, json_payload) self.result["response"].append(resp) return resp
def set_lancred_switch(self, set_lan): method = 'POST' set_lan_path = '/fm/fmrest/lanConfig/saveSwitchCredentials' response = dcnm_send(self.module, method, set_lan_path, urlencode(set_lan)) self.result['response'].append(response) fail, self.result['changed'] = self.handle_response(response, "create") if fail: self.failure(response)
def dcnm_policy_get_policy_info_from_dcnm(self, policy_id): path = "/rest/control/policies/" + policy_id resp = dcnm_send(self.module, "GET", path) if (resp and (resp["RETURN_CODE"] == 200) and (resp["MESSAGE"] == "OK") and resp["DATA"]): return resp["DATA"] else: return []
def config_deploy(self): # config-deploy method = 'POST' path = '/rest/control/fabrics/{}'.format(self.fabric) deploy_path = path + '/config-deploy' response = dcnm_send(self.module, method, deploy_path) self.result['response'].append(response) fail, self.result['changed'] = self.handle_response(response, "create") if fail: self.failure(response)
def delete_switch(self): if self.diff_delete: method = 'DELETE' for sn in self.diff_delete: delete_path = '/rest/control/fabrics/{}/switches/{}'.format( self.fabric, sn) response = dcnm_send(self.module, method, delete_path) self.result['response'].append(response) fail, self.result['changed'] = self.handle_response( response, "delete") if fail: self.failure(response)
def dcnm_policy_get_all_policies(self, snos): path = "/rest/control/policies/switches?serialNumber=" + snos # Append ',' separated snos ro the path and get all policies. Then filter the list based on the # given template name resp = dcnm_send(self.module, "GET", path) if (resp and (resp["RETURN_CODE"] == 200) and (resp["MESSAGE"] == "OK") and resp["DATA"]): return resp["DATA"] else: return []
def dcnm_policy_delete_policy(self, policy, mark_del): if mark_del == True: path = "/rest/control/policies/" + policy["policyId"] json_payload = json.dumps(policy) command = "PUT" else: path = "/rest/control/policies/" + policy json_payload = "" command = "DELETE" resp = dcnm_send(self.module, command, path, json_payload) self.result["response"].append(resp) return resp
def import_switches(self): method = 'POST' path = '/rest/control/fabrics/{}'.format(self.fabric) create_path = path + '/inventory/discover?gfBlockingCall=true' if self.diff_create: for create in self.diff_create: import_response = dcnm_send(self.module, method, create_path, json.dumps(create)) self.result['response'].append(import_response) fail, self.result['changed'] = self.handle_response( import_response, "create") if fail: self.failure(import_response)
def get_diff_query(self): query = [] method = 'GET' path = '/rest/control/fabrics/{}/inventory'.format(self.fabric) inv_objects = dcnm_send(self.module, method, path) missing_fabric, not_ok = self.handle_response(inv_objects, 'query_dcnm') if inv_objects.get('ERROR') == 'Not Found' and inv_objects.get( 'RETURN_CODE') == 404: self.module.fail_json( msg="Fabric {} not present on DCNM".format(self.fabric)) return if missing_fabric or not_ok: msg1 = "Fabric {} not present on DCNM".format(self.fabric) msg2 = "Unable to find inventories under fabric: {}".format( self.fabric) self.module.fail_json(msg=msg1 if missing_fabric else msg2) if not inv_objects['DATA']: return if self.config: for want_c in self.want_create: for inv in inv_objects['DATA']: if want_c['role'] == 'None' and want_c["seedIP"] != 'None': if want_c["seedIP"] == inv['ipAddress']: query.append(inv) continue elif want_c['role'] != 'None' and want_c[ "seedIP"] == 'None': if want_c['role'] == inv['switchRole'].replace( " ", ""): query.append(inv) continue else: if want_c["seedIP"] == inv['ipAddress'] and \ want_c['role'] == inv['switchRole'].replace(" ", ""): query.append(inv) continue else: for inv in inv_objects['DATA']: query.append(inv) self.query = query
def get_have(self): method = 'GET' path = '/rest/control/fabrics/{}/inventory'.format(self.fabric) inv_objects = dcnm_send(self.module, method, path) missing_fabric, not_ok = self.handle_response(inv_objects, 'query_dcnm') if inv_objects.get('ERROR') == 'Not Found' and inv_objects.get( 'RETURN_CODE') == 404: self.module.fail_json( msg="Fabric {} not present on DCNM".format(self.fabric)) return if missing_fabric or not_ok: msg1 = "Fabric {} not present on DCNM".format(self.fabric) msg2 = "Unable to find inventories under fabric: {}".format( self.fabric) self.module.fail_json(msg=msg1 if missing_fabric else msg2) if not inv_objects['DATA']: return have_switch = [] for inv in inv_objects['DATA']: get_switch = {} get_switch.update({'sysName': inv['logicalName']}) get_switch.update({'serialNumber': inv['serialNumber']}) get_switch.update({'ipaddr': inv['ipAddress']}) get_switch.update({'platform': inv['nonMdsModel']}) get_switch.update({'version': inv['release']}) get_switch.update({ 'deviceIndex': inv['logicalName'] + '(' + inv['serialNumber'] + ')' }) get_switch.update({'role': inv['switchRole'].replace(" ", "")}) get_switch.update({'mode': inv['mode']}) get_switch.update({'serialNumber': inv['serialNumber']}) switchdict = {} switchlst = [] switchlst.append(get_switch) switchdict["switches"] = switchlst have_switch.append(switchdict) self.have_create = have_switch
def update_discover_params(self, inv): # with the inv parameters perform the test-reachability (discover) method = 'POST' path = '/rest/control/fabrics/{}/inventory/test-reachability'.format( self.fabric) response = dcnm_send(self.module, method, path, json.dumps(inv)) self.result['response'].append(response) fail, self.result['changed'] = self.handle_response(response, "create") if fail: self.module.fail_json(msg=response) if ('DATA' in response): return response['DATA'] else: return 0
def rediscover_all_switches(self): # Get Fabric Inventory Details method = 'GET' inv_path = '/rest/control/fabrics/{}/inventory'.format(self.fabric) get_inv = dcnm_send(self.module, method, inv_path) missing_fabric, not_ok = self.handle_response(get_inv, 'query_dcnm') if missing_fabric or not_ok: msg1 = "Fabric {} not present on DCNM".format(self.fabric) msg2 = "Unable to find inventories under fabric: {}".format( self.fabric) self.module.fail_json(msg=msg1 if missing_fabric else msg2) if not get_inv.get('DATA'): return for inv in get_inv['DATA']: self.rediscover_switch(inv['serialNumber'])
def dcnm_template_get_policy_list(self, snos, tlist): policies = {} path = "/rest/control/policies/switches?serialNumber=" + snos resp = dcnm_send(self.module, "GET", path) if (resp and (resp["RETURN_CODE"] == 200) and (resp["MESSAGE"] == "OK") and resp["DATA"]): for p in resp["DATA"]: if p["templateName"] in tlist: if None == policies.get(p["templateName"], None): policies[p["templateName"]] = {} policies[p["templateName"]][p["policyId"]] = {} policies[p["templateName"]][ p["policyId"]]["fabricName"] = p["fabricName"] policies[p["templateName"]][ p["policyId"]]["serialNumber"] = p["serialNumber"] return policies
def dcnm_template_delete_template(self, del_payload): tlist = [] policies = {} path = "/rest/config/templates/delete/bulk" changed = False json_payload = json.dumps(del_payload) resp = dcnm_send(self.module, "DELETE", path, json_payload) if "Template deletion successful" in resp["DATA"]: resp["DATA"] = resp["DATA"].replace("Invalid JSON response: ", "") changed = True elif "notDeletd" in resp["DATA"]: resp["DATA"] = resp["DATA"].replace("Invalid JSON response: ", "") resp["DATA"] = resp["DATA"].replace( '"notDeletdTemplate"', "Templates in use, not deleted") tlist = self.dcnm_template_get_tlist_from_resp(resp) # Since there are templates which are not deleted because they are being used by some policies, # get the policies that are using these templates. This will help the user to take necessary actions policies = self.dcnm_template_get_policies(tlist) # Make sure to mark changed to False if none of the templates are deleted if len(del_payload["fabTemplate"]) == len(tlist): # Since the number of templates in tlist is same as the number of templates to be deleted, it means # no template has been deleted. Hence we can mark changed to False self.result["changed"] = False else: self.result["changed"] = True if policies: self.result["template-policy-map"] = policies self.result["response"].append(resp) return changed
def get_have(self): method = 'GET' path = '/appcenter/Cisco/elasticservice/elasticservice-api/?attached-fabric={}'.format( self.fabric) snode_objects = dcnm_send(self.module, method, path) missing_fabric, not_ok = self.handle_response(snode_objects, 'query_dcnm') if missing_fabric or not_ok: msg1 = "Fabric {} not present on DCNM".format(self.fabric) msg2 = "Unable to Service Node under fabric: {}".format( self.fabric) self.module.fail_json(msg=msg1 if missing_fabric else msg2) return if not snode_objects['DATA']: return have_switch = [] for snode in snode_objects['DATA']: get_snode = {} get_snode.update({'name': snode['name']}) get_snode.update({'formFactor': snode['formFactor']}) get_snode.update({'interfaceName': snode['interfaceName']}) get_snode.update({'type': snode['type']}) get_snode.update( {'attachedFabricName': snode['attachedFabricName']}) get_snode.update({ 'attachedSwitchInterfaceName': snode['attachedSwitchInterfaceName'] }) get_snode.update({'attachedSwitchSn': snode['attachedSwitchSn']}) get_snode.update({'fabricName': snode['fabricName']}) have_switch.append(get_snode) self.have_create = have_switch
def dcnm_template_get_policies(self, tlist): policies = {} # We need to check all switches on the Server to see if the given templates are deployed # on any of the switches path = "/rest/control/switches/roles" resp = dcnm_send(self.module, "GET", path) if (resp and (resp["RETURN_CODE"] == 200) and (resp["MESSAGE"] == "OK") and resp["DATA"]): switches = resp["DATA"] snos = "" for sw in switches: # Build the string of serial numbers which will be used to fetch the policies from all the switches snos = snos + sw["serialNumber"] + "," snos.rstrip(",") policies = self.dcnm_template_get_policy_list(snos, tlist) return policies
def dcnm_policy_send_message_to_dcnm(self): resp = None delete_flag = False mark_delete_flag = False create_flag = False deploy_flag = False saved_flag = False snos = [] delete = [] for policy in self.diff_delete: # Get all serial numbers. We will require this to do save and deploy if policy["serialNumber"] not in snos: snos.append(policy["serialNumber"]) # First Mark the policy as deleted. Then deploy the same to remove the configuration # from the switch. Then we can finally delete the policies from the DCNM server resp = self.dcnm_policy_delete_policy(policy, True) if isinstance(resp, list): resp = resp[0] if (resp and (resp.get("DATA", None) != None) and (resp["RETURN_CODE"] == 200) and resp["MESSAGE"] == "OK"): delete.append(policy["policyId"]) mark_delete_flag = True # Once all policies are deleted, do a save & deploy so that the deleted policies are removed from the # switch if (snos != []) and (mark_delete_flag == True): resp = self.dcnm_policy_save_and_deploy(snos) if isinstance(resp, list): resp = resp[0] if (resp and (resp.get("DATA", None) != None) and (resp["RETURN_CODE"] == 200) and resp["MESSAGE"] == "OK"): saved_flag = True # Now use 'DELETE' command to delete the policies on the DCNM server for ditem in delete: # First check if the policy to be deleted exist. path = "/rest/control/policies/" + ditem resp = dcnm_send(self.module, "GET", path, "") if resp and isinstance(resp, list): resp = resp[0] if (resp and (resp.get("DATA", None) != None) and (resp["RETURN_CODE"] == 200) and resp["MESSAGE"] == "OK"): resp = self.dcnm_policy_delete_policy(ditem, False) if isinstance(resp, list): resp = resp[0] if (resp and (resp.get("DATA", None) != None) and (resp["RETURN_CODE"] == 200) and resp["MESSAGE"] == "OK"): if "Deleted successfully" in resp["DATA"]["message"]: delete_flag = True for policy in self.diff_create: # POP the 'create_additional_policy' object before sending create policy.pop("create_additional_policy") resp = self.dcnm_policy_create_policy(policy, "POST") if isinstance(resp, list): resp = resp[0] if (resp and (resp["RETURN_CODE"] == 200) and (resp["MESSAGE"] == "OK") and (resp.get("DATA", None) != None)): if resp["DATA"].get("successList", None) != None: if "is created successfully" in resp["DATA"][ "successList"][0].get("message"): policy_id = re.findall( r"POLICY-\d+", resp["DATA"]["successList"][0].get("message"), ) if (self.deploy == True) and (policy_id[0] not in self.deploy_payload): self.deploy_payload.append(policy_id[0]) create_flag = True for policy in self.diff_modify: # POP the 'create_additional_policy' object before sending create policy.pop("create_additional_policy") resp = self.dcnm_policy_create_policy(policy, "PUT") if isinstance(resp, list): resp = resp[0] if (resp and (resp["RETURN_CODE"] == 200) and (resp["MESSAGE"] == "OK") and (resp.get("DATA", None) != None)): if resp["DATA"].get("successList", None) != None: if "is created successfully" in resp["DATA"][ "successList"][0].get("message"): create_flag = True if self.deploy_payload: resp = self.dcnm_policy_deploy_policy(self.deploy_payload) if isinstance(resp, list): resp = resp[0] if (resp and (resp["RETURN_CODE"] == 200) and (resp["MESSAGE"] == "OK") and (resp.get("DATA", None) != None)): deploy_flag = True self.result["changed"] = (mark_delete_flag or saved_flag or delete_flag or create_flag or deploy_flag)