diff --git a/CHANGELOG.md b/CHANGELOG.md
index b58024b66..0fa765297 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -27,7 +27,7 @@ This project adheres to [Semantic Versioning](http://semver.org/).
### Added
-* Support to configure muliple interfaces for vrf_lite on a vrf
+* Support to configure multiple interfaces for vrf_lite on a vrf
* Added support for more switch roles in inventory module.
### Fixed
diff --git a/README.md b/README.md
index 18b603582..7a66c75b7 100644
--- a/README.md
+++ b/README.md
@@ -63,7 +63,7 @@ You can also include it in a `requirements.yml` file and install it with `ansibl
---
collections:
- name: cisco.dcnm
- version: 3.3.1
+ version: 3.4.0
```
## Using this collection
@@ -140,6 +140,7 @@ ansible_ssh_pass=dcnm_password
ansible_network_os=cisco.dcnm.dcnm
ansible_httpapi_validate_certs=False
ansible_httpapi_use_ssl=True
+ansible_httpapi_login_domain=local
```
* Ansible YAML Format
@@ -152,6 +153,7 @@ all:
ansible_python_interpreter: python
ansible_httpapi_validate_certs: False
ansible_httpapi_use_ssl: True
+ ansible_httpapi_login_domain: local
children:
dcnm_controllers:
hosts:
@@ -195,5 +197,3 @@ distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-
-
diff --git a/docs/cisco.dcnm.dcnm_httpapi.rst b/docs/cisco.dcnm.dcnm_httpapi.rst
index 8e7a15b44..3b1fd9ca9 100644
--- a/docs/cisco.dcnm.dcnm_httpapi.rst
+++ b/docs/cisco.dcnm.dcnm_httpapi.rst
@@ -22,6 +22,42 @@ Synopsis
+Parameters
+----------
+
+.. raw:: html
+
+
diff --git a/galaxy.yml b/galaxy.yml
index b615fa7bd..29fe357c6 100644
--- a/galaxy.yml
+++ b/galaxy.yml
@@ -1,7 +1,7 @@
---
namespace: cisco
name: dcnm
-version: 3.3.1
+version: 3.4.0
readme: README.md
authors:
- Shrishail Kariyappanavar
diff --git a/plugins/httpapi/dcnm.py b/plugins/httpapi/dcnm.py
index 7db9c6e55..5cde03360 100644
--- a/plugins/httpapi/dcnm.py
+++ b/plugins/httpapi/dcnm.py
@@ -26,6 +26,17 @@
a connection to the DCNM controller, send API requests and process the
respsonse from the controller.
version_added: "0.9.0"
+options:
+ login_domain:
+ description:
+ - The login domain name to use for user authentication
+ - Only needed for NDFC
+ type: string
+ default: local
+ env:
+ - name: ANSIBLE_HTTPAPI_LOGIN_DOMAIN
+ vars:
+ - name: ansible_httpapi_login_domain
"""
import json
@@ -85,14 +96,12 @@ def _login_old(self, username, password, method, path):
)
)
- def _login_latestv1(self, username, password, method, path):
+ def _login_latestv1(self, username, password, login_domain, method, path):
"""Nexus Dashboard NDFC Helper Function to login to NDFC version 12 or later."""
- login_domain = "DefaultAuth"
- # login_domain = 'local'
payload = {
- "username": self.connection.get_option("remote_user"),
- "password": self.connection.get_option("password"),
- "domain": login_domain,
+ "username": username,
+ "password": password,
+ "domain": login_domain
}
data = json.dumps(payload)
try:
@@ -123,14 +132,12 @@ def _login_latestv1(self, username, password, method, path):
)
)
- def _login_latestv2(self, username, password, method, path):
+ def _login_latestv2(self, username, password, login_domain, method, path):
"""Nexus Dashboard NDFC Helper Function to login to NDFC version 12 or later."""
- login_domain = "DefaultAuth"
- # login_domain = 'local'
payload = {
- "userName": self.connection.get_option("remote_user"),
- "userPasswd": self.connection.get_option("password"),
- "domain": login_domain,
+ "userName": username,
+ "userPasswd": password,
+ "domain": login_domain
}
data = json.dumps(payload)
try:
@@ -168,6 +175,7 @@ def login(self, username, password):
"""
self.login_succeeded = False
self.login_fail_msg = []
+ login_domain = "local" # default login domain of Nexus Dashboard
method = "POST"
path = {"dcnm": "/rest/logon", "ndfc": "/login"}
login12Func = [self._login_latestv2, self._login_latestv1]
@@ -176,9 +184,11 @@ def login(self, username, password):
self._login_old(username, password, method, path["dcnm"])
# If login attempt failed then try NDFC version 12
+ if self.get_option("login_domain") is not None:
+ login_domain = self.get_option("login_domain")
if not self.login_succeeded:
for func in login12Func:
- func(username, password, method, path["ndfc"])
+ func(username, password, login_domain, method, path["ndfc"])
if self.login_succeeded:
break
diff --git a/plugins/modules/dcnm_interface.py b/plugins/modules/dcnm_interface.py
index b06ef4952..0ce3108fa 100644
--- a/plugins/modules/dcnm_interface.py
+++ b/plugins/modules/dcnm_interface.py
@@ -48,13 +48,19 @@
description:
- The required state of the configuration after module completion.
type: str
- choices:
- - merged
- - replaced
- - overridden
- - deleted
- - query
+ choices: ['merged', 'replaced', 'overridden', 'deleted', 'query']
default: merged
+ deploy:
+ description:
+ - Flag indicating if the configuration must be pushed to the switch. This flag is used to decide the deploy behavior in
+ 'deleted' and 'overridden' states as mentioned below
+ - In 'overridden' state this flag will be used to deploy deleted interfaces.
+ - In 'deleted' state this flag will be used to deploy deleted interfaces when a specific 'config' block is not
+ included.
+ - The 'deploy' flags included with individual interface configuration elements under the 'config' block will take precedence
+ over this global flag.
+ type: bool
+ default: true
config:
description:
- A dictionary of interface operations
@@ -1584,6 +1590,7 @@ class DcnmIntf:
"GLOBAL_IF_DEPLOY": "/rest/globalInterface/deploy",
"INTERFACE": "/rest/interface",
"IF_MARK_DELETE": "/rest/interface/markdelete",
+ "FABRIC_ACCESS_MODE": "/rest/control/fabrics/{}/accessmode",
},
12: {
"VPC_SNO": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/interface/vpcpair_serial_number?serial_number={}",
@@ -1593,6 +1600,7 @@ class DcnmIntf:
"GLOBAL_IF_DEPLOY": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/globalInterface/deploy",
"INTERFACE": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/interface",
"IF_MARK_DELETE": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/interface/markdelete",
+ "FABRIC_ACCESS_MODE": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{}/accessmode",
},
}
@@ -1617,6 +1625,10 @@ def __init__(self, module):
self.log_verbosity = 0
self.fd = None
self.vpc_ip_sn = {}
+ self.ip_sn = {}
+ self.hn_sn = {}
+ self.monitoring = []
+
self.changed_dict = [
{
"merged": [],
@@ -1626,15 +1638,16 @@ def __init__(self, module):
"deploy": [],
"query": [],
"debugs": [],
+ "delete_deploy": [],
+ "skipped": [],
+ "deferred": [],
}
]
self.dcnm_version = dcnm_version_supported(self.module)
- self.inventory_data = get_fabric_inventory_details(
- self.module, self.fabric
- )
- self.ip_sn, self.hn_sn = get_ip_sn_dict(self.inventory_data)
+ self.inventory_data = {}
+
self.paths = self.dcnm_intf_paths[self.dcnm_version]
self.dcnm_intf_facts = {
@@ -1780,6 +1793,28 @@ def log_msg(self, msg):
self.fd.write("\n")
self.fd.flush()
+ def dcnm_intf_dump_have_all(self):
+
+ lhave_all = []
+ for have in self.have_all:
+ lhave_all.append(
+ {
+ "COMPLIANCE": have["complianceStatus"],
+ "FABRIC": have["fabricName"],
+ "IF_NAME": have["ifName"],
+ "IF_TYPE": have["ifType"],
+ "IP": have["ipAddress"],
+ "SNO": have["serialNo"],
+ "SYS NAME": have["sysName"],
+ "DELETABLE": have["deletable"],
+ "MARKED DELETE": have["markDeleted"],
+ "ALIAS": have["alias"],
+ "IS PHYSICAL": have["isPhysical"],
+ "UNDERLAY POLICIES": have["underlayPolicies"],
+ }
+ )
+ self.log_msg(f"HAVE ALL = {lhave_all}")
+
# New Interfaces
def dcnm_intf_get_if_name(self, name, if_type):
@@ -1823,12 +1858,9 @@ def dcnm_intf_get_vpc_serial_number(self, sw):
# messing up the incoming config make a copy of it.
def dcnm_intf_copy_config(self):
- if None is self.config:
- return
-
for cfg in self.config:
- if None is cfg.get("switch", None):
+ if cfg.get("switch", None) is None:
continue
for sw in cfg["switch"]:
@@ -1856,6 +1888,7 @@ def dcnm_intf_copy_config(self):
c[ck]["sno"] = self.vpc_ip_sn[sw]
else:
c[ck]["sno"] = self.ip_sn[sw]
+
ifname, port_id = self.dcnm_intf_get_if_name(
c["name"], c["type"]
)
@@ -2324,6 +2357,7 @@ def dcnm_intf_validate_delete_state_input(self, cfg):
del_spec = dict(
name=dict(required=False, type="str"),
switch=dict(required=False, type="list", elements="str"),
+ deploy=dict(required=False, type="bool", default=True),
)
self.dcnm_intf_validate_interface_input(cfg, del_spec, None)
@@ -2350,9 +2384,6 @@ def dcnm_intf_validate_overridden_state_input(self, cfg):
def dcnm_intf_validate_input(self):
"""Parse the playbook values, validate to param specs."""
- if None is self.config:
- return
-
# Inputs will vary for each type of interface and for each state. Make specific checks
# for each case.
@@ -3145,14 +3176,13 @@ def dcnm_intf_merge_intf_info(self, intf_info, if_head):
def dcnm_intf_get_want(self):
- if None is self.config:
+ if self.config == []:
return
- if not self.intf_info:
+ if self.intf_info == []:
return
# self.intf_info is a list of directories each having config related to a particular interface
-
for delem in self.intf_info:
if any("profile" in key for key in delem):
for sw in delem["switch"]:
@@ -3171,9 +3201,22 @@ def dcnm_intf_get_intf_info(self, ifName, serialNumber, ifType):
sno = serialNumber
path = self.paths["IF_WITH_SNO_IFNAME"].format(sno, ifName)
- resp = dcnm_send(self.module, "GET", path)
- if "DATA" in resp and resp["DATA"]:
+ retry_count = 0
+ while retry_count < 3:
+ retry_count += 1
+ resp = dcnm_send(self.module, "GET", path)
+
+ if resp == [] or resp["RETURN_CODE"] == 200:
+ break
+ time.sleep(1)
+
+ if (
+ resp
+ and "DATA" in resp
+ and resp["DATA"]
+ and resp["RETURN_CODE"] == 200
+ ):
return resp["DATA"][0]
else:
return []
@@ -3191,7 +3234,7 @@ def dcnm_intf_get_have_all_with_sno(self, sno):
path = self.paths["IF_DETAIL_WITH_SNO"].format(sno)
resp = dcnm_send(self.module, "GET", path)
- if "DATA" in resp and resp["DATA"]:
+ if resp and "DATA" in resp and resp["DATA"]:
self.have_all.extend(resp["DATA"])
def dcnm_intf_get_have_all(self, sw):
@@ -3223,7 +3266,7 @@ def dcnm_intf_get_have(self):
for intf in elem["interfaces"]:
# For each interface present here, get the information that is already available
# in DCNM. Based on this information, we will create the required payloads to be sent
- # to the DCNM controller based on the requested
+ # to the DCNM controller.
# Fetch the information from DCNM w.r.t to the interafce that we have in self.want
intf_payload = self.dcnm_intf_get_intf_info_from_dcnm(intf)
@@ -3552,7 +3595,7 @@ def dcnm_intf_compare_want_and_have(self, state):
intf_changed = True
# if deploy flag is set to True, add the information so that this interface will be deployed
- if str(deploy) == "True":
+ if str(deploy).lower() == "true":
# Add to diff_deploy,
# 1. if intf_changed is True
# 2. if intf_changed is Flase, then if 'complianceStatus is
@@ -3714,7 +3757,7 @@ def dcnm_intf_process_config(self, cfg):
processed = []
- if None is cfg.get("switch", None):
+ if cfg.get("switch", None) is None:
return
for sw in cfg["switch"]:
@@ -3734,15 +3777,18 @@ def dcnm_intf_process_config(self, cfg):
def dcnm_intf_get_diff_overridden(self, cfg):
+ deploy = False
self.diff_create = []
self.diff_delete = [[], [], [], [], [], [], [], []]
self.diff_delete_deploy = [[], [], [], [], [], [], [], []]
self.diff_deploy = []
self.diff_replace = []
- if (cfg is not None) and (cfg != []):
- self.dcnm_intf_process_config(cfg)
- elif [] == cfg:
+ # If no config is included, delete/default all interfaces
+ if cfg == []:
+ # Since there is no 'config' block, then the 'deploy' flag at top level will be
+ # used to determine the deploy behaviour
+ deploy = self.module.params["deploy"]
for address in self.ip_sn.keys():
# the given switch may be part of a VPC pair. In that case we
# need to get interface information using one switch which returns interfaces
@@ -3752,9 +3798,17 @@ def dcnm_intf_get_diff_overridden(self, cfg):
for d in self.have_all
):
self.dcnm_intf_get_have_all(address)
- elif self.config:
- # compute have_all for every switch
- for config in self.config:
+ else:
+ # compute have_all for every switch included in 'cfg'.
+ # 'deploy' flag will be picked from 'cfg' in case of state 'deleted' and from
+ # top level in case of state 'overridden'
+
+ if self.module.params["state"] == "overridden":
+ deploy = self.module.params["deploy"]
+ if self.module.params["state"] == "deleted":
+ # NOTE: in case of state 'deleted' 'cfg' will have a single entry only.
+ deploy = cfg[0].get("deploy")
+ for config in cfg:
self.dcnm_intf_process_config(config)
del_list = []
@@ -3772,9 +3826,26 @@ def dcnm_intf_get_diff_overridden(self, cfg):
and (str(have["isPhysical"]).lower() == "true")
):
+ if have["alias"] != "" and have["deleteReason"] is not None:
+ self.changed_dict[0]["skipped"].append(
+ {
+ "Name": name,
+ "Alias": have["alias"],
+ "Delete Reason": have["deleteReason"],
+ }
+ )
+ continue
+
if str(have["deletable"]).lower() == "false":
# Add this 'have to a deferred list. We will process this list once we have processed all the 'haves'
defer_list.append(have)
+ self.changed_dict[0]["deferred"].append(
+ {
+ "Name": name,
+ "Deletable": have["deletable"],
+ "Underlay Policies": have["underlayPolicies"],
+ }
+ )
continue
uelem = self.dcnm_intf_get_default_eth_payload(
@@ -3787,7 +3858,6 @@ def dcnm_intf_get_diff_overridden(self, cfg):
intf = self.dcnm_intf_get_intf_info(
have["ifName"], have["serialNo"], have["ifType"]
)
-
if intf == []:
# In case of LANClassic fabrics, a GET on policy details for Ethernet interfaces will return [] since
# these interfaces dont have any policies configured by default. In that case there is nothing to be done
@@ -3798,7 +3868,6 @@ def dcnm_intf_get_diff_overridden(self, cfg):
== "DCNM_INTF_MATCH"
):
continue
-
if uelem is not None:
# Before defaulting ethernet interfaces, check if they are
# member of any port-channel. If so, do not default that
@@ -3817,7 +3886,6 @@ def dcnm_intf_get_diff_overridden(self, cfg):
self.changed_dict[0]["deploy"].append(
copy.deepcopy(delem)
)
-
# Sub-interafces are returned as INTERFACE_ETHERNET in have_all. So do an
# additional check to see if it is physical. If not assume it to be sub-interface
# for now. We will have to re-visit this check if there are additional non-physical
@@ -3839,19 +3907,50 @@ def dcnm_intf_get_diff_overridden(self, cfg):
)
)
):
-
- # Certain interfaces cannot be deleted, so check before deleting.
- if str(have["deletable"]).lower() == "true":
-
+ # Certain interfaces cannot be deleted, so check before deleting. But if the interface has been marked for delete,
+ # we still go in and check if need to deploy.
+ if (
+ str(have["deletable"]).lower() == "true"
+ or str(have["markDeleted"]).lower() == "true"
+ ):
# Port-channel which are created as part of VPC peer link should not be deleted
if have["ifType"] == "INTERFACE_PORT_CHANNEL":
- if have["alias"] == '"vpc-peer-link"':
+ if (
+ have["alias"] is not None
+ and "vpc-peer-link" in have["alias"]
+ ):
+ self.changed_dict[0]["skipped"].append(
+ {
+ "Name": name,
+ "Alias": have["alias"],
+ "Underlay Policies": have[
+ "underlayPolicies"
+ ],
+ }
+ )
continue
+ else:
+ self.changed_dict[0]["debugs"].append(
+ {
+ "Name": name,
+ "Alias": have["alias"],
+ "Underlay Policies": have[
+ "underlayPolicies"
+ ],
+ }
+ )
# Interfaces sometimes take time to get deleted from DCNM. Such interfaces will have
# underlayPolicies set to "None". Such interfaces need not be deleted again
if have["underlayPolicies"] is None:
+ self.changed_dict[0]["skipped"].append(
+ {
+ "Name": name,
+ "Alias": have["alias"],
+ "Underlay Policies": have["underlayPolicies"],
+ }
+ )
continue
# For interfaces that are matching, leave them alone. We will overwrite the config anyway
@@ -3872,7 +3971,6 @@ def dcnm_intf_get_diff_overridden(self, cfg):
and (fabric == d["interfaces"][0]["fabricName"])
)
]
-
if not match_want:
delem = {}
@@ -3883,19 +3981,23 @@ def dcnm_intf_get_diff_overridden(self, cfg):
delem["serialNumber"] = sno
delem["fabricName"] = fabric
- self.diff_delete[
- self.int_index[have["ifType"]]
- ].append(delem)
-
- # For INTERFACE_VLAN the "mode" argument is not set in have_all.
- # if have["mode"] is not None or have["ifType"] == "INTERFACE_VLAN":
- self.diff_delete_deploy[
- self.int_index[have["ifType"]]
- ].append(delem)
- self.changed_dict[0]["deleted"].append(
- copy.deepcopy(delem)
- )
- del_list.append(have)
+ # have_all will include interfaces which are marked for DELETE too. Do not delete them again.
+ if str(have["markDeleted"]).lower() == "false":
+ self.diff_delete[
+ self.int_index[have["ifType"]]
+ ].append(delem)
+ self.changed_dict[0]["deleted"].append(
+ copy.deepcopy(delem)
+ )
+ del_list.append(have)
+
+ if str(deploy).lower() == "true":
+ self.diff_delete_deploy[
+ self.int_index[have["ifType"]]
+ ].append(delem)
+ self.changed_dict[0]["delete_deploy"].append(
+ copy.deepcopy(delem)
+ )
for intf in defer_list:
# Check if the 'source' for the ethernet interface is one of the interfaces that is already deleted.
@@ -3939,26 +4041,10 @@ def dcnm_intf_get_diff_deleted(self):
self.diff_deploy = []
self.diff_replace = []
- if (None is self.config) or (self.config is []):
- # If no config is specified, then it means we need to delete or
- # reset all interfaces in the fabric.
-
- # Get the IP addresses from ip_sn. For every IP, get all interfaces
- # and delete/reset all
-
- for address in self.ip_sn.keys():
- # the given switch may be part of a VPC pair. In that case we
- # need to get interface information using one switch which returns interfaces
- # from both the switches
- if not any(
- d.get("serialNo", None) == self.ip_sn[address]
- for d in self.have_all
- ):
- self.dcnm_intf_get_have_all(address)
-
+ if self.config == []:
# Now that we have all the interface information we can run override
# and delete or reset interfaces.
- self.dcnm_intf_get_diff_overridden(None)
+ self.dcnm_intf_get_diff_overridden(self.config)
elif self.config:
for cfg in self.config:
if cfg.get("name", None) is not None:
@@ -3975,6 +4061,7 @@ def dcnm_intf_get_diff_deleted(self):
switches = cfg["switch"]
for sw in switches:
+
intf = {}
delem = {}
@@ -4086,15 +4173,70 @@ def dcnm_intf_get_diff_deleted(self):
self.diff_delete[
self.int_index[if_type]
].append(delem)
- if "monitor" not in intf_payload["policy"]:
- self.diff_delete_deploy[
- self.int_index[if_type]
- ].append(delem)
self.changed_dict[0]["deleted"].append(
copy.deepcopy(delem)
)
+
+ if "monitor" not in intf_payload["policy"]:
+ if (
+ str(cfg.get("deploy", "true")).lower()
+ == "true"
+ ):
+ self.diff_delete_deploy[
+ self.int_index[if_type]
+ ].append(delem)
+ self.changed_dict[0][
+ "delete_deploy"
+ ].append(copy.deepcopy(delem))
+ else:
+ # Get Interface details which will include even interfaces that are marked for delete.
+ if sw not in have_all:
+ have_all.append(sw)
+ self.dcnm_intf_get_have_all(sw)
+
+ # Get the matching interface from have_all
+ match_have = [
+ have
+ for have in self.have_all
+ if (
+ (
+ intf["ifName"].lower()
+ == have["ifName"].lower()
+ )
+ and (
+ intf["serialNumber"]
+ == have["serialNo"]
+ )
+ )
+ ]
+
+ if match_have:
+ # Matching interface found. Check 'complianceStatus' and deploy if necessary
+ if (
+ match_have[0]["complianceStatus"]
+ == "In-Sync"
+ ) or (
+ match_have[0]["complianceStatus"]
+ == "Pending"
+ ):
+ if (
+ str(
+ cfg.get("deploy", "true")
+ ).lower()
+ == "true"
+ ):
+ delem["ifName"] = if_name
+ delem["serialNumber"] = intf[
+ "serialNumber"
+ ]
+ self.diff_delete_deploy[
+ self.int_index[if_type]
+ ].append(delem)
+ self.changed_dict[0][
+ "delete_deploy"
+ ].append(copy.deepcopy(delem))
else:
- self.dcnm_intf_get_diff_overridden(cfg)
+ self.dcnm_intf_get_diff_overridden([cfg])
def dcnm_extract_if_name(self, cfg):
@@ -4284,6 +4426,7 @@ def dcnm_intf_check_deployment_status(self, deploy_list):
)
]
if match_have:
+
if match_have[0]["complianceStatus"] == "In-Sync":
break
@@ -4328,6 +4471,7 @@ def dcnm_intf_send_message_to_dcnm(self):
changed = False
delete = False
+ delete_deploy = False
create = False
deploy = False
replace = False
@@ -4387,9 +4531,6 @@ def dcnm_intf_send_message_to_dcnm(self):
resp = None
- # In 11.4 version of DCNM, sometimes interfaces don't get deleted
- # completely, but only marked for deletion. They get removed only after a
- # deploy. So we will do a deploy on the deleted elements
path = self.paths["GLOBAL_IF_DEPLOY"]
index = -1
for delem in self.diff_delete_deploy:
@@ -4408,11 +4549,17 @@ def dcnm_intf_send_message_to_dcnm(self):
else:
deploy_failed = True
for item in resp["DATA"]:
- if "No Commands to execute" not in item["message"]:
+ if (
+ "No Commands to execute" not in item["message"]
+ and "In-Sync" not in item["message"]
+ ):
deploy_failed = True
if deploy_failed is False:
resp["RETURN_CODE"] = 200
resp["MESSAGE"] = "OK"
+ delete_deploy = True
+ else:
+ delete_deploy = True
self.result["response"].append(resp)
resp = None
@@ -4422,6 +4569,7 @@ def dcnm_intf_send_message_to_dcnm(self):
json_payload = json.dumps(payload)
resp = dcnm_send(self.module, "PUT", path, json_payload)
+
self.result["response"].append(resp)
if (resp.get("MESSAGE") != "OK") or (
@@ -4439,6 +4587,7 @@ def dcnm_intf_send_message_to_dcnm(self):
json_payload = json.dumps(payload)
resp = dcnm_send(self.module, "POST", path, json_payload)
+
self.result["response"].append(resp)
if (resp.get("MESSAGE") != "OK") or (
@@ -4498,38 +4647,109 @@ def dcnm_intf_send_message_to_dcnm(self):
if (self.module.params["state"] == "overridden") or (
self.module.params["state"] == "deleted"
):
- self.result["changed"] = delete or create or deploy
+ self.result["changed"] = (
+ delete or create or deploy or delete_deploy
+ )
else:
- if delete or create or replace or deploy:
+ if delete or create or replace or deploy or delete_deploy:
self.result["changed"] = True
else:
self.result["changed"] = False
- def dcnm_translate_switch_info(self, config, ip_sn, hn_sn):
+ def dcnm_intf_update_inventory_data(self):
- if None is config:
- return
+ """
+ Routine to update inventory data for all fabrics included in the playbook. This routine
+ also updates ip_sn, sn_hn and hn_sn objetcs from the updated inventory data.
- for cfg in config:
+ Parameters:
+ None
- index = 0
+ Returns:
+ None
+ """
- if None is cfg.get("switch", None):
- continue
- for sw_elem in cfg["switch"]:
- addr_info = dcnm_get_ip_addr_info(
- self.module, sw_elem, ip_sn, hn_sn
+ inv_data = get_fabric_inventory_details(self.module, self.fabric)
+ self.inventory_data.update(inv_data)
+
+ if self.module.params["state"] != "query":
+
+ # Get all switches which are managable. Changes must be avoided to all switches which are not part of this list
+ managable_ip = [
+ (key, self.inventory_data[key]["serialNumber"])
+ for key in self.inventory_data
+ if str(self.inventory_data[key]["managable"]).lower() == "true"
+ ]
+ managable_hosts = [
+ (
+ self.inventory_data[key]["logicalName"],
+ self.inventory_data[key]["serialNumber"],
+ )
+ for key in self.inventory_data
+ if str(self.inventory_data[key]["managable"]).lower() == "true"
+ ]
+
+ managable = dict(managable_ip + managable_hosts)
+
+ # Get all switches which are managable. Deploy must be avoided to all switches which are not part of this list
+ ronly_sw_list = []
+ for cfg in self.config:
+ # Check if there are any switches which are not managable in the config.
+ if cfg.get("switch", None) is not None:
+ for sw in cfg["switch"]:
+ if sw not in managable:
+ if sw not in ronly_sw_list:
+ ronly_sw_list.append(sw)
+
+ # Deploy must be avoided to fabrics which are in monitoring mode
+ path = self.paths["FABRIC_ACCESS_MODE"].format(self.fabric)
+ resp = dcnm_send(self.module, "GET", path)
+
+ if resp and resp["RETURN_CODE"] == 200:
+ if str(resp["DATA"]["readonly"]).lower() == "true":
+ self.monitoring.append(self.fabric)
+
+ # Check if source fabric is in monitoring mode. If so return an error, since fabrics in monitoring mode do not allow
+ # create/modify/delete and deploy operations.
+ if self.fabric in self.monitoring:
+ self.module.fail_json(
+ msg="Error: Source Fabric '{0}' is in Monitoring mode, No changes are allowed on the fabric\n".format(
+ self.fabric
+ )
)
- cfg["switch"][index] = addr_info
- index = index + 1
- # Check if the VPC serial number information is already present. If not fetch that
+ if ronly_sw_list:
+ self.module.fail_json(
+ msg="Error: Switches {0} are not managable in Fabric '{1}', No changes are allowed on these switches\n".format(
+ ronly_sw_list, self.fabric
+ )
+ )
- if self.vpc_ip_sn.get(addr_info, None) is None:
- sno = self.dcnm_intf_get_vpc_serial_number(addr_info)
- if "~" in sno:
- # This switch is part of VPC pair. Populate the VPC serial number DB
- self.vpc_ip_sn[addr_info] = sno
+ # Based on the updated inventory_data, update ip_sn, hn_sn and sn_hn objects
+ self.ip_sn, self.hn_sn = get_ip_sn_dict(self.inventory_data)
+
+ def dcnm_translate_playbook_info(self, config, ip_sn, hn_sn):
+
+ for cfg in config:
+ index = 0
+ if cfg.get("switch", None) is None:
+ continue
+ for sw_elem in cfg["switch"][:]:
+ if sw_elem in self.ip_sn or sw_elem in self.hn_sn:
+ addr_info = dcnm_get_ip_addr_info(
+ self.module, sw_elem, ip_sn, hn_sn
+ )
+ cfg["switch"][index] = addr_info
+
+ # Check if the VPC serial number information is already present. If not fetch that
+ if self.vpc_ip_sn.get(addr_info, None) is None:
+ sno = self.dcnm_intf_get_vpc_serial_number(addr_info)
+ if "~" in sno:
+ # This switch is part of VPC pair. Populate the VPC serial number DB
+ self.vpc_ip_sn[addr_info] = sno
+ else:
+ cfg["switch"].remove(sw_elem)
+ index = index + 1
def main():
@@ -4537,7 +4757,8 @@ def main():
"""main entry point for module execution"""
element_spec = dict(
fabric=dict(required=True, type="str"),
- config=dict(required=False, type="list", elements="dict"),
+ config=dict(required=False, type="list", elements="dict", default=[]),
+ deploy=dict(required=False, type="bool", default=True),
state=dict(
type="str",
default="merged",
@@ -4552,6 +4773,17 @@ def main():
dcnm_intf = DcnmIntf(module)
+ state = module.params["state"]
+ if not dcnm_intf.config:
+ if state == "merged" or state == "replaced" or state == "query":
+ module.fail_json(
+ msg="'config' element is mandatory for state '{0}', given = '{1}'".format(
+ state, dcnm_intf.config
+ )
+ )
+
+ dcnm_intf.dcnm_intf_update_inventory_data()
+
if not dcnm_intf.ip_sn:
dcnm_intf.result[
"msg"
@@ -4564,16 +4796,7 @@ def main():
)
)
- state = module.params["state"]
- if not dcnm_intf.config:
- if state == "merged" or state == "replaced" or state == "query":
- module.fail_json(
- msg="'config' element is mandatory for state '{0}', given = '{1}'".format(
- state, dcnm_intf.config
- )
- )
-
- dcnm_intf.dcnm_translate_switch_info(
+ dcnm_intf.dcnm_translate_playbook_info(
dcnm_intf.config, dcnm_intf.ip_sn, dcnm_intf.hn_sn
)
@@ -4595,10 +4818,7 @@ def main():
dcnm_intf.dcnm_intf_get_diff_replaced()
if module.params["state"] == "overridden":
- if dcnm_intf.config is None:
- dcnm_intf.dcnm_intf_get_diff_overridden([])
- else:
- dcnm_intf.dcnm_intf_get_diff_overridden(None)
+ dcnm_intf.dcnm_intf_get_diff_overridden(dcnm_intf.config)
if module.params["state"] == "deleted":
dcnm_intf.dcnm_intf_get_diff_deleted()
@@ -4620,6 +4840,7 @@ def main():
or dcnm_intf.diff_delete[dcnm_intf.int_index["INTERFACE_VLAN"]]
or dcnm_intf.diff_delete[dcnm_intf.int_index["STRAIGHT_TROUGH_FEX"]]
or dcnm_intf.diff_delete[dcnm_intf.int_index["AA_FEX"]]
+ or dcnm_intf.diff_delete_deploy
):
dcnm_intf.result["changed"] = True
else:
@@ -4630,7 +4851,6 @@ def main():
module.exit_json(**dcnm_intf.result)
dcnm_intf.dcnm_intf_send_message_to_dcnm()
-
module.exit_json(**dcnm_intf.result)
diff --git a/plugins/modules/dcnm_inventory.py b/plugins/modules/dcnm_inventory.py
index d691f9d09..22326918f 100644
--- a/plugins/modules/dcnm_inventory.py
+++ b/plugins/modules/dcnm_inventory.py
@@ -44,6 +44,18 @@
- deleted
- query
default: merged
+ save:
+ description:
+ - Save/Recalculate the configuration of the fabric after the inventory is updated
+ type: bool
+ required: false
+ default: true
+ deploy:
+ description:
+ - Deploy the pending configuration of the fabric after inventory is updated
+ type: bool
+ required: false
+ default: true
config:
description:
- List of switches being managed. Not required for state deleted
@@ -106,6 +118,16 @@
type: list
elements: dict
suboptions:
+ discovery_username:
+ description:
+ - Username for device discovery during POAP and RMA discovery
+ type: str
+ required: false
+ discovery_password:
+ description:
+ - Password for device discovery during POAP and RMA discovery
+ type: str
+ required: false
serial_number:
description:
- Serial number of switch to Bootstrap.
@@ -161,6 +183,16 @@
type: list
elements: dict
suboptions:
+ discovery_username:
+ description:
+ - Username for device discovery during POAP and RMA discovery
+ type: str
+ required: false
+ discovery_password:
+ description:
+ - Password for device discovery during POAP and RMA discovery
+ type: str
+ required: false
serial_number:
description:
- Serial number of switch to Bootstrap for RMA.
@@ -577,6 +609,11 @@ def update_poap_params(self, inv, poap):
"preprovisionSerial": poap["preprovision_serial"],
}
+ # Add discovery credentials if set in the playbook
+ if poap.get("discovery_username"):
+ poap_upd['discoveryUsername'] = poap["discovery_username"]
+ poap_upd['discoveryPassword'] = poap["discovery_password"]
+
poap_upd = self.discover_poap_params(poap_upd, poap)
if poap_upd.get("serialNumber"):
@@ -636,6 +673,11 @@ def update_rma_params(self, inv, rma):
"data": json.dumps(rma["config_data"]),
}
+ # Add discovery credentials if set in the playbook
+ if rma.get("discovery_username"):
+ rma_upd['discoveryUsername'] = rma["discovery_username"]
+ rma_upd['discoveryPassword'] = rma["discovery_password"]
+
rma_upd = self.discover_rma_params(rma_upd, rma)
if rma_upd.get("newSerialNumber"):
@@ -901,10 +943,12 @@ def get_diff_merge(self):
break
# Config-save all switches
- self.config_save()
+ if self.params["save"]:
+ self.config_save()
# Config-deploy all switches
- self.config_deploy()
+ if self.params["deploy"]:
+ self.config_deploy()
if not found:
self.switch_snos.append(serial_num)
@@ -962,6 +1006,8 @@ def validate_input(self):
)
poap_spec = dict(
+ discovery_username=dict(type="str", no_log=True, length_max=32),
+ discovery_password=dict(type="str", no_log=True, length_max=32),
serial_number=dict(type="str", default=""),
preprovision_serial=dict(type="str", default=""),
model=dict(type="str", default=""),
@@ -972,6 +1018,8 @@ def validate_input(self):
)
rma_spec = dict(
+ discovery_username=dict(type="str", no_log=True, length_max=32),
+ discovery_password=dict(type="str", no_log=True, length_max=32),
serial_number=dict(type="str", required=True),
old_serial=dict(type="str", required=True),
model=dict(type="str", required=True),
@@ -1006,6 +1054,13 @@ def validate_input(self):
)
if inv["poap"][0].get("serial_number") and inv["poap"][0].get("preprovision_serial") and not self.nd:
msg = "Serial number swap is not supported in DCNM version 11"
+ if inv["poap"][0].get("discovery_username"):
+ if inv["poap"][0].get("discovery_password") is None:
+ msg = "discovery_password must be set when discovery_username is specified"
+ if inv["poap"][0].get("discovery_password"):
+ if inv["poap"][0].get("discovery_username") is None:
+ msg = "discovery_username must be set when discovery_password is specified"
+
if "rma" in inv:
if state != "merged":
msg = "'merged' is only supported state for RMA"
@@ -1013,6 +1068,12 @@ def validate_input(self):
msg = "user_name must be 'admin' for RMA"
if inv["rma"][0].get("serial_number") is None or inv["rma"][0].get("old_serial") is None:
msg = "Please provide 'serial_number' and 'old_serial' for RMA"
+ if inv["rma"][0].get("discovery_username"):
+ if inv["rma"][0].get("discovery_password") is None:
+ msg = "discovery_password must be set when discovery_username is specified"
+ if inv["rma"][0].get("discovery_password"):
+ if inv["rma"][0].get("discovery_username") is None:
+ msg = "discovery_username must be set when discovery_password is specified"
if msg:
self.module.fail_json(msg=msg)
else:
@@ -1732,7 +1793,9 @@ def main():
state=dict(
default="merged", choices=["merged", "overridden", "deleted", "query"]
),
- query_poap=dict(type="bool", default=False)
+ query_poap=dict(type="bool", default=False),
+ save=dict(type="bool", default=True),
+ deploy=dict(type="bool", default=True),
)
module = AnsibleModule(argument_spec=element_spec, supports_check_mode=True)
@@ -1844,11 +1907,13 @@ def main():
# Step 7
# Config-save all switches
- dcnm_inv.config_save()
+ if module.params["save"]:
+ dcnm_inv.config_save()
# Step 8
# Config-deploy all switches
- dcnm_inv.config_deploy()
+ if module.params["deploy"]:
+ dcnm_inv.config_deploy()
module.exit_json(**dcnm_inv.result)
diff --git a/plugins/modules/dcnm_policy.py b/plugins/modules/dcnm_policy.py
index 121b0af2e..9bdd101a6 100644
--- a/plugins/modules/dcnm_policy.py
+++ b/plugins/modules/dcnm_policy.py
@@ -1112,9 +1112,10 @@ def dcnm_policy_send_message_to_dcnm(self):
and (resp.get("DATA", None) is not None)
):
if resp["DATA"].get("successList", None) is not None:
- if "is created successfully" in resp["DATA"][
- "successList"
- ][0].get("message"):
+ if (
+ resp["DATA"]["successList"][0].get("status").lower()
+ == "success"
+ ):
policy_id = re.findall(
r"POLICY-\d+",
resp["DATA"]["successList"][0].get("message"),
diff --git a/tests/integration/targets/dcnm_interface/tasks/dcnm.yaml b/tests/integration/targets/dcnm_interface/tasks/dcnm.yaml
index e42041ea1..e36a5bfc9 100644
--- a/tests/integration/targets/dcnm_interface/tasks/dcnm.yaml
+++ b/tests/integration/targets/dcnm_interface/tasks/dcnm.yaml
@@ -19,13 +19,113 @@
loop_control:
loop_var: test_case_to_run
-- name: Final Cleanup - delete feature_interface_vlan and hsrp policies that we created during init
+###############################################
+## FACTS ##
+###############################################
+- set_fact:
+ vpc_delete_path: {}
+
+- set_fact:
+ vpc_delete_path: "{{ vpc_delete_path | combine (item) }}"
+ with_items:
+ - {'12': '/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/vpcpair?serialNumber='}
+ - {'11': '/rest/vpcpair?serialNumber='}
+
+##############################################
+## DELETE VXLAN VPC PAIR ##
+##############################################
+- name: Final Cleanup - Delete DCNM VXLAN Fabric VPC switch pair
+ cisco.dcnm.dcnm_rest:
+ method: DELETE
+ path: "{{ [vpc_delete_path[controller_version], ansible_vxlan_fabric_sno1] | join ('') }}"
+ register: result
+ ignore_errors: yes
+ when: (ansible_vxlan_fabric is defined and ansible_vxlan_fabric_sno1 is defined and ansible_vxlan_fabric_sno2 is defined)
+
+- name: Wait for 10 secs
+ wait_for:
+ timeout: 10
+ when: (ansible_vxlan_fabric is defined and ansible_vxlan_fabric_sno1 is defined and ansible_vxlan_fabric_sno2 is defined)
+
+##############################################
+## CONFIG SAVE ##
+##############################################
+
+- name: Config Save
+ cisco.dcnm.dcnm_rest:
+ method: POST
+ path: "{{ vxlan_config_save_path[controller_version] }}"
+ register: result
+ when: (ansible_vxlan_fabric is defined and ansible_vxlan_fabric_sno1 is defined and ansible_vxlan_fabric_sno2 is defined)
+ ignore_errors: yes
+
+##############################################
+## DEPLOY VXLAN VPC PAIR ##
+##############################################
+
+- name: Final Cleanup - Deploy DCNM VXLAN Fabric VPC switch pair
+ cisco.dcnm.dcnm_rest:
+ method: POST
+ path: "{{ vpc_vxlan_deploy_path[controller_version] }}"
+ register: result
+ with_sequence: count=1
+ loop_control:
+ pause: 5
+ ignore_errors: yes
+ when: (ansible_vxlan_fabric is defined and ansible_vxlan_fabric_sno1 is defined and ansible_vxlan_fabric_sno2 is defined)
+
+##############################################
+## DELETE CXT VPC PAIR ##
+##############################################
+- name: Final Cleanup - Delete DCNM CXT Fabric VPC switch pair
+ cisco.dcnm.dcnm_rest:
+ method: DELETE
+ path: "{{ [vpc_delete_path[controller_version], ansible_cxt_fabric_sno1] | join ('') }}"
+ register: result
+ ignore_errors: yes
+ when: (ansible_cxt_fabric is defined and ansible_cxt_fabric_sno1 is defined and ansible_cxt_fabric_sno2 is defined)
+
+- name: Wait for 10 secs
+ wait_for:
+ timeout: 10
+ when: (ansible_cxt_fabric is defined and ansible_cxt_fabric_sno1 is defined and ansible_cxt_fabric_sno2 is defined)
+
+##############################################
+## CONFIG SAVE ##
+##############################################
+
+- name: Config Save
+ cisco.dcnm.dcnm_rest:
+ method: POST
+ path: "{{ cxt_config_save_path[controller_version] }}"
+ register: result
+ when: (ansible_cxt_fabric is defined and ansible_cxt_fabric_sno1 is defined and ansible_cxt_fabric_sno2 is defined)
+ ignore_errors: yes
+
+##############################################
+## DEPLOY CXT VPC PAIR ##
+##############################################
+
+- name: Final Cleanup - Deploy DCNM CXT Fabric VPC switch pair
+ cisco.dcnm.dcnm_rest:
+ method: POST
+ path: "{{ vpc_cxt_deploy_path[controller_version] }}"
+ register: result
+ with_sequence: count=1
+ loop_control:
+ pause: 5
+ ignore_errors: yes
+ when: (ansible_cxt_fabric is defined and ansible_cxt_fabric_sno1 is defined and ansible_cxt_fabric_sno2 is defined)
+
+- name: Final Cleanup - delete my_vpc my_lacp my_interface_vlan and my_hsrp policies that we created during init
cisco.dcnm.dcnm_policy:
fabric: "{{ ansible_it_fabric }}"
state: deleted # only choose form [merged, deleted, query]
config:
- name: my_interface_vlan
- name: my_hsrp
+ - name: my_lacp
+ - name: my_vpc
- switch:
- ip: "{{ ansible_switch1 }}"
- ip: "{{ ansible_switch2 }}"
@@ -36,12 +136,17 @@
- 'item["RETURN_CODE"] == 200'
loop: '{{ result.response }}'
+##############################################
+## DELETE ALL TEMPLATES ##
+##############################################
- name: Final Cleanup - delete all templates created during init
cisco.dcnm.dcnm_template:
state: deleted # only choose form [merged, deleted, query]
config:
- name: my_interface_vlan
- name: my_hsrp
+ - name: my_lacp
+ - name: my_vpc
register: result
- assert:
diff --git a/tests/integration/targets/dcnm_interface/tests/dcnm/dcnm_delete_deploy.yaml b/tests/integration/targets/dcnm_interface/tests/dcnm/dcnm_delete_deploy.yaml
new file mode 100644
index 000000000..783195442
--- /dev/null
+++ b/tests/integration/targets/dcnm_interface/tests/dcnm/dcnm_delete_deploy.yaml
@@ -0,0 +1,229 @@
+##############################################
+## SETUP ##
+##############################################
+
+- name: Remove local log file
+ local_action: command rm -f dcnm_intf.log
+
+- name: Put the fabric to default state
+ cisco.dcnm.dcnm_interface:
+ check_deploy: True
+ fabric: "{{ ansible_it_fabric }}"
+ state: overridden # only choose form [merged, replaced, deleted, overridden, query]
+ register: result
+
+- assert:
+ that:
+ - 'item["RETURN_CODE"] == 200'
+ loop: '{{ result.response }}'
+
+- block:
+
+##############################################
+## MERGE ##
+##############################################
+ - name: Create interfaces to check deploy cases during delete
+ cisco.dcnm.dcnm_interface:
+ check_deploy: True
+ fabric: "{{ ansible_it_fabric }}"
+ state: merged # only choose form [merged, replaced, deleted, overridden, query]
+ config:
+ - name: po333 # should be of the form po
+ type: pc # choose from this list [pc, vpc, sub_int, lo, eth, svi]
+ switch:
+ - "{{ ansible_switch1 }}" # provide the switch information where the config is to be deployed
+ deploy: true # choose from [true, false]
+ profile:
+ mode: trunk # choose from [trunk, access, l3, monitor]
+ register: result
+
+ - assert:
+ that:
+ - 'result.changed == true'
+ - '(result["diff"][0]["merged"] | length) == 1'
+ - '(result["diff"][0]["deleted"] | length) == 0'
+ - '(result["diff"][0]["replaced"] | length) == 0'
+ - '(result["diff"][0]["overridden"] | length) == 0'
+ - '(result["diff"][0]["deploy"] | length) == 1'
+
+ - assert:
+ that:
+ - 'item["RETURN_CODE"] == 200'
+ loop: '{{ result.response }}'
+
+##############################################
+## DELETE ##
+##############################################
+
+ - name: Delete interfaces with global deploy as false
+ cisco.dcnm.dcnm_interface:
+ check_deploy: True
+ deploy: false
+ fabric: "{{ ansible_it_fabric }}"
+ state: deleted # only choose form [merged, replaced, deleted, overridden,query]
+ register: result
+
+ - assert:
+ that:
+ - 'result.changed == true'
+ - '(result["diff"][0]["merged"] | length) == 0'
+ - '(result["diff"][0]["deleted"] | length) == 1'
+ - '(result["diff"][0]["delete_deploy"] | length) == 0'
+ - '(result["diff"][0]["replaced"] | length) == 0'
+ - '(result["diff"][0]["overridden"] | length) == 0'
+ - '(result["diff"][0]["deploy"] | length) == 0'
+
+ - assert:
+ that:
+ - 'item["RETURN_CODE"] == 200'
+ loop: '{{ result.response }}'
+
+##############################################
+## DELETE ##
+##############################################
+
+ - name: Delete interfaces again, global deploy as true
+ cisco.dcnm.dcnm_interface:
+ check_deploy: True
+ deploy: true
+ fabric: "{{ ansible_it_fabric }}"
+ state: deleted # only choose form [merged, replaced, deleted, overridden,query]
+ register: result
+
+ - assert:
+ that:
+ - 'result.changed == true'
+ - '(result["diff"][0]["merged"] | length) == 0'
+ - '(result["diff"][0]["deleted"] | length) == 0'
+ - '(result["diff"][0]["delete_deploy"] | length) == 1'
+ - '(result["diff"][0]["replaced"] | length) == 0'
+ - '(result["diff"][0]["overridden"] | length) == 0'
+ - '(result["diff"][0]["deploy"] | length) == 0'
+
+ - assert:
+ that:
+ - 'item["RETURN_CODE"] == 200'
+ loop: '{{ result.response }}'
+
+##############################################
+## DELETE ##
+##############################################
+
+ - name: Delete interfaces - Idempotence
+ cisco.dcnm.dcnm_interface:
+ check_deploy: True
+ deploy: true
+ fabric: "{{ ansible_it_fabric }}"
+ state: deleted # only choose form [merged, replaced, deleted, overridden,query]
+ register: result
+
+ - assert:
+ that:
+ - 'result.changed == false'
+ - '(result["diff"][0]["merged"] | length) == 0'
+ - '(result["diff"][0]["deleted"] | length) == 0'
+ - '(result["diff"][0]["delete_deploy"] | length) == 0'
+ - '(result["diff"][0]["replaced"] | length) == 0'
+ - '(result["diff"][0]["overridden"] | length) == 0'
+ - '(result["diff"][0]["deploy"] | length) == 0'
+
+ - assert:
+ that:
+ - 'item["RETURN_CODE"] == 200'
+ loop: '{{ result.response }}'
+
+##############################################
+## MERGE ##
+##############################################
+ - name: Create interfaces to check deploy cases during delete inlcuding config block
+ cisco.dcnm.dcnm_interface:
+ check_deploy: True
+ fabric: "{{ ansible_it_fabric }}"
+ state: merged # only choose form [merged, replaced, deleted, overridden, query]
+ config:
+ - name: po334 # should be of the form po
+ type: pc # choose from this list [pc, vpc, sub_int, lo, eth, svi]
+ switch:
+ - "{{ ansible_switch1 }}" # provide the switch information where the config is to be deployed
+ deploy: true # choose from [true, false]
+ profile:
+ mode: trunk # choose from [trunk, access, l3, monitor]
+ register: result
+
+ - assert:
+ that:
+ - 'result.changed == true'
+ - '(result["diff"][0]["merged"] | length) == 1'
+ - '(result["diff"][0]["deleted"] | length) == 0'
+ - '(result["diff"][0]["replaced"] | length) == 0'
+ - '(result["diff"][0]["overridden"] | length) == 0'
+ - '(result["diff"][0]["deploy"] | length) == 1'
+
+ - assert:
+ that:
+ - 'item["RETURN_CODE"] == 200'
+ loop: '{{ result.response }}'
+
+##############################################
+## DELETE ##
+##############################################
+
+ - name: Delete interfaces - global deploy as true and deploy in config block as false
+ cisco.dcnm.dcnm_interface:
+ check_deploy: True
+ deploy: true
+ fabric: "{{ ansible_it_fabric }}"
+ state: deleted # only choose form [merged, replaced, deleted, overridden,query]
+ config:
+ - name: po334 # should be of the form po
+ switch:
+ - "{{ ansible_switch1 }}" # provide the switch information where the config is to be deployed
+ deploy: false # choose from [true, false]
+ register: result
+
+ - assert:
+ that:
+ - 'result.changed == true'
+ - '(result["diff"][0]["merged"] | length) == 0'
+ - '(result["diff"][0]["deleted"] | length) == 1'
+ - '(result["diff"][0]["delete_deploy"] | length) == 0'
+ - '(result["diff"][0]["replaced"] | length) == 0'
+ - '(result["diff"][0]["overridden"] | length) == 0'
+ - '(result["diff"][0]["deploy"] | length) == 0'
+
+ - assert:
+ that:
+ - 'item["RETURN_CODE"] == 200'
+ loop: '{{ result.response }}'
+
+##############################################
+## DELETE ##
+##############################################
+
+ - name: Delete interfaces - global deploy as false and deploy in config block as true
+ cisco.dcnm.dcnm_interface:
+ check_deploy: True
+ deploy: false
+ fabric: "{{ ansible_it_fabric }}"
+ state: deleted # only choose form [merged, replaced, deleted, overridden,query]
+ config:
+ - name: po334 # should be of the form po
+ switch:
+ - "{{ ansible_switch1 }}" # provide the switch information where the config is to be deployed
+ deploy: true # choose from [true, false]
+ register: result
+
+ - assert:
+ that:
+ - 'result.changed == true'
+ - '(result["diff"][0]["merged"] | length) == 0'
+ - '(result["diff"][0]["deleted"] | length) == 0'
+ - '(result["diff"][0]["delete_deploy"] | length) == 1'
+ - '(result["diff"][0]["replaced"] | length) == 0'
+ - '(result["diff"][0]["overridden"] | length) == 0'
+ - '(result["diff"][0]["deploy"] | length) == 0'
+
+ - assert:
+ that:
+ - 'item["RETURN_CODE"] == 200'
+ loop: '{{ result.response }}'
diff --git a/tests/integration/targets/dcnm_interface/tests/dcnm/dcnm_delete_diff_options.yaml b/tests/integration/targets/dcnm_interface/tests/dcnm/dcnm_delete_diff_options.yaml
index 86d26a8d6..ddd1ce1e1 100644
--- a/tests/integration/targets/dcnm_interface/tests/dcnm/dcnm_delete_diff_options.yaml
+++ b/tests/integration/targets/dcnm_interface/tests/dcnm/dcnm_delete_diff_options.yaml
@@ -158,7 +158,7 @@
mode: lo # choose from [lo]
ipv4_addr: 193.168.2.1 # ipv4 address for the loopback interface
- - name: vpc100 # should be of the form vpc
+ - name: vpc101 # should be of the form vpc
type: vpc # choose from this list [pc, vpc, sub_int, lo, eth, svi]
switch: # provide switches of vPC pair
- "{{ ansible_switch1 }}"
@@ -265,7 +265,7 @@
mode: lo # choose from [lo]
ipv4_addr: 193.168.2.1 # ipv4 address for the loopback interface
- - name: vpc100 # should be of the form vpc
+ - name: vpc102 # should be of the form vpc
type: vpc # choose from this list [pc, vpc, sub_int, lo, eth, svi]
switch: # provide switches of vPC pair
- "{{ ansible_switch1 }}"
@@ -323,7 +323,7 @@
- name: lo100 # should be of the form lo
switch:
- "{{ ansible_switch1 }}" # provide the switch where to deploy the config
- - name: vpc100 # should be of the form vpc
+ - name: vpc102 # should be of the form vpc
switch:
- "{{ ansible_switch1 }}"
- "{{ ansible_switch2 }}" # provide the switch where to deploy the config
diff --git a/tests/integration/targets/dcnm_interface/tests/dcnm/dcnm_intf_misc.yaml b/tests/integration/targets/dcnm_interface/tests/dcnm/dcnm_intf_misc.yaml
new file mode 100644
index 000000000..f9674527b
--- /dev/null
+++ b/tests/integration/targets/dcnm_interface/tests/dcnm/dcnm_intf_misc.yaml
@@ -0,0 +1,196 @@
+##############################################
+## SETUP ##
+##############################################
+
+- name: Remove local log file
+ local_action: command rm -f dcnm_intf.log
+
+- name: Put the fabric to default state
+ cisco.dcnm.dcnm_interface:
+ check_deploy: True
+ fabric: "{{ ansible_it_fabric }}"
+ state: overridden # only choose form [merged, replaced, deleted, overridden, query]
+ register: result
+
+- assert:
+ that:
+ - 'item["RETURN_CODE"] == 200'
+ loop: '{{ result.response }}'
+
+- block:
+
+##############################################
+## MERGE ##
+##############################################
+
+ - name: Create interfaces to check delete with deploy and no deploy
+ cisco.dcnm.dcnm_interface:
+ check_deploy: True
+ fabric: "{{ ansible_it_fabric }}"
+ state: merged # only choose form [merged, replaced, deleted, overridden, query]
+ config:
+ - name: po300 # should be of the form po
+ type: pc # choose from this list [pc, vpc, sub_int, lo, eth, svi]
+ switch:
+ - "{{ ansible_switch1 }}" # provide the switch information where the config is to be deployed
+ deploy: true # choose from [true, false]
+ profile:
+ mode: trunk # choose from [trunk, access, l3, monitor]
+ register: result
+
+ - assert:
+ that:
+ - 'result.changed == true'
+ - '(result["diff"][0]["merged"] | length) == 1'
+ - '(result["diff"][0]["deleted"] | length) == 0'
+ - '(result["diff"][0]["replaced"] | length) == 0'
+ - '(result["diff"][0]["overridden"] | length) == 0'
+ - '(result["diff"][0]["deploy"] | length) == 1'
+ - '(result["diff"][0]["delete_deploy"] | length) == 0'
+
+ - assert:
+ that:
+ - 'item["RETURN_CODE"] == 200'
+ loop: '{{ result.response }}'
+
+##############################################
+## DELETE ##
+##############################################
+
+ - name: Delete interface with deploy set to False
+ cisco.dcnm.dcnm_interface:
+ fabric: "{{ ansible_it_fabric }}"
+ state: deleted # only choose form [merged, replaced, deleted, overridden, query]
+ config:
+ - name: po300 # should be of the form po
+ deploy: false
+ switch:
+ - "{{ ansible_switch1 }}" # provide the switch information where the config is to be deployed
+ register: result
+
+ - assert:
+ that:
+ - 'result.changed == true'
+ - '(result["diff"][0]["merged"] | length) == 0'
+ - '(result["diff"][0]["deleted"] | length) == 1'
+ - '(result["diff"][0]["replaced"] | length) == 0'
+ - '(result["diff"][0]["overridden"] | length) == 0'
+ - '(result["diff"][0]["deploy"] | length) == 0'
+ - '(result["diff"][0]["delete_deploy"] | length) == 0'
+
+ - assert:
+ that:
+ - 'item["RETURN_CODE"] == 200'
+ loop: '{{ result.response }}'
+
+##############################################
+## DELETE ##
+##############################################
+
+ - name: Delete interface (already marked deleted) with deploy set to True
+ cisco.dcnm.dcnm_interface:
+ fabric: "{{ ansible_it_fabric }}"
+ check_deploy: True
+ state: deleted # only choose form [merged, replaced, deleted, overridden, query]
+ config:
+ - name: po300 # should be of the form po
+ switch:
+ - "{{ ansible_switch1 }}" # provide the switch information where the config is to be deployed
+ register: result
+
+ - assert:
+ that:
+ - 'result.changed == true'
+ - '(result["diff"][0]["merged"] | length) == 0'
+ - '(result["diff"][0]["deleted"] | length) == 0'
+ - '(result["diff"][0]["replaced"] | length) == 0'
+ - '(result["diff"][0]["overridden"] | length) == 0'
+ - '(result["diff"][0]["deploy"] | length) == 0'
+ - '(result["diff"][0]["delete_deploy"] | length) == 1'
+
+ - assert:
+ that:
+ - 'item["RETURN_CODE"] == 200'
+ loop: '{{ result.response }}'
+
+##############################################
+## DELETE ##
+##############################################
+
+ - name: Delete interface again (already deployed) with deploy set to True
+ cisco.dcnm.dcnm_interface:
+ fabric: "{{ ansible_it_fabric }}"
+ check_deploy: True
+ state: deleted # only choose form [merged, replaced, deleted, overridden, query]
+ config:
+ - name: po300 # should be of the form po
+ switch:
+ - "{{ ansible_switch1 }}" # provide the switch information where the config is to be deployed
+ register: result
+
+ - assert:
+ that:
+ - 'result.changed == false'
+ - '(result["diff"][0]["merged"] | length) == 0'
+ - '(result["diff"][0]["deleted"] | length) == 0'
+ - '(result["diff"][0]["replaced"] | length) == 0'
+ - '(result["diff"][0]["overridden"] | length) == 0'
+ - '(result["diff"][0]["deploy"] | length) == 0'
+ - '(result["diff"][0]["delete_deploy"] | length) == 0'
+
+ - assert:
+ that:
+ - 'item["RETURN_CODE"] == 200'
+ loop: '{{ result.response }}'
+
+##############################################
+## MERGE ##
+##############################################
+
+ - name: Create interfaces with src fabric in monitoring mode
+ cisco.dcnm.dcnm_interface:
+ check_deploy: True
+ fabric: "{{ ansible_ext_fabric }}"
+ state: merged # only choose form [merged, replaced, deleted, overridden, query]
+ config:
+ - name: po300 # should be of the form po
+ type: pc # choose from this list [pc, vpc, sub_int, lo, eth, svi]
+ switch:
+ - "{{ ansible_switch1 }}" # provide the switch information where the config is to be deployed
+ deploy: true # choose from [true, false]
+ profile:
+ mode: trunk # choose from [trunk, access, l3, monitor]
+ register: result
+ ignore_errors: yes
+
+ - assert:
+ that:
+ - '("Monitoring mode" in result["msg"])'
+ - '("No changes are allowed on the fabric" in result["msg"])'
+ - '("{{ ansible_ext_fabric }}" in result["msg"])'
+
+##############################################
+## MERGE ##
+##############################################
+
+ - name: Create interface on a switch that is not 'managable'.
+ cisco.dcnm.dcnm_interface:
+ check_deploy: True
+ fabric: "mmudigon-unnumbered"
+ state: merged # only choose form [merged, replaced, deleted, overridden, query]
+ config:
+ - name: po300 # should be of the form po
+ type: pc # choose from this list [pc, vpc, sub_int, lo, eth, svi]
+ switch:
+ - "n9kv-test-sw2" # provide the switch information where the config is to be deployed
+ deploy: true # choose from [true, false]
+ profile:
+ mode: trunk # choose from [trunk, access, l3, monitor]
+ register: result
+ ignore_errors: yes
+
+ - assert:
+ that:
+ - '("are not managable in Fabric" in result["msg"])'
+ - '("No changes are allowed on these switches" in result["msg"])'
+ - '("n9kv-test-sw2" in result["msg"])'
diff --git a/tests/integration/targets/prepare_dcnm_intf/tasks/main.yaml b/tests/integration/targets/prepare_dcnm_intf/tasks/main.yaml
index ee4e24460..2a122e3c2 100644
--- a/tests/integration/targets/prepare_dcnm_intf/tasks/main.yaml
+++ b/tests/integration/targets/prepare_dcnm_intf/tasks/main.yaml
@@ -1,46 +1,311 @@
- # SVI interfaces require interface-vlan and hsrp features to be enabled
-
- - name: Create templates for interface-vlan and hsrp features
- cisco.dcnm.dcnm_template:
- state: merged # only choose form [merged, deleted, query]
- config:
- - name: my_interface_vlan
- tags: "interface_vlan"
- description: "internal template for enabling interface-vlan feature"
- content: |
- ##
- ##template content
-
- feature interface-vlan
-
- ##
- - name: my_hsrp
- tags: "hsrp"
- description: "internal template for enabling hsrp feature"
- content: |
- ##
- ##template content
-
- feature hsrp
-
- ##
- register: result
-
-# Create the policy to deploy interface-vlan and hsrp features on the switches
- - name: Create interface-vlan and hsrp policies
- cisco.dcnm.dcnm_policy:
- fabric: "{{ ansible_it_fabric }}"
- config:
- - name: my_interface_vlan # This must be a valid template name
- create_additional_policy: false # Do not create a policy if it already exists
- priority: 101
- - name: my_hsrp # This must be a valid template name
- create_additional_policy: false # Do not create a policy if it already exists
- priority: 101
-
- - switch:
- - ip: "{{ ansible_switch1 }}"
- - ip: "{{ ansible_switch2 }}"
- deploy: true
- state: merged
- register: result
\ No newline at end of file
+# SVI interfaces require interface-vlan and hsrp features to be enabled
+- name: Create templates for vpc, lacp, interface-vlan and hsrp features
+ cisco.dcnm.dcnm_template:
+ state: merged # only choose form [merged, deleted, query]
+ config:
+ - name: my_vpc
+ tags: "vpc"
+ description: "internal template for enabling VPC feature"
+ content: |
+ ##
+ ##template content
+
+ feature vpc
+
+ ##
+ - name: my_lacp
+ tags: "lacp"
+ description: "internal template for enabling LACP feature"
+ content: |
+ ##
+ ##template content
+
+ feature lacp
+
+ ##
+ - name: my_interface_vlan
+ tags: "interface_vlan"
+ description: "internal template for enabling interface-vlan feature"
+ content: |
+ ##
+ ##template content
+
+ feature interface-vlan
+
+ ##
+ - name: my_hsrp
+ tags: "hsrp"
+ description: "internal template for enabling hsrp feature"
+ content: |
+ ##
+ ##template content
+
+ feature hsrp
+
+ ##
+ register: result
+
+# Create the policy to deploy lacp, interface-vlan and hsrp features on the switches
+- name: Create vpc, lacp, interface-vlan and hsrp policies
+ cisco.dcnm.dcnm_policy:
+ fabric: "{{ ansible_it_fabric }}"
+ config:
+ - name: my_interface_vlan # This must be a valid template name
+ create_additional_policy: false # Do not create a policy if it already exists
+ priority: 101
+ - name: my_hsrp # This must be a valid template name
+ create_additional_policy: false # Do not create a policy if it already exists
+ priority: 101
+ - name: my_lacp # This must be a valid template name
+ create_additional_policy: false # Do not create a policy if it already exists
+ priority: 101
+ - name: my_vpc # This must be a valid template name
+ create_additional_policy: false # Do not create a policy if it already exists
+ priority: 101
+
+ - switch:
+ - ip: "{{ ansible_switch1 }}"
+ - ip: "{{ ansible_switch2 }}"
+ deploy: true
+ state: merged
+ register: result
+
+# Determine the version of Controller
+- name: Determine version of DCNM or NDFC
+ cisco.dcnm.dcnm_rest:
+ method: GET
+ path: /appcenter/cisco/ndfc/api/about/version
+ register: result
+ ignore_errors: yes
+
+- set_fact:
+ controller_version: "{{ result.response['DATA']['version'][0:2] | int }}"
+ when: ( result.response['DATA']['version'] is search("\d\d.\d+") )
+ ignore_errors: yes
+
+- name: Determine version of DCNM or NDFC
+ cisco.dcnm.dcnm_rest:
+ method: GET
+ path: /fm/fmrest/about/version
+ register: result
+ ignore_errors: yes
+
+- set_fact:
+ controller_version: "{{ result.response['DATA']['version'][0:2] | int }}"
+ when: ( result.response['DATA']['version'] is search("\d\d.\d+") )
+ ignore_errors: yes
+
+- name: Determine version of DCNM or NDFC
+ cisco.dcnm.dcnm_rest:
+ method: GET
+ path: /fm/fmrest/about/version
+ register: result
+ ignore_errors: yes
+
+- set_fact:
+ controller_version: '11'
+ when: ( result.response['DATA']['version'] == 'DEVEL' )
+ ignore_errors: yes
+
+###############################################
+## FACTS ##
+###############################################
+- set_fact:
+ vpc_create_path: {}
+ vpc_vxlan_deploy_path: {}
+ cxt_create_path: {}
+ vpc_cxt_deploy_path: {}
+ vxlan_config_save_path: {}
+ cxt_config_save_path: {}
+
+- set_fact:
+ vxlan_config_save_path: "{{ vxlan_config_save_path | combine (item) }}"
+ with_items:
+ - {'12': '/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{{ ansible_vxlan_fabric }}/config-save'}
+ - {'11': '/rest/control/fabrics/{{ ansible_vxlan_fabric }}/config-save'}
+ when: (ansible_vxlan_fabric is defined)
+
+- set_fact:
+ cxt_config_save_path: "{{ cxt_config_save_path | combine (item) }}"
+ with_items:
+ - {'12': '/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{{ ansible_cxt_fabric }}/config-save'}
+ - {'11': '/rest/control/fabrics/{{ ansible_cxt_fabric }}/config-save'}
+ when: (ansible_cxt_fabric is defined)
+
+- set_fact:
+ vpc_create_path: "{{ vpc_create_path | combine (item) }}"
+ with_items:
+ - {'12': '/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/vpcpair'}
+ - {'11': '/rest/vpcpair'}
+
+- set_fact:
+ vpc_vxlan_deploy_path: "{{ vpc_vxlan_deploy_path | combine (item) }}"
+ with_items:
+ - {'12': '/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{{ ansible_vxlan_fabric }}/config-deploy/{{ ansible_vxlan_fabric_sno1 }},{{ ansible_vxlan_fabric_sno2 }}'}
+ - {'11': '/rest/control/fabrics/{{ ansible_vxlan_fabric }}/config-deploy/{{ ansible_vxlan_fabric_sno1 }},{{ ansible_vxlan_fabric_sno2 }}'}
+ when: (ansible_vxlan_fabric is defined)
+
+- set_fact:
+ vpc_cxt_deploy_path: "{{ vpc_cxt_deploy_path | combine (item) }}"
+ with_items:
+ - {'12': '/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{{ ansible_cxt_fabric }}/config-deploy/{{ ansible_cxt_fabric_sno1 }},{{ ansible_cxt_fabric_sno2 }}'}
+ - {'11': '/rest/control/fabrics/{{ ansible_cxt_fabric }}/config-deploy/{{ ansible_cxt_fabric_sno1 }},{{ ansible_cxt_fabric_sno2 }}'}
+ when: (ansible_cxt_fabric is defined)
+
+- set_fact:
+ vxlan_vpc_create: False
+ vxlan_vpc_deploy: False
+ cxt_vpc_create: False
+ cxt_vpc_deploy: False
+
+- set_fact:
+ vpc_vxlan_data: {
+ "peerOneId": "{{ ansible_vxlan_fabric_sno1 }}",
+ "peerTwoId": "{{ ansible_vxlan_fabric_sno2 }}",
+ "useVirtualPeerlink": false
+ }
+ vxlan_vpc_create: True
+ vxlan_vpc_deploy: True
+ when: (ansible_vxlan_fabric is defined and ansible_vxlan_fabric_sno1 is defined and ansible_vxlan_fabric_sno2 is defined)
+
+- set_fact:
+ vpc_cxt_data: {
+ "peerOneId": "{{ ansible_cxt_fabric_sno1 }}",
+ "peerTwoId": "{{ ansible_cxt_fabric_sno2 }}",
+ "useVirtualPeerlink": false,
+ "nvPairs": {
+ "DOMAIN_ID": "{{ ansible_cxt_vpc_domain_id }}",
+ "PEER1_KEEP_ALIVE_LOCAL_IP": "{{ ansible_cxt_fabric_sw1 }}",
+ "PEER2_KEEP_ALIVE_LOCAL_IP": "{{ ansible_cxt_fabric_sw2 }}",
+ "KEEP_ALIVE_VRF": "management",
+ "isVpcPlus": "false",
+ "fabricPath_switch_id": "",
+ "isVTEPS": "false",
+ "NVE_INTERFACE": "",
+ "PEER1_SOURCE_LOOPBACK": "",
+ "PEER2_SOURCE_LOOPBACK": "",
+ "PEER1_PRIMARY_IP": "",
+ "PEER2_PRIMARY_IP": "",
+ "LOOPBACK_SECONDARY_IP": "",
+ "PEER1_DOMAIN_CONF": "",
+ "PEER2_DOMAIN_CONF": "",
+ "clear_policy": "false",
+ "FABRIC_NAME": "",
+ "PEER1_PCID": "{{ ansible_cxt_vpc_peer1_pcid }}",
+ "PEER2_PCID": "{{ ansible_cxt_vpc_peer2_pcid }}",
+ "PEER1_MEMBER_INTERFACES": "{{ ansible_cxt_vpc_peer1_member }}",
+ "PEER2_MEMBER_INTERFACES": "{{ ansible_cxt_vpc_peer2_member }}",
+ "PC_MODE": "active",
+ "PEER1_PO_DESC": "",
+ "PEER2_PO_DESC": "",
+ "ADMIN_STATE": "true",
+ "ALLOWED_VLANS": "all",
+ "PEER1_PO_CONF": "",
+ "PEER2_PO_CONF": ""
+ }
+ }
+ cxt_vpc_create: True
+ cxt_vpc_deploy: True
+ when: (ansible_cxt_fabric is defined and ansible_cxt_fabric_sno1 is defined and ansible_cxt_fabric_sno2 is defined)
+
+##############################################
+## CREATE VXLAN VPC PAIR ##
+##############################################
+
+- name: Create DCNM VPC switch pair
+ cisco.dcnm.dcnm_rest:
+ method: POST
+ path: "{{ vpc_create_path[controller_version] }}"
+ json_data:
+ "{{ vpc_vxlan_data | to_json}}"
+ register: result
+ when: (vxlan_vpc_create == True)
+ ignore_errors: yes
+
+- name: Wait for 10 secs
+ wait_for:
+ timeout: 10
+ when: (vxlan_vpc_create == True)
+
+##############################################
+## CONFIG SAVE ##
+##############################################
+
+- name: Config Save
+ cisco.dcnm.dcnm_rest:
+ method: POST
+ path: "{{ vxlan_config_save_path[controller_version] }}"
+ register: result
+ when: (vxlan_vpc_create == True)
+ ignore_errors: yes
+
+##############################################
+## DEPLOY VXLAN VPC PAIR ##
+##############################################
+
+- name: Deploy VPC switch pair
+ cisco.dcnm.dcnm_rest:
+ method: POST
+ path: "{{ vpc_vxlan_deploy_path[controller_version] }}"
+ register: result
+ with_sequence: count=1
+ loop_control:
+ pause: 5
+ when: (vxlan_vpc_deploy == True)
+ ignore_errors: yes
+
+- name: Wait for 30 secs
+ wait_for:
+ timeout: 30
+ when: (vxlan_vpc_deploy == True)
+
+##############################################
+## CREATE CXT VPC PAIR ##
+##############################################
+
+- name: Create DCNM VPC switch pair
+ cisco.dcnm.dcnm_rest:
+ method: POST
+ path: "{{ vpc_create_path[controller_version] }}"
+ json_data:
+ "{{ vpc_cxt_data | to_json}}"
+ register: result
+ when: (cxt_vpc_create == True)
+ ignore_errors: yes
+
+- name: Wait for 20 secs
+ wait_for:
+ timeout: 10
+ when: (cxt_vpc_create == True)
+
+##############################################
+## CONFIG SAVE ##
+##############################################
+
+- name: Config Save
+ cisco.dcnm.dcnm_rest:
+ method: POST
+ path: "{{ cxt_config_save_path[controller_version] }}"
+ register: result
+ when: (cxt_vpc_create == True)
+ ignore_errors: yes
+
+##############################################
+## DEPLOY CXT VPC PAIR ##
+##############################################
+
+- name: Deploy VPC switch pair
+ cisco.dcnm.dcnm_rest:
+ method: POST
+ path: "{{ vpc_cxt_deploy_path[controller_version] }}"
+ register: result
+ with_sequence: count=1
+ loop_control:
+ pause: 5
+ when: (cxt_vpc_deploy == True)
+ ignore_errors: yes
+
+- name: Wait for 30 secs
+ wait_for:
+ timeout: 30
+ when: (cxt_vpc_deploy == True)
diff --git a/tests/unit/modules/dcnm/fixtures/dcnm_intf_aa_fex_configs.json b/tests/unit/modules/dcnm/fixtures/dcnm_intf_aa_fex_configs.json
index 2b36b8467..de72c114c 100644
--- a/tests/unit/modules/dcnm/fixtures/dcnm_intf_aa_fex_configs.json
+++ b/tests/unit/modules/dcnm/fixtures/dcnm_intf_aa_fex_configs.json
@@ -1,12 +1,28 @@
{
"mock_fab_inv_data": {
"192.168.1.108": {
- "isVpcConfigured": "True",
- "vpcDomain": 1
+ "logicalName": "n9kv-108",
+ "serialNumber": "SAL1819SAN8",
+ "isVpcConfigured": "True",
+ "vpcDomain": 1,
+ "switchRoleEnum": "Leaf",
+ "managable": "True"
},
"192.168.1.109": {
+ "logicalName": "n9kv-109",
+ "serialNumber": "FOX1821H035",
+ "isVpcConfigured": "True",
+ "vpcDomain": 1,
+ "switchRoleEnum": "Leaf",
+ "managable": "True"
+ },
+ "10.69.69.1": {
+ "logicalName": "n9kv-1",
+ "serialNumber": "TEST-SNO-1",
"isVpcConfigured": "True",
- "vpcDomain": 1
+ "vpcDomain": 1,
+ "switchRoleEnum": "None",
+ "managable": "False"
}
},
@@ -20,6 +36,20 @@
"192.168.1.109" : "FOX1821H035~SAL1819SAN8"
},
+ "mock_monitor_true_resp": {
+ "RETURN_CODE": 200,
+ "DATA":{
+ "readonly": "True"
+ }
+ },
+
+ "mock_monitor_false_resp": {
+ "RETURN_CODE": 200,
+ "DATA":{
+ "readonly": "False"
+ }
+ },
+
"mock_vpc_resp" : {
"MESSAGE": "OK",
"REQUEST_PATH": "https://10.122.197.6:443/rest/interface/vpcpair_serial_number?serial_number=FOX1821H035",
diff --git a/tests/unit/modules/dcnm/fixtures/dcnm_intf_bunched_configs.json b/tests/unit/modules/dcnm/fixtures/dcnm_intf_bunched_configs.json
index b23f02abf..d54461084 100644
--- a/tests/unit/modules/dcnm/fixtures/dcnm_intf_bunched_configs.json
+++ b/tests/unit/modules/dcnm/fixtures/dcnm_intf_bunched_configs.json
@@ -1,15 +1,31 @@
{
- "mock_fab_inv_data": {
- "192.168.1.108": {
+ "mock_fab_inv_data": {
+ "192.168.1.108": {
+ "logicalName": "n9kv-108",
+ "serialNumber": "SAL1819SAN8",
"isVpcConfigured": "True",
- "vpcDomain": 1
- },
+ "vpcDomain": 1,
+ "switchRoleEnum": "Leaf",
+ "managable": "True"
+ },
"192.168.1.109": {
+ "logicalName": "n9kv-109",
+ "serialNumber": "FOX1821H035",
+ "isVpcConfigured": "True",
+ "vpcDomain": 1,
+ "switchRoleEnum": "Leaf",
+ "managable": "True"
+ },
+ "10.69.69.1": {
+ "logicalName": "n9kv-1",
+ "serialNumber": "TEST-SNO-1",
"isVpcConfigured": "True",
- "vpcDomain": 1
+ "vpcDomain": 1,
+ "switchRoleEnum": "None",
+ "managable": "False"
}
- },
+ },
"mock_ip_sn" : {
"192.168.1.109": "FOX1821H035",
@@ -31,6 +47,20 @@
"192.168.1.109" : "FOX1821H035~SAL1819SAN8"
},
+ "mock_monitor_true_resp": {
+ "RETURN_CODE": 200,
+ "DATA":{
+ "readonly": "True"
+ }
+ },
+
+ "mock_monitor_false_resp": {
+ "RETURN_CODE": 200,
+ "DATA":{
+ "readonly": "False"
+ }
+ },
+
"mock_succ_resp" : {
"DATA": {},
"MESSAGE": "OK",
diff --git a/tests/unit/modules/dcnm/fixtures/dcnm_intf_eth_configs.json b/tests/unit/modules/dcnm/fixtures/dcnm_intf_eth_configs.json
index e807e9d8b..df177a308 100644
--- a/tests/unit/modules/dcnm/fixtures/dcnm_intf_eth_configs.json
+++ b/tests/unit/modules/dcnm/fixtures/dcnm_intf_eth_configs.json
@@ -1,14 +1,30 @@
{
- "mock_fab_inv_data": {
- "192.168.1.108": {
+ "mock_fab_inv_data": {
+ "192.168.1.108": {
+ "logicalName": "n9kv-108",
+ "serialNumber": "SAL1819SAN8",
"isVpcConfigured": "True",
- "vpcDomain": 1
- },
+ "vpcDomain": 1,
+ "switchRoleEnum": "Leaf",
+ "managable": "True"
+ },
"192.168.1.109": {
+ "logicalName": "n9kv-109",
+ "serialNumber": "FOX1821H035",
+ "isVpcConfigured": "True",
+ "vpcDomain": 1,
+ "switchRoleEnum": "Leaf",
+ "managable": "True"
+ },
+ "10.69.69.1": {
+ "logicalName": "n9kv-1",
+ "serialNumber": "TEST-SNO-1",
"isVpcConfigured": "True",
- "vpcDomain": 1
+ "vpcDomain": 1,
+ "switchRoleEnum": "None",
+ "managable": "False"
}
- },
+ },
"mock_ip_sn" : {
"192.168.1.109": "FOX1821H035",
@@ -30,6 +46,20 @@
"METHOD": "GET"
},
+ "mock_monitor_true_resp": {
+ "RETURN_CODE": 200,
+ "DATA":{
+ "readonly": "True"
+ }
+ },
+
+ "mock_monitor_false_resp": {
+ "RETURN_CODE": 200,
+ "DATA":{
+ "readonly": "False"
+ }
+ },
+
"mock_succ_resp" : {
"DATA": {},
"MESSAGE": "OK",
diff --git a/tests/unit/modules/dcnm/fixtures/dcnm_intf_have_all_payloads.json b/tests/unit/modules/dcnm/fixtures/dcnm_intf_have_all_payloads.json
index a6eb86147..e4ae9211b 100644
--- a/tests/unit/modules/dcnm/fixtures/dcnm_intf_have_all_payloads.json
+++ b/tests/unit/modules/dcnm/fixtures/dcnm_intf_have_all_payloads.json
@@ -15,6 +15,7 @@
"deletable": "True",
"markDeleted": "False",
"alias": "",
+ "deleteReason": null,
"complianceStatus": "In-Sync",
"underlayPolicies": [
{
@@ -39,6 +40,7 @@
"deletable": "True",
"markDeleted": "False",
"alias": "",
+ "deleteReason": null,
"complianceStatus": "In-Sync",
"underlayPolicies": [
{
@@ -63,6 +65,7 @@
"deletable": "True",
"markDeleted": "False",
"alias": "",
+ "deleteReason": null,
"complianceStatus": "In-Sync",
"underlayPolicies": [
{
@@ -88,6 +91,7 @@
"deletable": "True",
"markDeleted": "False",
"alias": "",
+ "deleteReason": null,
"complianceStatus": "In-Sync",
"underlayPolicies": [
{
@@ -112,6 +116,7 @@
"deletable": "True",
"markDeleted": "False",
"alias": "",
+ "deleteReason": null,
"complianceStatus": "In-Sync",
"underlayPolicies": [
{
@@ -125,14 +130,14 @@
}
]
}
- ],
- "RETURN_CODE": 200,
- "METHOD": "GET"
+ ],
+ "RETURN_CODE": 200,
+ "METHOD": "GET"
},
- "deployed_payloads" :
- {
- "MESSAGE": "OK",
+ "deployed_payloads" :
+ {
+ "MESSAGE": "OK",
"REQUEST_PATH": "https://10.122.197.6:443/rest/interface?serialNumber=SAL1819SAN8",
"DATA": [
{
@@ -864,11 +869,45 @@
],
"RETURN_CODE": 200,
"METHOD": "GET"
- },
+ },
- "payloads" :
- {
- "MESSAGE": "OK",
+ "deleted_intf_payloads" :
+ {
+ "MESSAGE": "OK",
+ "REQUEST_PATH": "https://10.122.197.6:443/rest/interface?serialNumber=SAL1819SAN8",
+ "DATA": [
+ {
+ "ifName": "port-channel999",
+ "mode": "pc",
+ "serialNo": "SAL1819SAN8",
+ "fabricName": "test_fabric",
+ "ifType": "INTERFACE_PORT_CHANNEL",
+ "isPhysical": "False",
+ "deletable": "True",
+ "markDeleted": "True",
+ "alias": "",
+ "deleteReason": null,
+ "complianceStatus": "In-Sync",
+ "underlayPolicies": [
+ {
+ "source" : ""
+ }
+ ],
+ "interfaces": [
+ {
+ "nvPairs": {
+ }
+ }
+ ]
+ }
+ ],
+ "RETURN_CODE": 200,
+ "METHOD": "GET"
+ },
+
+ "payloads" :
+ {
+ "MESSAGE": "OK",
"REQUEST_PATH": "https://10.122.197.6:443/rest/interface?serialNumber=SAL1819SAN8",
"DATA": [
{
@@ -881,6 +920,7 @@
"deletable": "True",
"markDeleted": "False",
"alias": "",
+ "deleteReason": null,
"complianceStatus": "In-Sync",
"underlayPolicies": [
{
@@ -904,6 +944,7 @@
"deletable": "False",
"markDeleted": "False",
"alias": "",
+ "deleteReason": null,
"complianceStatus": "In-Sync",
"underlayPolicies": [
{
@@ -927,6 +968,7 @@
"deletable": "True",
"markDeleted": "False",
"alias": "",
+ "deleteReason": null,
"complianceStatus": "In-Sync",
"underlayPolicies": [
{
@@ -950,6 +992,7 @@
"deletable": "True",
"markDeleted": "False",
"alias": "",
+ "deleteReason": null,
"complianceStatus": "In-Sync",
"underlayPolicies": [
{
@@ -973,6 +1016,7 @@
"deletable": "True",
"markDeleted": "False",
"alias": "",
+ "deleteReason": null,
"complianceStatus": "In-Sync",
"underlayPolicies": [
{
@@ -996,6 +1040,7 @@
"deletable": "True",
"markDeleted": "False",
"alias": "",
+ "deleteReason": null,
"complianceStatus": "In-Sync",
"underlayPolicies": [
{
@@ -1019,6 +1064,7 @@
"deletable": "True",
"markDeleted": "False",
"alias": "",
+ "deleteReason": null,
"complianceStatus": "In-Sync",
"underlayPolicies": [
{
@@ -1042,6 +1088,7 @@
"deletable": "False",
"markDeleted": "False",
"alias": "",
+ "deleteReason": null,
"complianceStatus": "In-Sync",
"underlayPolicies": [
{
@@ -1065,6 +1112,7 @@
"deletable": "False",
"markDeleted": "False",
"alias": "",
+ "deleteReason": null,
"complianceStatus": "In-Sync",
"underlayPolicies": [
{
@@ -1088,6 +1136,7 @@
"deletable": "True",
"markDeleted": "False",
"alias": "",
+ "deleteReason": null,
"complianceStatus": "In-Sync",
"underlayPolicies": [
{
@@ -1111,6 +1160,7 @@
"deletable": "True",
"markDeleted": "False",
"alias": "",
+ "deleteReason": null,
"complianceStatus": "In-Sync",
"underlayPolicies": [
{
@@ -1134,6 +1184,7 @@
"deletable": "False",
"markDeleted": "False",
"alias": "",
+ "deleteReason": null,
"complianceStatus": "In-Sync",
"underlayPolicies": [
{
@@ -1150,6 +1201,6 @@
],
"RETURN_CODE": 200,
"METHOD": "GET"
- }
+ }
}
diff --git a/tests/unit/modules/dcnm/fixtures/dcnm_intf_lo_configs.json b/tests/unit/modules/dcnm/fixtures/dcnm_intf_lo_configs.json
index 745c7af93..6ba28cf15 100644
--- a/tests/unit/modules/dcnm/fixtures/dcnm_intf_lo_configs.json
+++ b/tests/unit/modules/dcnm/fixtures/dcnm_intf_lo_configs.json
@@ -1,15 +1,30 @@
{
- "mock_fab_inv_data": {
- "192.168.1.108": {
+ "mock_fab_inv_data": {
+ "192.168.1.108": {
+ "logicalName": "n9kv-108",
+ "serialNumber": "SAL1819SAN8",
"isVpcConfigured": "True",
- "vpcDomain": 1
- },
+ "vpcDomain": 1,
+ "switchRoleEnum": "Leaf",
+ "managable": "True"
+ },
"192.168.1.109": {
+ "logicalName": "n9kv-109",
+ "serialNumber": "FOX1821H035",
+ "isVpcConfigured": "True",
+ "vpcDomain": 1,
+ "switchRoleEnum": "Leaf",
+ "managable": "True"
+ },
+ "10.69.69.1": {
+ "logicalName": "n9kv-1",
+ "serialNumber": "TEST-SNO-1",
"isVpcConfigured": "True",
- "vpcDomain": 1
+ "vpcDomain": 1,
+ "switchRoleEnum": "None",
+ "managable": "False"
}
- },
-
+ },
"mock_ip_sn" : {
"192.168.1.109": "FOX1821H035",
"192.168.1.108": "SAL1819SAN8"
@@ -20,6 +35,20 @@
"192.168.1.109" : "FOX1821H035~SAL1819SAN8"
},
+ "mock_monitor_true_resp": {
+ "RETURN_CODE": 200,
+ "DATA":{
+ "readonly": "True"
+ }
+ },
+
+ "mock_monitor_false_resp": {
+ "RETURN_CODE": 200,
+ "DATA":{
+ "readonly": "False"
+ }
+ },
+
"mock_vpc_resp" : {
"MESSAGE": "OK",
"REQUEST_PATH": "https://10.122.197.6:443/rest/interface/vpcpair_serial_number?serial_number=FOX1821H035",
diff --git a/tests/unit/modules/dcnm/fixtures/dcnm_intf_mixed_configs.json b/tests/unit/modules/dcnm/fixtures/dcnm_intf_mixed_configs.json
index b84ed755e..e391c78a9 100644
--- a/tests/unit/modules/dcnm/fixtures/dcnm_intf_mixed_configs.json
+++ b/tests/unit/modules/dcnm/fixtures/dcnm_intf_mixed_configs.json
@@ -1,20 +1,50 @@
{
- "mock_fab_inv_data": {
- "192.168.1.108": {
+ "mock_fab_inv_data": {
+ "192.168.1.108": {
+ "logicalName": "n9kv-108",
+ "serialNumber": "SAL1819SAN8",
"isVpcConfigured": "True",
- "vpcDomain": 1
- },
+ "vpcDomain": 1,
+ "switchRoleEnum": "Leaf",
+ "managable": "True"
+ },
"192.168.1.109": {
+ "logicalName": "n9kv-109",
+ "serialNumber": "FOX1821H035",
+ "isVpcConfigured": "True",
+ "vpcDomain": 1,
+ "switchRoleEnum": "Leaf",
+ "managable": "True"
+ },
+ "10.69.69.1": {
+ "logicalName": "n9kv-1",
+ "serialNumber": "TEST-SNO-1",
"isVpcConfigured": "True",
- "vpcDomain": 1
+ "vpcDomain": 1,
+ "switchRoleEnum": "None",
+ "managable": "False"
}
- },
+ },
"mock_ip_sn" : {
"192.168.1.109": "FOX1821H035",
"192.168.1.108": "SAL1819SAN8"
},
+ "mock_monitor_true_resp": {
+ "RETURN_CODE": 200,
+ "DATA":{
+ "readonly": "True"
+ }
+ },
+
+ "mock_monitor_false_resp": {
+ "RETURN_CODE": 200,
+ "DATA":{
+ "readonly": "False"
+ }
+ },
+
"mock_vpc_resp" : {
"MESSAGE": "OK",
"REQUEST_PATH": "https://10.122.197.6:443/rest/interface/vpcpair_serial_number?serial_number=FOX1821H035",
diff --git a/tests/unit/modules/dcnm/fixtures/dcnm_intf_multi_configs.json b/tests/unit/modules/dcnm/fixtures/dcnm_intf_multi_configs.json
index 96208d42c..eb1501551 100644
--- a/tests/unit/modules/dcnm/fixtures/dcnm_intf_multi_configs.json
+++ b/tests/unit/modules/dcnm/fixtures/dcnm_intf_multi_configs.json
@@ -1,12 +1,42 @@
{
- "mock_fab_inv_data": {
- "192.168.1.108": {
+ "mock_fab_inv_data": {
+ "192.168.1.108": {
+ "logicalName": "n9kv-108",
+ "serialNumber": "SAL1819SAN8",
"isVpcConfigured": "True",
- "vpcDomain": 1
- },
+ "vpcDomain": 1,
+ "switchRoleEnum": "Leaf",
+ "managable": "True"
+ },
"192.168.1.109": {
+ "logicalName": "n9kv-109",
+ "serialNumber": "FOX1821H035",
+ "isVpcConfigured": "True",
+ "vpcDomain": 1,
+ "switchRoleEnum": "Leaf",
+ "managable": "True"
+ },
+ "10.69.69.1": {
+ "logicalName": "n9kv-1",
+ "serialNumber": "TEST-SNO-1",
"isVpcConfigured": "True",
- "vpcDomain": 1
+ "vpcDomain": 1,
+ "switchRoleEnum": "None",
+ "managable": "False"
+ }
+ },
+
+ "mock_monitor_true_resp": {
+ "RETURN_CODE": 200,
+ "DATA":{
+ "readonly": "True"
+ }
+ },
+
+ "mock_monitor_false_resp": {
+ "RETURN_CODE": 200,
+ "DATA":{
+ "readonly": "False"
}
},
diff --git a/tests/unit/modules/dcnm/fixtures/dcnm_intf_multi_intf_configs.json b/tests/unit/modules/dcnm/fixtures/dcnm_intf_multi_intf_configs.json
index 8555beefb..c80b7d293 100644
--- a/tests/unit/modules/dcnm/fixtures/dcnm_intf_multi_intf_configs.json
+++ b/tests/unit/modules/dcnm/fixtures/dcnm_intf_multi_intf_configs.json
@@ -1,12 +1,42 @@
{
- "mock_fab_inv_data": {
- "192.168.1.108": {
+ "mock_fab_inv_data": {
+ "192.168.1.108": {
+ "logicalName": "n9kv-108",
+ "serialNumber": "SAL1819SAN8",
"isVpcConfigured": "True",
- "vpcDomain": 1
- },
+ "vpcDomain": 1,
+ "switchRoleEnum": "Leaf",
+ "managable": "True"
+ },
"192.168.1.109": {
+ "logicalName": "n9kv-109",
+ "serialNumber": "FOX1821H035",
+ "isVpcConfigured": "True",
+ "vpcDomain": 1,
+ "switchRoleEnum": "Leaf",
+ "managable": "True"
+ },
+ "10.69.69.1": {
+ "logicalName": "n9kv-1",
+ "serialNumber": "TEST-SNO-1",
"isVpcConfigured": "True",
- "vpcDomain": 1
+ "vpcDomain": 1,
+ "switchRoleEnum": "None",
+ "managable": "False"
+ }
+ },
+
+ "mock_monitor_true_resp": {
+ "RETURN_CODE": 200,
+ "DATA":{
+ "readonly": "True"
+ }
+ },
+
+ "mock_monitor_false_resp": {
+ "RETURN_CODE": 200,
+ "DATA":{
+ "readonly": "False"
}
},
diff --git a/tests/unit/modules/dcnm/fixtures/dcnm_intf_pc_configs.json b/tests/unit/modules/dcnm/fixtures/dcnm_intf_pc_configs.json
index 52c91a16c..add47f751 100644
--- a/tests/unit/modules/dcnm/fixtures/dcnm_intf_pc_configs.json
+++ b/tests/unit/modules/dcnm/fixtures/dcnm_intf_pc_configs.json
@@ -1,12 +1,41 @@
{
- "mock_fab_inv_data": {
- "192.168.1.108": {
+ "mock_fab_inv_data": {
+ "192.168.1.108": {
+ "logicalName": "n9kv-108",
+ "serialNumber": "SAL1819SAN8",
"isVpcConfigured": "True",
- "vpcDomain": 1
- },
+ "vpcDomain": 1,
+ "switchRoleEnum": "Leaf",
+ "managable": "True"
+ },
"192.168.1.109": {
+ "logicalName": "n9kv-109",
+ "serialNumber": "FOX1821H035",
+ "isVpcConfigured": "True",
+ "vpcDomain": 1,
+ "switchRoleEnum": "Leaf",
+ "managable": "True"
+ },
+ "10.69.69.1": {
+ "logicalName": "n9kv-1",
+ "serialNumber": "TEST-SNO-1",
"isVpcConfigured": "True",
- "vpcDomain": 1
+ "vpcDomain": 1,
+ "switchRoleEnum": "None",
+ "managable": "False"
+ }
+ },
+ "mock_monitor_true_resp": {
+ "RETURN_CODE": 200,
+ "DATA":{
+ "readonly": "True"
+ }
+ },
+
+ "mock_monitor_false_resp": {
+ "RETURN_CODE": 200,
+ "DATA":{
+ "readonly": "False"
}
},
@@ -135,6 +164,37 @@
"deploy": "False"
}],
+ "pc_unmanagable_merged_config" : [
+ {
+ "switch": [
+ "n9kv-1"
+ ],
+ "profile": {
+ "description": "port channel acting as trunk",
+ "bpdu_guard": "True",
+ "sno": "SAL1819SAN8",
+ "mtu": "jumbo",
+ "pc_mode": "on",
+ "mode": "trunk",
+ "members": [
+ "e1/9"
+ ],
+ "port_type_fast": "True",
+ "policy": "int_port_channel_trunk_host_11_1",
+ "admin_state": "True",
+ "allowed_vlans": "none",
+ "cmds": [
+ "no shutdown"
+ ],
+ "ifname": "Port-channel300",
+ "fabric": "test_fabric"
+ },
+ "type": "pc",
+ "name": "po300",
+ "deploy": "True"
+ }
+ ],
+
"pc_merged_config" : [
{
"switch": [
@@ -237,6 +297,24 @@
"deploy": "True"
}],
+ "pc_deleted_config_deploy" : [
+ {
+ "switch": [
+ "192.168.1.108"
+ ],
+ "name": "po999",
+ "deploy": "True"
+ }],
+
+ "pc_deleted_config_no_deploy" : [
+ {
+ "switch": [
+ "192.168.1.108"
+ ],
+ "name": "po300",
+ "deploy": "False"
+ }],
+
"pc_deleted_config" : [
{
"switch": [
diff --git a/tests/unit/modules/dcnm/fixtures/dcnm_intf_query_configs.json b/tests/unit/modules/dcnm/fixtures/dcnm_intf_query_configs.json
index 98f35e6fa..47ba4841e 100644
--- a/tests/unit/modules/dcnm/fixtures/dcnm_intf_query_configs.json
+++ b/tests/unit/modules/dcnm/fixtures/dcnm_intf_query_configs.json
@@ -1,12 +1,41 @@
{
- "mock_fab_inv_data": {
- "192.168.1.108": {
+ "mock_fab_inv_data": {
+ "192.168.1.108": {
+ "logicalName": "n9kv-108",
+ "serialNumber": "SAL1819SAN8",
"isVpcConfigured": "True",
- "vpcDomain": 1
- },
+ "vpcDomain": 1,
+ "switchRoleEnum": "Leaf",
+ "managable": "True"
+ },
"192.168.1.109": {
+ "logicalName": "n9kv-109",
+ "serialNumber": "FOX1821H035",
+ "isVpcConfigured": "True",
+ "vpcDomain": 1,
+ "switchRoleEnum": "Leaf",
+ "managable": "True"
+ },
+ "10.69.69.1": {
+ "logicalName": "n9kv-1",
+ "serialNumber": "TEST-SNO-1",
"isVpcConfigured": "True",
- "vpcDomain": 1
+ "vpcDomain": 1,
+ "switchRoleEnum": "None",
+ "managable": "False"
+ }
+ },
+ "mock_monitor_true_resp": {
+ "RETURN_CODE": 200,
+ "DATA":{
+ "readonly": "True"
+ }
+ },
+
+ "mock_monitor_false_resp": {
+ "RETURN_CODE": 200,
+ "DATA":{
+ "readonly": "False"
}
},
diff --git a/tests/unit/modules/dcnm/fixtures/dcnm_intf_st_fex_configs.json b/tests/unit/modules/dcnm/fixtures/dcnm_intf_st_fex_configs.json
index d44e78fb1..179632827 100644
--- a/tests/unit/modules/dcnm/fixtures/dcnm_intf_st_fex_configs.json
+++ b/tests/unit/modules/dcnm/fixtures/dcnm_intf_st_fex_configs.json
@@ -1,14 +1,43 @@
{
"mock_fab_inv_data": {
"192.168.1.108": {
- "isVpcConfigured": "True",
- "vpcDomain": 1
+ "logicalName": "n9kv-108",
+ "serialNumber": "SAL1819SAN8",
+ "isVpcConfigured": "True",
+ "vpcDomain": 1,
+ "switchRoleEnum": "Leaf",
+ "managable": "True"
},
"192.168.1.109": {
+ "logicalName": "n9kv-109",
+ "serialNumber": "FOX1821H035",
+ "isVpcConfigured": "True",
+ "vpcDomain": 1,
+ "switchRoleEnum": "Leaf",
+ "managable": "True"
+ },
+ "10.69.69.1": {
+ "logicalName": "n9kv-1",
+ "serialNumber": "TEST-SNO-1",
"isVpcConfigured": "True",
- "vpcDomain": 1
+ "vpcDomain": 1,
+ "switchRoleEnum": "None",
+ "managable": "False"
}
},
+ "mock_monitor_true_resp": {
+ "RETURN_CODE": 200,
+ "DATA":{
+ "readonly": "True"
+ }
+ },
+
+ "mock_monitor_false_resp": {
+ "RETURN_CODE": 200,
+ "DATA":{
+ "readonly": "False"
+ }
+ },
"mock_ip_sn" : {
"192.168.1.109": "FOX1821H035",
diff --git a/tests/unit/modules/dcnm/fixtures/dcnm_intf_subint_configs.json b/tests/unit/modules/dcnm/fixtures/dcnm_intf_subint_configs.json
index 4f9cb9186..36a279eec 100644
--- a/tests/unit/modules/dcnm/fixtures/dcnm_intf_subint_configs.json
+++ b/tests/unit/modules/dcnm/fixtures/dcnm_intf_subint_configs.json
@@ -1,12 +1,41 @@
{
- "mock_fab_inv_data": {
- "192.168.1.108": {
+ "mock_fab_inv_data": {
+ "192.168.1.108": {
+ "logicalName": "n9kv-108",
+ "serialNumber": "SAL1819SAN8",
"isVpcConfigured": "True",
- "vpcDomain": 1
- },
+ "vpcDomain": 1,
+ "switchRoleEnum": "Leaf",
+ "managable": "True"
+ },
"192.168.1.109": {
+ "logicalName": "n9kv-109",
+ "serialNumber": "FOX1821H035",
+ "isVpcConfigured": "True",
+ "vpcDomain": 1,
+ "switchRoleEnum": "Leaf",
+ "managable": "True"
+ },
+ "10.69.69.1": {
+ "logicalName": "n9kv-1",
+ "serialNumber": "TEST-SNO-1",
"isVpcConfigured": "True",
- "vpcDomain": 1
+ "vpcDomain": 1,
+ "switchRoleEnum": "None",
+ "managable": "False"
+ }
+ },
+ "mock_monitor_true_resp": {
+ "RETURN_CODE": 200,
+ "DATA":{
+ "readonly": "True"
+ }
+ },
+
+ "mock_monitor_false_resp": {
+ "RETURN_CODE": 200,
+ "DATA":{
+ "readonly": "False"
}
},
diff --git a/tests/unit/modules/dcnm/fixtures/dcnm_intf_svi_configs.json b/tests/unit/modules/dcnm/fixtures/dcnm_intf_svi_configs.json
index 33d92d86d..9921e8a78 100644
--- a/tests/unit/modules/dcnm/fixtures/dcnm_intf_svi_configs.json
+++ b/tests/unit/modules/dcnm/fixtures/dcnm_intf_svi_configs.json
@@ -1,12 +1,41 @@
{
- "mock_fab_inv_data": {
- "192.168.1.108": {
+ "mock_fab_inv_data": {
+ "192.168.1.108": {
+ "logicalName": "n9kv-108",
+ "serialNumber": "SAL1819SAN8",
"isVpcConfigured": "True",
- "vpcDomain": 1
- },
+ "vpcDomain": 1,
+ "switchRoleEnum": "Leaf",
+ "managable": "True"
+ },
"192.168.1.109": {
+ "logicalName": "n9kv-109",
+ "serialNumber": "FOX1821H035",
+ "isVpcConfigured": "True",
+ "vpcDomain": 1,
+ "switchRoleEnum": "Leaf",
+ "managable": "True"
+ },
+ "10.69.69.1": {
+ "logicalName": "n9kv-1",
+ "serialNumber": "TEST-SNO-1",
"isVpcConfigured": "True",
- "vpcDomain": 1
+ "vpcDomain": 1,
+ "switchRoleEnum": "None",
+ "managable": "False"
+ }
+ },
+ "mock_monitor_true_resp": {
+ "RETURN_CODE": 200,
+ "DATA":{
+ "readonly": "True"
+ }
+ },
+
+ "mock_monitor_false_resp": {
+ "RETURN_CODE": 200,
+ "DATA":{
+ "readonly": "False"
}
},
diff --git a/tests/unit/modules/dcnm/fixtures/dcnm_intf_vpc_configs.json b/tests/unit/modules/dcnm/fixtures/dcnm_intf_vpc_configs.json
index 789fe548a..920a94cae 100644
--- a/tests/unit/modules/dcnm/fixtures/dcnm_intf_vpc_configs.json
+++ b/tests/unit/modules/dcnm/fixtures/dcnm_intf_vpc_configs.json
@@ -1,12 +1,41 @@
{
- "mock_fab_inv_data": {
- "192.168.1.108": {
+ "mock_fab_inv_data": {
+ "192.168.1.108": {
+ "logicalName": "n9kv-108",
+ "serialNumber": "SAL1819SAN8",
"isVpcConfigured": "True",
- "vpcDomain": 1
- },
+ "vpcDomain": 1,
+ "switchRoleEnum": "Leaf",
+ "managable": "True"
+ },
"192.168.1.109": {
+ "logicalName": "n9kv-109",
+ "serialNumber": "FOX1821H035",
+ "isVpcConfigured": "True",
+ "vpcDomain": 1,
+ "switchRoleEnum": "Leaf",
+ "managable": "True"
+ },
+ "10.69.69.1": {
+ "logicalName": "n9kv-1",
+ "serialNumber": "TEST-SNO-1",
"isVpcConfigured": "True",
- "vpcDomain": 1
+ "vpcDomain": 1,
+ "switchRoleEnum": "None",
+ "managable": "False"
+ }
+ },
+ "mock_monitor_true_resp": {
+ "RETURN_CODE": 200,
+ "DATA":{
+ "readonly": "True"
+ }
+ },
+
+ "mock_monitor_false_resp": {
+ "RETURN_CODE": 200,
+ "DATA":{
+ "readonly": "False"
}
},
diff --git a/tests/unit/modules/dcnm/fixtures/dcnm_inventory.json b/tests/unit/modules/dcnm/fixtures/dcnm_inventory.json
index b496773af..0d4007dee 100644
--- a/tests/unit/modules/dcnm/fixtures/dcnm_inventory.json
+++ b/tests/unit/modules/dcnm/fixtures/dcnm_inventory.json
@@ -190,7 +190,9 @@
"hostname": "test_poap_test",
"model": "N9K-C9300v",
"serial_number": "9D2DAUJJFQQ",
- "version": "9.3(7)"
+ "version": "9.3(7)",
+ "discovery_username": "aaa_username",
+ "discovery_password": "aaa_password"
}
]
}
@@ -342,6 +344,40 @@
}
],
+ "playbook_poap_missing_credentials_password" : [
+ {
+ "password": "password",
+ "seed_ip": "192.168.1.223",
+ "user_name": "admin",
+ "poap": [
+ {
+ "config_data": "{\"modulesModel\": [\"N9K-C9300v\"], \"gateway\": \"192.168.1.1/24\"}",
+ "hostname": "test_poap_test",
+ "model": "N9K-C9300v",
+ "version": "9.3(7)",
+ "discovery_username": "aaa_username"
+ }
+ ]
+ }
+ ],
+
+ "playbook_poap_missing_credentials_username" : [
+ {
+ "password": "password",
+ "seed_ip": "192.168.1.223",
+ "user_name": "admin",
+ "poap": [
+ {
+ "config_data": "{\"modulesModel\": [\"N9K-C9300v\"], \"gateway\": \"192.168.1.1/24\"}",
+ "hostname": "test_poap_test",
+ "model": "N9K-C9300v",
+ "version": "9.3(7)",
+ "discovery_password": "aaa_password"
+ }
+ ]
+ }
+ ],
+
"playbook_poap_no_model_switch_config" : [
{
"password": "password",
@@ -388,7 +424,45 @@
"model": "N9K-C9300v",
"serial_number": "9D2DAUJJFQQ",
"old_serial": "9D2DAUJJFRR",
- "version": "9.3(7)"
+ "version": "9.3(7)",
+ "discovery_username": "aaa_username",
+ "discovery_password": "aaa_password"
+ }
+ ]
+ }
+ ],
+
+ "playbook_rma_missing_credentials_password" : [
+ {
+ "password": "password",
+ "seed_ip": "192.168.1.223",
+ "user_name": "admin",
+ "rma": [
+ {
+ "config_data": "{\"modulesModel\": [\"N9K-C9300v\"], \"gateway\": \"192.168.1.1/24\"}",
+ "hostname": "test_poap_test",
+ "model": "N9K-C9300v",
+ "version": "9.3(7)",
+ "old_serial": "9D2DAUJJFRR",
+ "discovery_username": "aaa_username"
+ }
+ ]
+ }
+ ],
+
+ "playbook_rma_missing_credentials_username" : [
+ {
+ "password": "password",
+ "seed_ip": "192.168.1.223",
+ "user_name": "admin",
+ "rma": [
+ {
+ "config_data": "{\"modulesModel\": [\"N9K-C9300v\"], \"gateway\": \"192.168.1.1/24\"}",
+ "hostname": "test_poap_test",
+ "model": "N9K-C9300v",
+ "version": "9.3(7)",
+ "old_serial": "9D2DAUJJFRR",
+ "discovery_password": "aaa_password"
}
]
}
diff --git a/tests/unit/modules/dcnm/test_dcnm_intf.py b/tests/unit/modules/dcnm/test_dcnm_intf.py
index 5a719f555..6ceb0bb17 100644
--- a/tests/unit/modules/dcnm/test_dcnm_intf.py
+++ b/tests/unit/modules/dcnm/test_dcnm_intf.py
@@ -96,6 +96,7 @@ def load_multi_intf_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
self.playbook_mock_vpc_resp,
playbook_pc_intf,
@@ -137,6 +138,7 @@ def load_multi_intf_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
self.playbook_mock_vpc_resp,
playbook_pc_intf,
@@ -180,6 +182,7 @@ def load_missing_intf_elems_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
self.playbook_mock_vpc_resp,
playbook_pc_intf1,
@@ -223,6 +226,7 @@ def load_mixed_intf_elems_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
self.playbook_mock_vpc_resp,
playbook_pc_intf,
@@ -271,6 +275,7 @@ def load_bunched_intf_elems_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
self.playbook_mock_vpc_resp,
playbook_pc_intf1,
@@ -315,6 +320,7 @@ def load_missing_members_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
self.playbook_mock_vpc_resp,
playbook_intf,
@@ -345,6 +351,7 @@ def load_type_missing_fixtures(self):
"payloads"
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_pc_intf,
self.playbook_mock_succ_resp,
@@ -372,6 +379,7 @@ def load_missing_state_fixtures(self):
"payloads"
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_pc_intf,
playbook_have_all_data,
@@ -433,6 +441,13 @@ def load_query_state_fixtures(self):
self.playbook_mock_succ_resp,
]
+ def load_intf_misc_fixtures(self):
+
+ if "test_dcnm_intf_merge_fabric_monitoring" in self._testMethodName:
+ self.run_dcnm_send.side_effect = [self.mock_monitor_true_resp]
+ if "test_dcnm_intf_merge_unmanagable_switch" in self._testMethodName:
+ self.run_dcnm_send.side_effect = [self.mock_monitor_false_resp]
+
# -------------------------- SVI-FIXTURES --------------------------
def load_svi_fixtures(self):
@@ -445,6 +460,7 @@ def load_svi_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_svi_intf1,
playbook_have_all_data,
@@ -461,6 +477,7 @@ def load_svi_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_svi_intf1,
playbook_have_all_data,
@@ -478,6 +495,7 @@ def load_svi_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_svi_intf1,
self.playbook_mock_succ_resp,
@@ -492,8 +510,10 @@ def load_svi_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_svi_intf1,
+ playbook_svi_intf1,
]
if "_svi_replaced_existing" in self._testMethodName:
playbook_svi_intf1 = self.payloads_data.get("svi_merged_payloads")
@@ -502,6 +522,7 @@ def load_svi_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_svi_intf1,
playbook_have_all_data,
@@ -518,6 +539,7 @@ def load_svi_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_svi_intf1,
playbook_have_all_data,
@@ -552,6 +574,7 @@ def load_aa_fex_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_aa_fex_intf1,
playbook_have_all_data,
@@ -567,6 +590,7 @@ def load_aa_fex_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_aa_fex_intf1,
playbook_have_all_data,
@@ -582,6 +606,7 @@ def load_aa_fex_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_aa_fex_intf1,
playbook_have_all_data,
@@ -599,6 +624,7 @@ def load_aa_fex_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
self.playbook_mock_vpc_resp,
playbook_aa_fex_intf1,
@@ -620,6 +646,7 @@ def load_aa_fex_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_aa_fex_intf1,
self.playbook_mock_succ_resp,
@@ -634,8 +661,10 @@ def load_aa_fex_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_aa_fex_intf1,
+ playbook_aa_fex_intf1,
]
if "_aa_fex_replaced_existing" in self._testMethodName:
@@ -645,6 +674,7 @@ def load_aa_fex_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_aa_fex_intf1,
playbook_have_all_data,
@@ -661,6 +691,7 @@ def load_aa_fex_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_aa_fex_intf1,
playbook_have_all_data,
@@ -691,6 +722,7 @@ def load_aa_fex_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_aa_fex_intf1,
playbook_have_all_data,
@@ -725,6 +757,7 @@ def load_st_fex_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_st_fex_intf1,
playbook_have_all_data,
@@ -740,6 +773,7 @@ def load_st_fex_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_st_fex_intf1,
playbook_have_all_data,
@@ -755,6 +789,7 @@ def load_st_fex_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_st_fex_intf1,
playbook_have_all_data,
@@ -772,6 +807,7 @@ def load_st_fex_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
self.playbook_mock_vpc_resp,
playbook_st_fex_intf1,
@@ -793,6 +829,7 @@ def load_st_fex_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_st_fex_intf1,
self.playbook_mock_succ_resp,
@@ -807,8 +844,10 @@ def load_st_fex_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_st_fex_intf1,
+ playbook_st_fex_intf1,
]
if "_st_fex_replaced_existing" in self._testMethodName:
playbook_st_fex_intf1 = self.payloads_data.get("st_fex_merged_payloads_150")
@@ -817,6 +856,7 @@ def load_st_fex_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_st_fex_intf1,
playbook_have_all_data,
@@ -833,6 +873,7 @@ def load_st_fex_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_st_fex_intf1,
playbook_have_all_data,
@@ -863,6 +904,7 @@ def load_st_fex_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_st_fex_intf1,
playbook_have_all_data,
@@ -900,6 +942,7 @@ def load_pc_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_pc_intf1,
playbook_pc_intf2,
@@ -930,6 +973,7 @@ def load_pc_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_pc_intf1,
playbook_have_all_data,
@@ -964,6 +1008,7 @@ def load_pc_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_pc_intf1,
playbook_pc_intf2,
@@ -1003,6 +1048,7 @@ def load_pc_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_pc_intf1,
playbook_pc_intf2,
@@ -1019,6 +1065,74 @@ def load_pc_fixtures(self):
self.playbook_mock_succ_resp,
]
+ if "_intf_deleted_existing_no_deploy" in self._testMethodName:
+ playbook_pc_intf1 = self.payloads_data.get(
+ "pc_merged_trunk_payloads"
+ )
+ playbook_have_all_data = self.have_all_payloads_data.get(
+ "payloads"
+ )
+
+ self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
+ self.playbook_mock_vpc_resp,
+ playbook_pc_intf1,
+ self.playbook_mock_succ_resp,
+ self.playbook_mock_succ_resp,
+ self.playbook_mock_succ_resp,
+ self.playbook_mock_succ_resp,
+ self.playbook_mock_succ_resp,
+ self.playbook_mock_succ_resp,
+ self.playbook_mock_succ_resp,
+ self.playbook_mock_succ_resp,
+ self.playbook_mock_succ_resp,
+ ]
+
+ if "_intf_deleted_deploy" in self._testMethodName:
+ playbook_pc_intf1 = []
+ playbook_have_all_data = self.have_all_payloads_data.get(
+ "deleted_intf_payloads"
+ )
+
+ self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
+ self.playbook_mock_vpc_resp,
+ playbook_pc_intf1,
+ playbook_have_all_data,
+ self.playbook_mock_succ_resp,
+ self.playbook_mock_succ_resp,
+ self.playbook_mock_succ_resp,
+ self.playbook_mock_succ_resp,
+ self.playbook_mock_succ_resp,
+ self.playbook_mock_succ_resp,
+ self.playbook_mock_succ_resp,
+ self.playbook_mock_succ_resp,
+ self.playbook_mock_succ_resp,
+ ]
+
+ if "_intf_deleted_existing_no_deploy" in self._testMethodName:
+ playbook_pc_intf1 = self.payloads_data.get(
+ "pc_merged_trunk_payloads"
+ )
+ playbook_have_all_data = self.have_all_payloads_data.get(
+ "payloads"
+ )
+
+ self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
+ self.playbook_mock_vpc_resp,
+ playbook_pc_intf1,
+ self.playbook_mock_succ_resp,
+ self.playbook_mock_succ_resp,
+ self.playbook_mock_succ_resp,
+ self.playbook_mock_succ_resp,
+ self.playbook_mock_succ_resp,
+ self.playbook_mock_succ_resp,
+ self.playbook_mock_succ_resp,
+ self.playbook_mock_succ_resp,
+ self.playbook_mock_succ_resp,
+ ]
+
if "_pc_replaced_existing" in self._testMethodName:
playbook_pc_intf1 = self.payloads_data.get(
"pc_merged_trunk_payloads"
@@ -1035,6 +1149,7 @@ def load_pc_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_pc_intf1,
playbook_pc_intf2,
@@ -1066,6 +1181,7 @@ def load_pc_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_pc_intf1,
playbook_have_all_data,
@@ -1107,6 +1223,7 @@ def load_eth_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_eth_intf1,
playbook_eth_intf2,
@@ -1141,6 +1258,7 @@ def load_eth_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_eth_intf1,
playbook_have_all_data,
@@ -1182,6 +1300,7 @@ def load_eth_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_eth_intf1,
playbook_eth_intf2,
@@ -1231,6 +1350,7 @@ def load_eth_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_eth_intf1,
playbook_eth_intf2,
@@ -1277,6 +1397,7 @@ def load_eth_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_have_all_data,
playbook_eth_intf1,
@@ -1313,6 +1434,7 @@ def load_eth_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_eth_intf1,
playbook_have_all_data,
@@ -1352,6 +1474,7 @@ def load_subint_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_sub_intf1,
playbook_sub_intf2,
@@ -1383,6 +1506,7 @@ def load_subint_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_subint_intf1,
playbook_subint_intf2,
@@ -1407,6 +1531,7 @@ def load_subint_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_subint_intf1,
playbook_subint_intf2,
@@ -1437,6 +1562,7 @@ def load_subint_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_subint_intf1,
playbook_have_all_data,
@@ -1466,6 +1592,7 @@ def load_subint_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_subint_intf1,
playbook_subint_intf2,
@@ -1487,6 +1614,7 @@ def load_subint_fixtures(self):
"payloads"
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
[],
self.playbook_mock_succ_resp,
@@ -1514,6 +1642,7 @@ def load_subint_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_subint_intf1,
playbook_have_all_data,
@@ -1550,6 +1679,7 @@ def load_lo_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_lo_intf1,
playbook_lo_intf2,
@@ -1577,6 +1707,7 @@ def load_lo_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_lo_intf1,
playbook_lo_intf2,
@@ -1605,6 +1736,7 @@ def load_lo_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_lo_intf1,
playbook_have_all_data,
@@ -1633,6 +1765,7 @@ def load_lo_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_lo_intf1,
playbook_lo_intf2,
@@ -1659,6 +1792,7 @@ def load_lo_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_lo_intf1,
playbook_lo_intf2,
@@ -1688,6 +1822,7 @@ def load_lo_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_lo_intf1,
playbook_lo_intf2,
@@ -1720,6 +1855,7 @@ def load_lo_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_lo_intf1,
playbook_have_all_data,
@@ -1748,6 +1884,7 @@ def load_lo_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
playbook_lo_intf1,
playbook_have_all_data,
@@ -1783,6 +1920,7 @@ def load_vpc_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
self.playbook_mock_vpc_resp,
playbook_vpc_intf1,
@@ -1816,6 +1954,7 @@ def load_vpc_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
self.playbook_mock_vpc_resp,
playbook_vpc_intf1,
@@ -1849,6 +1988,7 @@ def load_vpc_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
self.playbook_mock_vpc_resp,
playbook_vpc_intf1,
@@ -1879,6 +2019,7 @@ def load_vpc_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
self.playbook_mock_vpc_resp,
playbook_vpc_intf1,
@@ -1913,6 +2054,7 @@ def load_vpc_fixtures(self):
)
self.run_dcnm_send.side_effect = [
+ self.mock_monitor_false_resp,
self.playbook_mock_vpc_resp,
self.playbook_mock_vpc_resp,
playbook_vpc_intf1,
@@ -1987,6 +2129,7 @@ def load_fixtures(self, response=None, device=""):
self.load_missing_state_fixtures()
self.load_missing_members_fixtures()
self.load_query_state_fixtures()
+ self.load_intf_misc_fixtures()
# -------------------------- GEN-INTF --------------------------
@@ -2005,6 +2148,8 @@ def test_dcnm_intf_multi_intf_merged_new(self):
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
set_module_args(
dict(
@@ -2049,6 +2194,8 @@ def test_dcnm_intf_multi_intf_merged_exist(self):
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
set_module_args(
dict(
@@ -2102,6 +2249,8 @@ def test_dcnm_intf_missing_intf_elems_merged_new(self):
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -2145,6 +2294,8 @@ def test_dcnm_intf_check_multi_intf_merged_new(self):
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
set_module_args(
dict(
@@ -2190,6 +2341,8 @@ def test_dcnm_intf_pc_merged_new(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -2233,6 +2386,8 @@ def test_dcnm_intf_pc_merged_idempotent(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -2261,6 +2416,8 @@ def test_dcnm_intf_pc_merged_policy_change(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -2287,6 +2444,8 @@ def test_dcnm_intf_pc_deleted_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -2313,6 +2472,76 @@ def test_dcnm_intf_pc_deleted_existing(self):
True,
)
+ def test_dcnm_intf_deleted_existing_no_deploy(self):
+
+ # load the json from playbooks
+ self.config_data = loadPlaybookData("dcnm_intf_pc_configs")
+ self.payloads_data = loadPlaybookData("dcnm_intf_pc_payloads")
+ self.have_all_payloads_data = loadPlaybookData(
+ "dcnm_intf_have_all_payloads"
+ )
+
+ # load required config data
+ self.playbook_config = self.config_data.get("pc_deleted_config_no_deploy")
+ self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
+ self.mock_ip_sn = self.config_data.get("mock_ip_sn")
+ self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
+ self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
+
+ set_module_args(
+ dict(
+ state="deleted",
+ fabric="test_fabric",
+ config=self.playbook_config,
+ )
+ )
+ result = self.execute_module(changed=True, failed=False)
+
+ self.assertEqual(len(result["diff"][0]["deleted"]), 1)
+ for intf in result["diff"][0]["deleted"]:
+ self.assertEqual(
+ (
+ intf["ifName"]
+ in [
+ "Port-channel300",
+ ]
+ ),
+ True,
+ )
+ self.assertEqual(len(result["diff"][0]["delete_deploy"]), 0)
+
+ def test_dcnm_intf_deleted_deploy(self):
+
+ # load the json from playbooks
+ self.config_data = loadPlaybookData("dcnm_intf_pc_configs")
+ self.payloads_data = loadPlaybookData("dcnm_intf_pc_payloads")
+ self.have_all_payloads_data = loadPlaybookData(
+ "dcnm_intf_have_all_payloads"
+ )
+
+ # load required config data
+ self.playbook_config = self.config_data.get("pc_deleted_config_deploy")
+ self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
+ self.mock_ip_sn = self.config_data.get("mock_ip_sn")
+ self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
+ self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
+
+ set_module_args(
+ dict(
+ state="deleted",
+ fabric="test_fabric",
+ config=self.playbook_config,
+ )
+ )
+ result = self.execute_module(changed=True, failed=False)
+
+ self.assertEqual(len(result["diff"][0]["deleted"]), 0)
+ self.assertEqual(len(result["diff"][0]["delete_deploy"]), 1)
+
def test_dcnm_intf_pc_replaced_existing(self):
# load the json from playbooks
@@ -2327,6 +2556,8 @@ def test_dcnm_intf_pc_replaced_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -2380,6 +2611,8 @@ def test_dcnm_intf_pc_overridden_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -2444,6 +2677,8 @@ def test_dcnm_intf_eth_merged_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -2473,6 +2708,8 @@ def test_dcnm_intf_eth_merged_new(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -2514,6 +2751,8 @@ def test_dcnm_intf_eth_merged_idempotent(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
for cfg in self.playbook_config:
@@ -2543,6 +2782,8 @@ def test_dcnm_intf_eth_replaced_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -2598,6 +2839,8 @@ def test_dcnm_intf_eth_deleted_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -2627,6 +2870,8 @@ def test_dcnm_intf_eth_overridden_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -2685,6 +2930,8 @@ def test_dcnm_intf_subint_merged_new(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -2717,6 +2964,8 @@ def test_dcnm_intf_subint_merged_idempotent(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
for cfg in self.playbook_config:
@@ -2746,6 +2995,8 @@ def test_dcnm_intf_subint_replaced_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -2798,6 +3049,8 @@ def test_dcnm_intf_subint_replaced_non_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -2826,6 +3079,8 @@ def test_dcnm_intf_subint_deleted_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -2859,6 +3114,8 @@ def test_dcnm_intf_subint_deleted_non_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -2886,6 +3143,8 @@ def test_dcnm_intf_subint_overridden_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -2944,6 +3203,8 @@ def test_dcnm_intf_lo_merged_new(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -2977,6 +3238,8 @@ def test_dcnm_intf_lo_merged_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -3006,6 +3269,8 @@ def test_dcnm_intf_lo_merged_idempotent(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
for cfg in self.playbook_config:
@@ -3035,6 +3300,8 @@ def test_dcnm_intf_lo_replaced_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -3082,6 +3349,8 @@ def test_dcnm_intf_lo_deleted_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -3113,6 +3382,8 @@ def test_dcnm_intf_lo_overridden_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -3171,6 +3442,8 @@ def test_dcnm_intf_lo_overridden_existing_2(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -3228,6 +3501,8 @@ def test_dcnm_intf_lo_overridden_non_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -3287,6 +3562,8 @@ def test_dcnm_intf_vpc_merged_new(self):
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -3319,6 +3596,8 @@ def test_dcnm_intf_vpc_merged_idempotent(self):
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
for cfg in self.playbook_config:
@@ -3326,6 +3605,8 @@ def test_dcnm_intf_vpc_merged_idempotent(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
set_module_args(
dict(
@@ -3352,6 +3633,8 @@ def test_dcnm_intf_vpc_deleted_existing(self):
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -3382,6 +3665,8 @@ def test_dcnm_intf_vpc_replaced_existing(self):
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -3441,6 +3726,8 @@ def test_dcnm_intf_vpc_overridden_existing(self):
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -3504,6 +3791,8 @@ def test_dcnm_intf_svi_merged_new(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -3536,6 +3825,8 @@ def test_dcnm_intf_svi_merged_idempotent(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -3564,6 +3855,8 @@ def test_dcnm_intf_svi_deleted_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -3595,6 +3888,8 @@ def test_dcnm_intf_svi_deleted_non_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -3624,6 +3919,8 @@ def test_dcnm_intf_svi_replaced_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -3695,6 +3992,8 @@ def test_dcnm_intf_svi_overridden_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -3758,6 +4057,8 @@ def test_dcnm_intf_aa_fex_merged_new(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -3790,6 +4091,8 @@ def test_dcnm_intf_aa_fex_merged_idempotent(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -3816,6 +4119,8 @@ def test_dcnm_intf_aa_fex_merged_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -3846,6 +4151,8 @@ def test_dcnm_intf_aa_fex_merged_multi_switches(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -3878,6 +4185,8 @@ def test_dcnm_intf_aa_fex_deleted_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -3909,6 +4218,8 @@ def test_dcnm_intf_aa_fex_deleted_non_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -3936,6 +4247,8 @@ def test_dcnm_intf_aa_fex_replaced_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -3989,6 +4302,8 @@ def test_dcnm_intf_aa_fex_overridden_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -4051,6 +4366,8 @@ def test_dcnm_intf_aa_fex_overridden_modify_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -4115,6 +4432,8 @@ def test_dcnm_intf_st_fex_merged_new(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -4147,6 +4466,8 @@ def test_dcnm_intf_st_fex_merged_idempotent(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -4173,6 +4494,8 @@ def test_dcnm_intf_st_fex_merged_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -4203,6 +4526,8 @@ def test_dcnm_intf_st_fex_merged_multi_switches(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -4235,6 +4560,8 @@ def test_dcnm_intf_st_fex_deleted_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -4266,6 +4593,8 @@ def test_dcnm_intf_st_fex_deleted_non_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -4293,6 +4622,8 @@ def test_dcnm_intf_st_fex_replaced_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -4344,6 +4675,8 @@ def test_dcnm_intf_st_fex_overridden_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -4406,6 +4739,8 @@ def test_dcnm_intf_st_fex_overridden_modify_existing(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -4470,6 +4805,8 @@ def test_dcnm_intf_gen_missing_ip_sn(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = []
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
dict(
@@ -4500,6 +4837,8 @@ def test_dcnm_intf_mixed_intf_merged_new(self):
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
set_module_args(
dict(
@@ -4531,6 +4870,8 @@ def test_dcnm_intf_bunched_intf_merged_new(self):
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
set_module_args(
dict(
@@ -4579,6 +4920,8 @@ def test_dcnm_intf_type_missing_merged_new(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -4609,6 +4952,8 @@ def test_dcnm_intf_missing_state(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -4642,6 +4987,8 @@ def test_dcnm_intf_missing_peer_members(self):
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
set_module_args(
dict(
@@ -4677,6 +5024,8 @@ def test_dcnm_intf_query(self):
self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
self.mock_ip_sn = self.config_data.get("mock_ip_sn")
self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
set_module_args(
@@ -4695,3 +5044,73 @@ def test_dcnm_intf_query(self):
self.assertEqual(len(result["diff"][0]["replaced"]), 0)
self.assertEqual(len(result["diff"][0]["deploy"]), 0)
self.assertEqual(len(result["diff"][0]["query"]), 8)
+
+ def test_dcnm_intf_merge_fabric_monitoring(self):
+
+ # load the json from playbooks
+ self.config_data = loadPlaybookData("dcnm_intf_pc_configs")
+ self.payloads_data = loadPlaybookData("dcnm_intf_pc_payloads")
+ self.have_all_payloads_data = loadPlaybookData(
+ "dcnm_intf_have_all_payloads"
+ )
+
+ # load required config data
+ self.playbook_config = self.config_data.get("pc_merged_config")
+ self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
+ self.mock_ip_sn = self.config_data.get("mock_ip_sn")
+ self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
+ self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
+
+ set_module_args(
+ dict(
+ state="merged",
+ fabric="fabric_monitoring",
+ config=self.playbook_config,
+ )
+ )
+
+ result = None
+
+ try:
+ result = self.execute_module(changed=False, failed=False)
+ except Exception as e:
+ self.assertEqual(result, None)
+ self.assertEqual(("is in Monitoring mode" in str(e)), True)
+ self.assertEqual(("No changes are allowed on the fabric" in str(e)), True)
+
+ def test_dcnm_intf_merge_unmanagable_switch(self):
+
+ # load the json from playbooks
+ self.config_data = loadPlaybookData("dcnm_intf_pc_configs")
+ self.payloads_data = loadPlaybookData("dcnm_intf_pc_payloads")
+ self.have_all_payloads_data = loadPlaybookData(
+ "dcnm_intf_have_all_payloads"
+ )
+
+ # load required config data
+ self.playbook_config = self.config_data.get("pc_unmanagable_merged_config")
+ self.playbook_mock_succ_resp = self.config_data.get("mock_succ_resp")
+ self.mock_ip_sn = self.config_data.get("mock_ip_sn")
+ self.mock_fab_inv = self.config_data.get("mock_fab_inv_data")
+ self.mock_monitor_true_resp = self.config_data.get("mock_monitor_true_resp")
+ self.mock_monitor_false_resp = self.config_data.get("mock_monitor_false_resp")
+ self.playbook_mock_vpc_resp = self.config_data.get("mock_vpc_resp")
+
+ set_module_args(
+ dict(
+ state="merged",
+ fabric="test_fabric",
+ config=self.playbook_config,
+ )
+ )
+
+ result = None
+
+ try:
+ result = self.execute_module(changed=False, failed=False)
+ except Exception as e:
+ self.assertEqual(result, None)
+ self.assertEqual(("are not managable in Fabric" in str(e)), True)
+ self.assertEqual(("No changes are allowed on these switches" in str(e)), True)
diff --git a/tests/unit/modules/dcnm/test_dcnm_inventory.py b/tests/unit/modules/dcnm/test_dcnm_inventory.py
index 917dbad64..0b7a9357c 100644
--- a/tests/unit/modules/dcnm/test_dcnm_inventory.py
+++ b/tests/unit/modules/dcnm/test_dcnm_inventory.py
@@ -84,6 +84,10 @@ class TestDcnmInvModule(TestDcnmModule):
playbook_rma_switch_noserial_config = test_data.get("playbook_rma_switch_noserial_config")
playbook_rma_switch_nooldserial_config = test_data.get("playbook_rma_switch_nooldserial_config")
playbook_rma_switch_config = test_data.get("playbook_rma_switch_config")
+ playbook_poap_missing_credentials_password = test_data.get("playbook_poap_missing_credentials_password")
+ playbook_poap_missing_credentials_username = test_data.get("playbook_poap_missing_credentials_username")
+ playbook_rma_missing_credentials_password = test_data.get("playbook_rma_missing_credentials_password")
+ playbook_rma_missing_credentials_username = test_data.get("playbook_rma_missing_credentials_username")
rma_inv_data = test_data.get("rma_inv_data")
# initial merge switch success
@@ -806,6 +810,9 @@ def load_fixtures(self, response=None, device=""):
elif "poap_overridden_switch" in self._testMethodName:
self.init_data()
+ elif "poap_missing_credentials" in self._testMethodName:
+ self.init_data()
+
elif "poap_idempotent_switch" in self._testMethodName:
self.init_data()
self.run_dcnm_send.side_effect = [
@@ -1298,7 +1305,6 @@ def test_dcnm_inv_poap_switch_fabric(self):
config=self.playbook_poap_switch_config,
)
)
-
result = self.execute_module(changed=True, failed=False)
for resp in result["response"]:
@@ -1660,3 +1666,67 @@ def test_dcnm_inv_rma_switch_fabric(self):
for resp in result["response"]:
self.assertEqual(resp["RETURN_CODE"], 200)
self.assertEqual(resp["MESSAGE"], "OK")
+
+ def test_dcnm_inv_poap_missing_credentials_password(self):
+ set_module_args(
+ dict(
+ state="merged",
+ fabric="kharicha-fabric",
+ config=self.playbook_poap_missing_credentials_password,
+ )
+ )
+
+ result = self.execute_module(changed=False, failed=True)
+
+ self.assertEqual(
+ result.get("msg"),
+ "discovery_password must be set when discovery_username is specified",
+ )
+
+ def test_dcnm_inv_poap_missing_credentials_username(self):
+ set_module_args(
+ dict(
+ state="merged",
+ fabric="kharicha-fabric",
+ config=self.playbook_poap_missing_credentials_username,
+ )
+ )
+
+ result = self.execute_module(changed=False, failed=True)
+
+ self.assertEqual(
+ result.get("msg"),
+ "discovery_username must be set when discovery_password is specified",
+ )
+
+ def test_dcnm_inv_rma_missing_credentials_password(self):
+ set_module_args(
+ dict(
+ state="merged",
+ fabric="kharicha-fabric",
+ config=self.playbook_rma_missing_credentials_password,
+ )
+ )
+
+ result = self.execute_module(changed=False, failed=True)
+
+ self.assertEqual(
+ result.get("msg"),
+ "discovery_password must be set when discovery_username is specified",
+ )
+
+ def test_dcnm_inv_rma_missing_credentials_username(self):
+ set_module_args(
+ dict(
+ state="merged",
+ fabric="kharicha-fabric",
+ config=self.playbook_rma_missing_credentials_username,
+ )
+ )
+
+ result = self.execute_module(changed=False, failed=True)
+
+ self.assertEqual(
+ result.get("msg"),
+ "discovery_username must be set when discovery_password is specified",
+ )
|