Skip to content

Commit

Permalink
Initial Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
mikewiebe committed Mar 26, 2024
0 parents commit fab43c5
Show file tree
Hide file tree
Showing 105 changed files with 2,668 additions and 0 deletions.
140 changes: 140 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
pip-wheel-metadata/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
.python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# PEP 582; used by e.g. github.com/David-OConnor/pyflow
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# VSCode
.vscode/

# Ignore Roles Files Directories
roles/prepare_model/files
roles/dtc/common/files/*
roles/dtc/create/files
roles/dtc/deploy/files
roles/dtc/remove/files
roles/validate/files/*
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Ansible Solution Collection: netascode_dc_vxlan
Ansible collection for configuring a VXLAN Fabric using Direct to Controller (DTC) or Direct To Device (DTD) workflows.
1 change: 1 addition & 0 deletions docs/about.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Documentation for the netascode-dc-vxlan collection
19 changes: 19 additions & 0 deletions galaxy.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
namespace: cisco
name: nac_dc_vxlan
version: 0.1.0
readme: README.md
authors:
- Matt Tarkington <mtarking>
- Mike Wiebe <mikewiebe>
- Rafael Muller <rmuller>
- Shangxin Du <shdu>
description: Ansible solution collection for VXLAN
license_file: LICENSE
tags: [cisco, ndfc, dcnm, nxos, dnac, networking, vxlan]
dependencies:
"ansible.netcommon": ">=4.1.0"
"cisco.ios": ">=4.3.0"
"cisco.nxos": ">=4.0.1"
"cisco.dcnm": ">=2.4.0"
repository: https://github.com/netascode/ansible-dc-vxlan
Empty file added images/.gitkeep
Empty file.
31 changes: 31 additions & 0 deletions plugins/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# Collections Plugins Directory

This directory can be used to ship various plugins inside an Ansible collection. Each plugin is placed in a folder that
is named after the type of plugin it is in. It can also include the `module_utils` and `modules` directory that
would contain module utils and modules respectively.

Here is an example directory of the majority of plugins currently supported by Ansible:

```
└── plugins
├── action
├── become
├── cache
├── callback
├── cliconf
├── connection
├── filter
├── httpapi
├── inventory
├── lookup
├── module_utils
├── modules
├── netconf
├── shell
├── strategy
├── terminal
├── test
└── vars
```

A full list of plugin types can be found at [Working With Plugins](https://docs.ansible.com/ansible-core/2.13/plugins/plugins.html).
69 changes: 69 additions & 0 deletions plugins/action/common/nac_dc_validate.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
from __future__ import absolute_import, division, print_function


__metaclass__ = type

from ansible import constants as C
from ansible.utils.display import Display
from ansible.plugins.action import ActionBase

from ..helper_functions import do_something

import iac_validate.validator
from iac_validate.yaml import load_yaml_files
import os

display = Display()

class ActionModule(ActionBase):

def run(self, tmp=None, task_vars=None):
results = super(ActionModule, self).run(tmp, task_vars)
results['failed'] = False
results['msg'] = None
results['data'] = {}

schema = self._task.args.get('schema')
rules = self._task.args.get('rules')
mdata = self._task.args.get('mdata')

# Generate a warning if the Schema and Rules are not provided
if schema and not os.path.exists(schema):
display.warning("The provided schema ({0}) does not appear to exist! ".format(schema))
# The rules directory is considered empty if it only contains the .gitkeep file
if len(os.listdir(rules)) == 1 and '.gitkeep' in os.listdir(rules):
display.warning("The rules directory ({0}) is empty! ".format(rules))

# Verify That Data Sources Exists
if mdata and not os.path.exists(mdata):
results['failed'] = True
results['msg'] = "The data directory ({0}) for this fabric does not appear to exist!".format(mdata)
return results
if len(os.listdir(mdata)) == 0:
results['failed'] = True
results['msg'] = "The data directory ({0}) for this fabric is empty!".format(mdata)
return results

if schema is None:
schema = ""
if rules is None:
rules = ""

validator = iac_validate.validator.Validator(schema, rules)
if schema:
validator.validate_syntax([mdata])
if rules:
validator.validate_semantics([mdata])

msg = ""
for error in validator.errors:
msg += error + "\n"

if msg:
results['failed'] = True
results['msg'] = msg

# Return Schema Validated Model Data
results['data'] = load_yaml_files([mdata])

return results
9 changes: 9 additions & 0 deletions plugins/action/common/prepare_plugins/101_prep_global.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class PreparePlugin:
def __init__(self, **kwargs):
self.kwargs = kwargs
self.keys = []

def prepare(self):
model_data = self.kwargs['results']['model_extended']
self.kwargs['results']['model_extended'] = model_data
return self.kwargs['results']
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
class PreparePlugin:
def __init__(self, **kwargs):
self.kwargs = kwargs
self.keys = ['fabric', 'topology', 'switches']

def prepare(self):
model_data = self.kwargs['results']['model_extended']

if model_data.get(self.keys[0]).get(self.keys[1]).get(self.keys[2]) is not None:
model_data['fabric']['topology']['spine'] = {}
model_data['fabric']['topology']['leaf'] = {}
sm_switches = model_data['fabric']['topology']['switches']
for switch in sm_switches:
# Build list of switch IP's based on role keyed by switch name
name = switch.get('name')
role = switch.get('role')
model_data['fabric']['topology'][role][name] = {}
v4_key = 'management_ipv4_address'
v6_key = 'management_ipv6_address'
v4ip = switch.get('management').get(v4_key)
v6ip = switch.get('management').get(v6_key)
model_data['fabric']['topology'][role][name][v4_key] = v4ip
model_data['fabric']['topology'][role][name][v6_key] = v6ip

self.kwargs['results']['model_extended'] = model_data
return self.kwargs['results']
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
class PreparePlugin:
def __init__(self, **kwargs):
self.kwargs = kwargs
self.keys = ['fabric', 'overlay_services', 'vrfs', 'networks']

def prepare(self):
model_data = self.kwargs['results']['model_extended']

# Handle VRFs/Networks Under Overlay Services. Need to create an empty list
# if vrfs/networks or vrf/networks key is not present in the service model data
if model_data.get('fabric').get('overlay_services') is None:
model_data['fabric']['overlay_services'] = {'vrfs': []}
model_data['fabric']['overlay_services'] = {'networks': []}
if model_data.get('fabric').get('overlay_services').get('vrfs') is None:
model_data['fabric']['overlay_services']['vrfs'] = []
if model_data.get('fabric').get('overlay_services').get('networks') is None:
model_data['fabric']['overlay_services']['networks'] = []

# Rebuild sm_data['fabric']['overlay_services']['vrf_attach_groups'] into
# a structure that is easier to use.
model_data['fabric']['overlay_services']['vrf_attach_groups_dict'] = {}
for grp in model_data['fabric']['overlay_services']['vrf_attach_groups']:
model_data['fabric']['overlay_services']['vrf_attach_groups_dict'][grp['name']] = []
for switch in grp['switches']:
model_data['fabric']['overlay_services']['vrf_attach_groups_dict'][grp['name']].append(switch)

# Rebuild sm_data['fabric']['overlay_services']['network_attach_groups'] into
# a structure that is easier to use.
model_data['fabric']['overlay_services']['network_attach_groups_dict'] = {}
for grp in model_data['fabric']['overlay_services']['network_attach_groups']:
model_data['fabric']['overlay_services']['network_attach_groups_dict'][grp['name']] = []
for switch in grp['switches']:
model_data['fabric']['overlay_services']['network_attach_groups_dict'][grp['name']].append(switch)

self.kwargs['results']['model_extended'] = model_data
return self.kwargs['results']
Loading

0 comments on commit fab43c5

Please sign in to comment.