Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -256,7 +256,7 @@ ansible_connection: ansible.netcommon.httpapi
ansible_httpapi_port: 443
ansible_httpapi_use_ssl: true
ansible_httpapi_validate_certs: false
ansible_network_os: cisco.dcnm.dcnm
ansible_network_os: cisco.nd.nd #Change as per ansible_network_os
# NDFC API Credentials
ansible_user: "{{ lookup('env', 'ND_USERNAME') }}"
ansible_password: "{{ lookup('env', 'ND_PASSWORD') }}"
Expand Down
10 changes: 9 additions & 1 deletion plugins/action/dtc/fabric_check_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

from ansible.utils.display import Display
from ansible.plugins.action import ActionBase
from .rest_module_utils import get_rest_module


display = Display()
Expand All @@ -40,8 +41,15 @@ def run(self, tmp=None, task_vars=None):

fabric = self._task.args["fabric"]

network_os = task_vars['ansible_network_os']
rest_module = get_rest_module(network_os)
if not rest_module:
results['failed'] = True
results['msg'] = f"Unsupported network_os: {network_os}"
return results

ndfc_response = self._execute_module(
module_name="cisco.dcnm.dcnm_rest",
module_name=rest_module,
module_args={
"method": "GET",
"path": f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{fabric}/inventory/switchesByFabric",
Expand Down
9 changes: 8 additions & 1 deletion plugins/action/dtc/fabrics_config_save.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

from ansible.utils.display import Display
from ansible.plugins.action import ActionBase
from .rest_module_utils import get_rest_module


display = Display()
Expand All @@ -42,8 +43,14 @@ def run(self, tmp=None, task_vars=None):

for fabric in fabrics:
display.display(f"Executing config-save on Fabric: {fabric}")
network_os = task_vars['ansible_network_os']
rest_module = get_rest_module(network_os)
if not rest_module:
results['failed'] = True
results['msg'] = f"Unsupported network_os: {network_os}"
return results
ndfc_config_save = self._execute_module(
module_name="cisco.dcnm.dcnm_rest",
module_name=rest_module,
module_args={
"method": "POST",
"path": f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{fabric}/config-save",
Expand Down
11 changes: 9 additions & 2 deletions plugins/action/dtc/fabrics_deploy.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

from ansible.utils.display import Display
from ansible.plugins.action import ActionBase
from .rest_module_utils import get_rest_module


display = Display()
Expand All @@ -39,11 +40,17 @@ def run(self, tmp=None, task_vars=None):
results['failed'] = False

fabrics = self._task.args["fabrics"]

for fabric in fabrics:
display.display(f"Executing config-deploy on Fabric: {fabric}")
network_os = task_vars['ansible_network_os']
rest_module = get_rest_module(network_os)
if not rest_module:
results['failed'] = True
results['msg'] = f"Unsupported network_os: {network_os}"
return results

ndfc_deploy = self._execute_module(
module_name="cisco.dcnm.dcnm_rest",
module_name=rest_module,
module_args={
"method": "POST",
"path": f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/{fabric}/config-deploy?forceShowRun=false",
Expand Down
9 changes: 8 additions & 1 deletion plugins/action/dtc/get_poap_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
__metaclass__ = type

from ansible.plugins.action import ActionBase
from .rest_module_utils import get_rest_module
import json
import re
import inspect
Expand Down Expand Up @@ -148,8 +149,14 @@ def refresh(self) -> None:
self.refresh_succeeded = False
self.refresh_message = None

from .rest_module_utils import get_rest_module
network_os = self.task_vars['ansible_network_os']
rest_module = get_rest_module(network_os)
if not rest_module:
self.refresh_message = f"Unsupported network_os: {network_os}"
return
data = self.execute_module(
module_name="cisco.dcnm.dcnm_rest",
module_name=rest_module,
module_args={
"method": self.poap_get_method,
"path": self.poap_get_path
Expand Down
12 changes: 10 additions & 2 deletions plugins/action/dtc/manage_child_fabric_networks.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from ansible.plugins.action import ActionBase
from ansible.template import Templar
from ansible.errors import AnsibleFileNotFound
from .rest_module_utils import get_rest_module


import json
Expand All @@ -53,6 +54,13 @@ def run(self, tmp=None, task_vars=None):

child_fabrics = msite_data['child_fabrics_data']

network_os = task_vars['ansible_network_os']
rest_module = get_rest_module(network_os)
if not rest_module:
results['failed'] = True
results['msg'] = f"Unsupported network_os: {network_os}"
return results

for network in networks:
network_attach_group_switches = [
network_attach_groups_dict['switches']
Expand Down Expand Up @@ -130,7 +138,7 @@ def run(self, tmp=None, task_vars=None):
# return results

ndfc_net = self._execute_module(
module_name="cisco.dcnm.dcnm_rest",
module_name=rest_module,
module_args={
"method": "GET",
"path": f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/networks/{network['name']}",
Expand Down Expand Up @@ -184,7 +192,7 @@ def run(self, tmp=None, task_vars=None):
rendered_to_nice_json = templar.environment.filters['to_nice_json'](rendered_content)

ndfc_net_update = self._execute_module(
module_name="cisco.dcnm.dcnm_rest",
module_name=rest_module,
module_args={
"method": "PUT",
"path": f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/networks/{network['name']}",
Expand Down
13 changes: 11 additions & 2 deletions plugins/action/dtc/manage_child_fabric_vrfs.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
from ansible.plugins.action import ActionBase
from ansible.template import Templar
from ansible.errors import AnsibleFileNotFound
from .rest_module_utils import get_rest_module


import json
Expand All @@ -53,6 +54,14 @@ def run(self, tmp=None, task_vars=None):

child_fabrics = msite_data['child_fabrics_data']


network_os = task_vars['ansible_network_os']
rest_module = get_rest_module(network_os)
if not rest_module:
results['failed'] = True
results['msg'] = f"Unsupported network_os: {network_os}"
return results

for vrf in vrfs:
vrf_attach_group_switches = [
vrf_attach_group_dict['switches']
Expand Down Expand Up @@ -130,7 +139,7 @@ def run(self, tmp=None, task_vars=None):
# return results

ndfc_vrf = self._execute_module(
module_name="cisco.dcnm.dcnm_rest",
module_name=rest_module,
module_args={
"method": "GET",
"path": f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/vrfs/{vrf['name']}"
Expand Down Expand Up @@ -195,7 +204,7 @@ def run(self, tmp=None, task_vars=None):
rendered_to_nice_json = templar.environment.filters['to_nice_json'](rendered_content)

ndfc_vrf_update = self._execute_module(
module_name="cisco.dcnm.dcnm_rest",
module_name=rest_module,
module_args={
"method": "PUT",
"path": f"/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/top-down/fabrics/{child_fabric}/vrfs/{vrf['name']}",
Expand Down
12 changes: 10 additions & 2 deletions plugins/action/dtc/manage_child_fabrics.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

from ansible.utils.display import Display
from ansible.plugins.action import ActionBase
from .rest_module_utils import get_rest_module

display = Display()

Expand All @@ -42,11 +43,18 @@ def run(self, tmp=None, task_vars=None):
child_fabrics = self._task.args['child_fabrics']
state = self._task.args['state']

network_os = task_vars['ansible_network_os']
rest_module = get_rest_module(network_os)
if not rest_module:
results['failed'] = True
results['msg'] = f"Unsupported network_os: {network_os}"
return results

if state == 'present':
for fabric in child_fabrics:
json_data = '{"destFabric":"%s","sourceFabric":"%s"}' % (parent_fabric, fabric)
add_fabric_result = self._execute_module(
module_name="cisco.dcnm.dcnm_rest",
module_name=rest_module,
module_args={
"method": "POST",
"path": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msdAdd",
Expand Down Expand Up @@ -75,7 +83,7 @@ def run(self, tmp=None, task_vars=None):
for fabric in child_fabrics:
json_data = '{"destFabric":"%s","sourceFabric":"%s"}' % (parent_fabric, fabric)
remove_fabric_result = self._execute_module(
module_name="cisco.dcnm.dcnm_rest",
module_name=rest_module,
module_args={
"method": "POST",
"path": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msdExit",
Expand Down
10 changes: 9 additions & 1 deletion plugins/action/dtc/prepare_msite_child_fabrics_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

from ansible.utils.display import Display
from ansible.plugins.action import ActionBase
from .rest_module_utils import get_rest_module

display = Display()

Expand All @@ -42,10 +43,17 @@ def run(self, tmp=None, task_vars=None):
parent_fabric = self._task.args["parent_fabric"]
child_fabrics = self._task.args["child_fabrics"]

network_os = task_vars['ansible_network_os']
rest_module = get_rest_module(network_os)
if not rest_module:
results['failed'] = True
results['msg'] = f"Unsupported network_os: {network_os}"
return results

# This is actaully not an accurrate API endpoint as it returns all fabrics in NDFC, not just the fabrics associated with MSD
# Therefore, we need to get the fabric associations response and filter out the fabrics that are not associated with the parent fabric (MSD)
msd_fabric_associations = self._execute_module(
module_name="cisco.dcnm.dcnm_rest",
module_name=rest_module,
module_args={
"method": "GET",
"path": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msd/fabric-associations",
Expand Down
7 changes: 4 additions & 3 deletions plugins/action/dtc/prepare_msite_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@

from ansible.utils.display import Display
from ansible.plugins.action import ActionBase
from ...plugin_utils.helper_functions import ndfc_get_fabric_attributes
from ...plugin_utils.helper_functions import ndfc_get_fabric_switches
from .rest_module_utils import get_rest_module
from ...plugin_utils/helper_functions import ndfc_get_fabric_attributes
from ...plugin_utils/helper_functions import ndfc_get_fabric_switches
import re

display = Display()
Expand All @@ -47,7 +48,7 @@ def run(self, tmp=None, task_vars=None):
# This is actaully not an accurrate API endpoint as it returns all fabrics in NDFC, not just the fabrics associated with MSD
# Therefore, we need to get the fabric associations response and filter out the fabrics that are not associated with the parent fabric (MSD)
msd_fabric_associations = self._execute_module(
module_name="cisco.dcnm.dcnm_rest",
module_name=task_vars['ansible_network_os_rest'],
module_args={
"method": "GET",
"path": "/appcenter/cisco/ndfc/api/v1/lan-fabric/rest/control/fabrics/msd/fabric-associations",
Expand Down
108 changes: 108 additions & 0 deletions plugins/action/dtc/rest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

# Copyright (c) 2024 Cisco Systems, Inc. and its affiliates
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of
# this software and associated documentation files (the "Software"), to deal in
# the Software without restriction, including without limitation the rights to
# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
# the Software, and to permit persons to whom the Software is furnished to do so,
# subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
# SPDX-License-Identifier: MIT

from __future__ import absolute_import, division, print_function

__metaclass__ = type

from ansible.utils.display import Display
from ansible.plugins.action import ActionBase
from .rest_module_utils import get_rest_module

display = Display()


class ActionModule(ActionBase):
"""
Action plugin to dynamically select between cisco.nd.nd_rest and cisco.dcnm.dcnm_rest
based on the ansible_network_os variable.
"""

def run(self, tmp=None, task_vars=None):
"""
Execute the action plugin.

Args:
tmp (str, optional): Temporary directory. Defaults to None.
task_vars (dict, optional): Dictionary of task variables. Defaults to None.

Returns:
dict: Results of the REST API call
"""
# Initialize results dictionary
results = super(ActionModule, self).run(tmp, task_vars)
results['changed'] = False
results['failed'] = False

# Get task arguments
module_args = self._task.args.copy()

# Get the network OS from task variables or module arguments
network_os = task_vars.get('ansible_network_os')
display.vvvv(f"Using OS module: {network_os}")

# Determine which module to use based on network_os
rest_module = get_rest_module(network_os)
if not rest_module:
results['failed'] = True
results['msg'] = f"Unsupported network_os: {network_os}"
return results

display.vvvv(f"Using ----------REST------------- module: {rest_module}")

try:
display.vvvv(f"Executing module: {rest_module} with args: {module_args}")

self._task.vars['ansible_rest_os_module'] = rest_module

# Set the connection to httpapi
if 'connection' not in task_vars:
task_vars['connection'] = 'httpapi'

# Execute the appropriate REST module
result = self._execute_module(
module_name=rest_module,
module_args=module_args,
task_vars=task_vars,
tmp=tmp,
wrap_async=False
)

# Update results with the module's results
if result.get('failed'):
results.update(result)
display.error(f"Module execution failed: {result.get('msg')}")
else:
results['changed'] = result.get('changed', False)
results.update(result)
display.vvvv(f"Module execution successful: {result}")

except Exception as e:
import traceback
error_trace = traceback.format_exc()
results['failed'] = True
results['msg'] = f"Failed to execute {rest_module}: {str(e)}\n{error_trace}"
display.error(results['msg'], wrap_text=False)

return results
9 changes: 9 additions & 0 deletions plugins/action/dtc/rest_module_utils.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Utility to select the correct REST module based on network_os

def get_rest_module(network_os):
if network_os == 'cisco.dcnm.dcnm':
return 'cisco.dcnm.dcnm_rest'
elif network_os == 'cisco.nd.nd':
return 'cisco.nd.nd_rest'
else:
return None
Loading