Skip to content

Commit

Permalink
Add Nornir plugins and update netmiko to 3.4.0:
Browse files Browse the repository at this point in the history
 - add nornir-f5 and nornir-pyez Nornir plugins
 - update dependencies (netmiko to 3.4.0 and click to 7.1.2 from ^7.1.2)
 - fix default_value in click command options
 - fix regex in _doc_generator
 - fix the code responsible for collecting statistic
 - fix documentation
  • Loading branch information
timeforplanb123 committed Apr 24, 2021
1 parent d5c028b commit e7e3435
Show file tree
Hide file tree
Showing 12 changed files with 187 additions and 66 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ nornir_cli

* **Manage your custom nornir runbooks**

* Create and manage your own runbooks collections
* Add your custom nornir runbooks to runbooks collections and run it for any hosts directly from the CLI
* Create and manage your own runbook collections
* Add your custom nornir runbooks to runbook collections and run it for any hosts directly from the CLI
* Or use `nornir_cli` for inventory management only, and take the result in your nornir runbooks. By excluding getting and filtering the inventory in your runbooks, you will make them more versatile.

* **Manage Inventory**
Expand All @@ -39,7 +39,7 @@ nornir_cli

* **Json input. Json output**

Json strings are everywhere! Ok, only in commands options
Json strings are everywhere! Ok, only in command options

* **Custom Multi Commands with click**

Expand Down Expand Up @@ -80,7 +80,7 @@ docker build -t timeforplanb123/nornir_cli .
docker run --rm -it timeforplanb123/nornir_cli sh
# nornir_cli --version
nornir_cli, version 0.2.0
nornir_cli, version 0.3.0
```

Expand Down
4 changes: 2 additions & 2 deletions docs/examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ And here is an example of this runbook:
```
=== "jinja2 template:"
```jinja
# nornir_cli/custom_commands/templates/dhcp_snooping.j2
# nornir_cli/custom_commands/dhcp/templates/dhcp_snooping.j2

dhcp enable
dhcp snooping enable
Expand All @@ -225,7 +225,7 @@ And here is an example of this runbook:
```
=== "textfsm template:"
```text
# nornir_cli/custom_commands/templates/disp_int.template
# nornir_cli/custom_commands/dhcp/templates/disp_int.template

Value NAME (\S+)
Value DESCRIPTION (.*)
Expand Down
6 changes: 3 additions & 3 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@

* **Manage your custom nornir runbooks**

* Create and manage your own runbooks collections
* Add your custom nornir runbooks to runbooks collections and run it for any hosts directly from the CLI
* Create and manage your own runbook collections
* Add your custom nornir runbooks to runbook collections and run it for any hosts directly from the CLI
* Or use `nornir_cli` for inventory management only, and take the result in your nornir runbooks. By excluding getting and filtering the inventory in your runbooks, you will make them more versatile.

* **Manage Inventory**
Expand Down Expand Up @@ -65,7 +65,7 @@ docker build -t timeforplanb123/nornir_cli .
docker run --rm -it timeforplanb123/nornir_cli sh
# nornir_cli --version
nornir_cli, version 0.2.0
nornir_cli, version 0.3.0
```

#### Simple Example
Expand Down
2 changes: 2 additions & 0 deletions docs/useful.md
Original file line number Diff line number Diff line change
Expand Up @@ -93,9 +93,11 @@ All custom Nornir runbooks stored in `custom_commands` directory (see [Click Mul
Commands:
dhcp
mpls
nornir-f5 nornir_f5 plugin
nornir-jinja2 nornir_jinja2 plugin
nornir-napalm nornir_napalm plugin
nornir-netmiko nornir_netmiko plugin
nornir-pyez nornir_pyez plugin
nornir-scrapli nornir_scrapli plugin
```

Expand Down
75 changes: 73 additions & 2 deletions docs/workflow.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ $ nornir_cli nornir-netmiko init -c ~/config.yaml
```
Why is `nornir-netmiko` here? `nornir_cli` runs Tasks based on Nornir plugins or your custom Nornir runbooks, so the first step is to select an available plugin or custom.

For version `0.2.0`, only Connection plugins and `nornir_jinja2` are available:
For version `0.3.0`, the following Nornir plugins are available:
```text
$ nornir_cli --help
Usage: nornir_cli [OPTIONS] COMMAND [ARGS]...
Expand All @@ -38,9 +38,11 @@ Options:
--help Show this message and exit.
Commands:
nornir_jinja2 nornir_jinja2 plugin
nornir-f5 nornir_f5 plugin
nornir-jinja2 nornir_jinja2 plugin
nornir-napalm nornir_napalm plugin
nornir-netmiko nornir_netmiko plugin
nornir-pyez nornir_pyez plugin
nornir-scrapli nornir_scrapli plugin
```
#### Without a configuration file
Expand Down Expand Up @@ -332,6 +334,75 @@ At first, let's check all available Tasks/commands for current list of nornir pl
template_string Renders a string with jinja2. All the host data is
available in the template
```
=== "nornir-pyez:"
```text
$ nornir_cli nornir-pyez
Usage: nornir_cli nornir-pyez [OPTIONS] COMMAND1 [ARGS]... [COMMAND2
[ARGS]...]...

nornir_pyez plugin

Options:
--help Show this message and exit.

Commands:
init Initialize a Nornir
filter Do simple or advanced filtering
show_inventory Show current inventory
pyez_facts
pyez_config
pyez_get_config
pyez_diff
pyez_commit
pyez_int_terse
pyez_route_info
pyez_rpc
pyez_sec_ike
pyez_sec_ipsec
pyez_sec_nat_dest
pyez_sec_nat_src
pyez_sec_policy
pyez_sec_zones
```
=== "nornir-f5:"
```text
$ nornir_cli nornir-f5
Usage: nornir_cli nornir-f5 [OPTIONS] COMMAND1 [ARGS]... [COMMAND2
[ARGS]...]...

nornir_f5 plugin

Options:
--help Show this message and exit.

Commands:
init Initialize a Nornir
filter Do simple or advanced filtering
show_inventory Show current inventory
atc Task to deploy declaratives on F5 devices
atc_info Task to verify if ATC service is available
and collect service info

bigip_cm_config_sync Task to synchronize the configuration
between devices

bigip_cm_failover_status Task to get the failover status of the
device

bigip_cm_sync_status Task to get the synchronization status of
the device

bigip_shared_file_transfer_uploads
Upload a file to a BIG-IP system using the
iControl REST API

bigip_shared_iapp_lx_package Task to manage Javascript LX packages on a
BIG-IP

bigip_sys_version Gets the system version of the BIG-IP
bigip_util_unix_ls Task to list information about the FILEs
bigip_util_unix_rm Task to delete a file from a BIG-IP system
```

And start `netmiko_send_command`, for example:

Expand Down
2 changes: 1 addition & 1 deletion nornir_cli/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "0.2.0"
__version__ = "0.3.0"
2 changes: 1 addition & 1 deletion nornir_cli/common_commands/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ def _get_lists(s):
def _doc_generator(s):
regex = (
r".*kwargs: (?P<kwargs>.*)"
r"|.*task: (?P<task>.*)"
r"|.*task(?P<task>.*)"
r"|(?P<returns>.*Returns.*)"
r"|(?P<colon>^\S+:.*)"
r"|(?P<dash>.* – .*)"
Expand Down
57 changes: 41 additions & 16 deletions nornir_cli/nornir_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
from nornir_cli import __version__


# CMD_FOLDERS = ["common_commands", "custom_commands"]
CMD_FOLDERS = ["common_commands"]

PACKAGE_NAME = "nornir_cli"
Expand Down Expand Up @@ -109,7 +108,6 @@ def get_command(self, ctx, cmd_name):
return

def get_custom_command(self, ctx, cmd_name):
# CMD_FOLDERS = CMD_FOLDERS + cmd_path
try:
for abs_path, rel_path in zip(
_get_cmd_folder(CMD_FOLDERS + cmd_path),
Expand Down Expand Up @@ -190,32 +188,40 @@ def finder():
else:
init_nornir_cli.group(cls=scls, chain=True)(f)

grp_exceptions = os.environ.get("NORNIR_CLI_GRP_EXCEPTIONS")

custom_exceptions = ["__pycache__", "templates"]

grp_exceptions = os.environ.get("NORNIR_CLI_GRP_EXCEPTIONS")
if grp_exceptions:
custom_exceptions += grp_exceptions.split(",")

scls = class_factory("LazyClass", param, ["custom_commands"])

return wrapper


#
# command decorator
def decorator(plugin, ctx):
def wrapper(f):
# methods with a large and complex __doc__ :(
method_exceptions = ("send_interactive",)
if obj_or.__doc__:

short_help = obj_or.__doc__.split("\n")[1].strip(", ., :")
doc = [title for title in obj_or.__doc__.split("\n")[:2] if title]

f.__doc__ = "\n".join(list(_doc_generator(obj_or.__doc__)))
short_help = doc[0].strip(", ., :")

if obj_or.__name__ in method_exceptions:
f.__doc__ = f"{short_help}\n" + "\n".join(
list(
_doc_generator(obj_or.__doc__[obj_or.__doc__.find(" Args:") : :])
)
)
f.__doc__ = "\n".join(list(_doc_generator(obj_or.__doc__)))

if obj_or.__name__ in method_exceptions:
f.__doc__ = f"{short_help}\n" + "\n".join(
list(
_doc_generator(
obj_or.__doc__[obj_or.__doc__.find(" Args:") : :]
)
)
)
else:
short_help = ""
cmd = click.command(name=obj_or.__name__, short_help=short_help)(f)

click.option(
Expand All @@ -242,24 +248,29 @@ def wrapper(f):
for key, value in p.items()
if key not in ["self", "task", "args", "kwargs"]
}

# dynamically generate options
for k, v in all_dict.items():
default_value = str(v.default) if not isinstance(v.default, type) else None
click.option(
"--" + k,
default=default_value,
show_default=True,
required=False if default_value else True,
required=False if default_value or default_value == "" else True,
type=PARAMETER_TYPES.setdefault(type(v.default), click.STRING),
)(cmd)

# last original functions with arguments
ctx.obj["queue_parameters"][obj_or].update({k: v.default})

# list of dictionaries with original function (key) and set of arguments (value)
ctx.obj["queue_functions"].append(ctx.obj["queue_parameters"])

# ctx.obj["queue_functions"] in the form of a generator expression
ctx.obj["queue_functions_generator"] = (
func_param for func_param in ctx.obj["queue_functions"]
)

return cmd

# get original function from Nornir plugin
Expand Down Expand Up @@ -321,8 +332,22 @@ def nornir_jinja2():
pass


@dec()
def custom():
@dec("nornir_pyez.plugins")
def nornir_pyez():
"""
nornir_pyez plugin
"""
pass


@dec("nornir_f5.plugins")
def nornir_f5():
"""
nornir_f5 plugin
"""
pass


@dec()
def custom():
pass
31 changes: 0 additions & 31 deletions nornir_cli/plugin_commands/cmd_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,6 @@
from tqdm import tqdm


# def _get_color(f, ch):
# if f:
# color = "red"
# elif ch:
# color = "yellow"
# else:
# color = "green"
# return color


def multiple_progress_bar(task, method, pg_bar, **kwargs):
task.run(task=method, **kwargs)
if pg_bar:
Expand Down Expand Up @@ -75,24 +65,3 @@ def cli(ctx, pg_bar, show_result, *args, **kwargs):

# show statistic
_info(nr, task)
# ch_sum = 0
# for host in nr.inventory.hosts:
# f, ch = (task[host].failed, task[host].changed)
# ch_sum += int(ch)
# click.secho(
# f"{host:<50}: ok={not f:<15} changed={ch:<15} failed={f:<15}",
# fg=_get_color(f, ch),
# bold=True,
# )
# print()
# f_sum = len(nr.data.failed_hosts)
# ok_sum = len(nr.inventory.hosts) - f_sum
# for state, summary, color in zip(
# ("OK", "CHANGED", "FAILED"), (ok_sum, ch_sum, f_sum), ("green", "yellow", "red")
# ):
# click.secho(
# f"{state:<8}: {summary}",
# fg=color,
# bold=True,
# )
# print()
Loading

0 comments on commit e7e3435

Please sign in to comment.