-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Ansible dynamic inventory support (#2)
* add dynamic inventory support * readme
- Loading branch information
1 parent
3ec475a
commit c0fb8b0
Showing
46 changed files
with
1,955 additions
and
278 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
inventory: | ||
plugin: nornsible.inventory.AnsibleInventory | ||
options: | ||
inventory: inventory.yaml |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
--- | ||
username: username | ||
password: password |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--- | ||
platform: ios | ||
connection_options: | ||
netmiko: | ||
platform: cisco_ios | ||
napalm: | ||
platform: ios |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
--- | ||
all: | ||
children: | ||
ios: | ||
hosts: | ||
c3560: | ||
ansible_host: c3560x |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
from nornir import InitNornir | ||
from nornir.plugins.tasks import networking | ||
|
||
|
||
def main(): | ||
nr = InitNornir(config_file="config.yaml") | ||
nr = nr.filter(name="c3560") | ||
agg_result = nr.run( | ||
task=networking.netmiko_send_command, command_string="show run | i hostname" | ||
) | ||
print(agg_result["c3560"].result) | ||
|
||
|
||
if __name__ == "__main__": | ||
main() |
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
import argparse | ||
from typing import List | ||
|
||
|
||
def parse_cli_args(raw_args: List[str]) -> dict: | ||
""" | ||
Parse CLI provided arguments; ignore unrecognized. | ||
Arguments: | ||
raw_args: List of CLI provided arguments | ||
Returns: | ||
cli_args: Processed CLI arguments | ||
Raises: | ||
N/A # noqa | ||
""" | ||
parser = argparse.ArgumentParser(description="Nornir Script Wrapper") | ||
parser.add_argument( | ||
"-w", | ||
"--workers", | ||
help="number of workers to set for global configuration", | ||
type=int, | ||
default=0, | ||
) | ||
parser.add_argument( | ||
"-l", | ||
"--limit", | ||
help="limit to host or comma separated list of hosts", | ||
type=str.lower, | ||
default="", | ||
) | ||
parser.add_argument( | ||
"-g", | ||
"--groups", | ||
help="limit to group or comma separated list of groups", | ||
type=str.lower, | ||
default="", | ||
) | ||
parser.add_argument( | ||
"-t", "--tags", help="names of tasks to explicitly run", type=str.lower, default="" | ||
) | ||
parser.add_argument("-s", "--skip", help="names of tasks to skip", type=str.lower, default="") | ||
parser.add_argument( | ||
"-d", "--disable-delegate", help="disable adding delegate host", action="store_true" | ||
) | ||
args, _ = parser.parse_known_args(raw_args) | ||
cli_args = { | ||
"workers": args.workers if args.workers else False, | ||
"limit": set(args.limit.split(",")) if args.limit else False, | ||
"groups": set(args.groups.split(",")) if args.groups else False, | ||
"run_tags": set(args.tags.split(",")) if args.tags else [], | ||
"skip_tags": set(args.skip.split(",")) if args.skip else [], | ||
"disable_delegate": args.disable_delegate, | ||
} | ||
return cli_args |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
import threading | ||
from typing import Dict, List, Any, Union, Callable, Optional | ||
|
||
from colorama import Back, Fore, init, Style | ||
from nornir.core.task import Result, Task | ||
|
||
|
||
init(autoreset=True, strip=False) | ||
LOCK = threading.Lock() | ||
|
||
|
||
def nornsible_task_message(msg: str, critical: Optional[bool] = False) -> None: | ||
""" | ||
Handle printing pretty messages for nornsible_task decorator | ||
Args: | ||
msg: message to beautifully print to stdout | ||
critical: (optional) message is critical | ||
Returns: | ||
N/A | ||
Raises: | ||
N/A # noqa | ||
""" | ||
if critical: | ||
back = Back.RED | ||
fore = Fore.WHITE | ||
else: | ||
back = Back.CYAN | ||
fore = Fore.WHITE | ||
|
||
LOCK.acquire() | ||
try: | ||
print(f"{Style.BRIGHT}{back}{fore}{msg}{'-' * (80 - len(msg))}") | ||
finally: | ||
LOCK.release() | ||
|
||
|
||
def nornsible_task(wrapped_func: Callable) -> Callable: | ||
""" | ||
Decorate an "operation" -- execute or skip the operation based on tags | ||
Args: | ||
wrapped_func: function to wrap in tag processor | ||
Returns: | ||
tag_wrapper: wrapped function | ||
Raises: | ||
N/A # noqa | ||
""" | ||
|
||
def tag_wrapper( | ||
task: Task, *args: List[Any], **kwargs: Dict[str, Any] | ||
) -> Union[Callable, Result]: | ||
if task.host.name == "delegate": | ||
return Result( | ||
host=task.host, result="Task skipped, delegate host!", failed=False, changed=False | ||
) | ||
if {wrapped_func.__name__}.intersection(task.nornir.skip_tags): | ||
msg = f"---- {task.host} skipping task {wrapped_func.__name__} " | ||
nornsible_task_message(msg) | ||
return Result(host=task.host, result="Task skipped!", failed=False, changed=False) | ||
if not task.nornir.run_tags: | ||
return wrapped_func(task, *args, **kwargs) | ||
if {wrapped_func.__name__}.intersection(task.nornir.run_tags): | ||
return wrapped_func(task, *args, **kwargs) | ||
msg = f"---- {task.host} skipping task {wrapped_func.__name__} " | ||
nornsible_task_message(msg) | ||
return Result(host=task.host, result="Task skipped!", failed=False, changed=False) | ||
|
||
tag_wrapper.__name__ = wrapped_func.__name__ | ||
return tag_wrapper | ||
|
||
|
||
def nornsible_delegate(wrapped_func: Callable) -> Callable: | ||
""" | ||
Decorate an "operation" -- execute only on "delegate" (localhost) | ||
Args: | ||
wrapped_func: function to wrap in delegate_wrapper | ||
Returns: | ||
tag_wrapper: wrapped function | ||
Raises: | ||
N/A # noqa | ||
""" | ||
|
||
def delegate_wrapper( | ||
task: Task, *args: List[Any], **kwargs: Dict[str, Any] | ||
) -> Union[Callable, Result]: | ||
if "delegate" not in task.nornir.inventory.hosts.keys(): | ||
msg = f"---- WARNING no delegate available for task {wrapped_func.__name__} " | ||
nornsible_task_message(msg, critical=True) | ||
return Result( | ||
host=task.host, result="Task skipped, delegate host!", failed=False, changed=False | ||
) | ||
if task.host.name != "delegate": | ||
return Result( | ||
host=task.host, | ||
result="Task skipped, non-delegate host!", | ||
failed=False, | ||
changed=False, | ||
) | ||
return wrapped_func(task, *args, **kwargs) | ||
|
||
delegate_wrapper.__name__ = wrapped_func.__name__ | ||
return delegate_wrapper |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
import logging | ||
import threading | ||
from typing import List, Optional | ||
|
||
from nornir.core.task import AggregatedResult, MultiResult, Result | ||
from nornir.plugins.functions.text import _print_result | ||
|
||
|
||
LOCK = threading.Lock() | ||
|
||
|
||
def print_result( | ||
result: Result, | ||
host: Optional[str] = None, | ||
nr_vars: List[str] = None, | ||
failed: bool = False, | ||
severity_level: int = logging.INFO, | ||
) -> None: | ||
updated_agg_result = AggregatedResult(result.name) | ||
for hostname, multi_result in result.items(): | ||
updated_multi_result = MultiResult(result.name) | ||
for r in multi_result: | ||
if isinstance(r.result, str) and r.result.startswith("Task skipped"): | ||
continue | ||
updated_multi_result.append(r) | ||
if updated_multi_result: | ||
updated_agg_result[hostname] = updated_multi_result # noqa | ||
|
||
if not updated_agg_result: | ||
return | ||
|
||
LOCK.acquire() | ||
try: | ||
_print_result(updated_agg_result, host, nr_vars, failed, severity_level) | ||
finally: | ||
LOCK.release() |
Oops, something went wrong.