Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New module cli_backup #488

Merged
merged 5 commits into from
Sep 20, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ Name | Description
### Modules
Name | Description
--- | ---
[ansible.netcommon.cli_backup](https://github.com/ansible-collections/ansible.netcommon/blob/main/docs/ansible.netcommon.cli_backup_module.rst)|Back up device configuration from network devices over network_cli
[ansible.netcommon.cli_command](https://github.com/ansible-collections/ansible.netcommon/blob/main/docs/ansible.netcommon.cli_command_module.rst)|Run a cli command on cli-based network devices
[ansible.netcommon.cli_config](https://github.com/ansible-collections/ansible.netcommon/blob/main/docs/ansible.netcommon.cli_config_module.rst)|Push text based configuration to network devices over network_cli
[ansible.netcommon.grpc_config](https://github.com/ansible-collections/ansible.netcommon/blob/main/docs/ansible.netcommon.grpc_config_module.rst)|Fetch configuration/state data from gRPC enabled target hosts.
Expand Down
3 changes: 3 additions & 0 deletions changelogs/fragments/cli_backup.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
minor_changes:
- Add new module cli_backup that exclusively handles configuration backup.
149 changes: 149 additions & 0 deletions docs/ansible.netcommon.cli_backup_module.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
.. _ansible.netcommon.cli_backup_module:


****************************
ansible.netcommon.cli_backup
****************************

**Back up device configuration from network devices over network_cli**


Version added: 4.2.0

.. contents::
:local:
:depth: 1


Synopsis
--------
- This module provides platform agnostic way of backing up text based configuration from network devices over network_cli connection plugin.




Parameters
----------

.. raw:: html

<table border=0 cellpadding=0 class="documentation-table">
<tr>
<th colspan="1">Parameter</th>
<th>Choices/<font color="blue">Defaults</font></th>
<th width="100%">Comments</th>
</tr>
<tr>
<td colspan="1">
<div class="ansibleOptionAnchor" id="parameter-"></div>
<b>defaults</b>
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
<div style="font-size: small">
<span style="color: purple">boolean</span>
</div>
</td>
<td>
<ul style="margin: 0; padding: 0"><b>Choices:</b>
<li><div style="color: blue"><b>no</b>&nbsp;&larr;</div></li>
<li>yes</li>
</ul>
</td>
<td>
<div>The <em>defaults</em> argument will influence how the running-config is collected from the device. When the value is set to true, the command used to collect the running-config is append with the all keyword. When the value is set to false, the command is issued without the all keyword.</div>
</td>
</tr>
<tr>
<td colspan="1">
<div class="ansibleOptionAnchor" id="parameter-"></div>
<b>dir_path</b>
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
<div style="font-size: small">
<span style="color: purple">path</span>
</div>
</td>
<td>
</td>
<td>
<div>This option provides the path ending with directory name in which the backup configuration file will be stored. If the directory does not exist it will be first created and the filename is either the value of <code>filename</code> or default filename as described in <code>filename</code> options description. If the path value is not given in that case a <em>backup</em> directory will be created in the current working directory and backup configuration will be copied in <code>filename</code> within <em>backup</em> directory.</div>
</td>
</tr>
<tr>
<td colspan="1">
<div class="ansibleOptionAnchor" id="parameter-"></div>
<b>filename</b>
<a class="ansibleOptionLink" href="#parameter-" title="Permalink to this option"></a>
<div style="font-size: small">
<span style="color: purple">string</span>
</div>
</td>
<td>
</td>
<td>
<div>The filename to be used to store the backup configuration. If the filename is not given it will be generated based on the hostname, current time and date in format defined by &lt;hostname&gt;_config.&lt;current-date&gt;@&lt;current-time&gt;</div>
</td>
</tr>
</table>
<br/>


Notes
-----

.. note::
- This module is supported on ``ansible_network_os`` network platforms. See the :ref:`Network Platform Options <platform_options>` for details.



Examples
--------

.. code-block:: yaml

- name: configurable backup path
ansible.netcommon.cli_backup:
filename: backup.cfg
dir_path: /home/user



Return Values
-------------
Common return values are documented `here <https://docs.ansible.com/ansible/latest/reference_appendices/common_return_values.html#common-return-values>`_, the following are the fields unique to this module:

.. raw:: html

<table border=0 cellpadding=0 class="documentation-table">
<tr>
<th colspan="1">Key</th>
<th>Returned</th>
<th width="100%">Description</th>
</tr>
<tr>
<td colspan="1">
<div class="ansibleOptionAnchor" id="return-"></div>
<b>backup_path</b>
<a class="ansibleOptionLink" href="#return-" title="Permalink to this return value"></a>
<div style="font-size: small">
<span style="color: purple">string</span>
</div>
</td>
<td>always</td>
<td>
<div>The full path to the backup file</div>
<br/>
<div style="font-size: smaller"><b>Sample:</b></div>
<div style="font-size: smaller; color: blue; word-wrap: break-word; word-break: break-all;">/playbooks/ansible/backup/hostname_config.2016-07-16@22:28:34</div>
</td>
</tr>
</table>
<br/><br/>


Status
------


Authors
~~~~~~~

- Kate Case (@Qalthos)
31 changes: 31 additions & 0 deletions plugins/action/cli_backup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#
# Copyright 2018 Red Hat Inc.
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later

from __future__ import absolute_import, division, print_function


__metaclass__ = type

from ansible_collections.ansible.netcommon.plugins.action.network import (
ActionModule as ActionNetworkModule,
)


class ActionModule(ActionNetworkModule):
def run(self, tmp=None, task_vars=None):
if self._play_context.connection.split(".")[-1] != "network_cli":
return {
"failed": True,
"msg": "Connection type %s is not valid for this module"
% self._play_context.connection,
}
result = super(ActionModule, self).run(task_vars=task_vars)
self._handle_backup_option(
result,
task_vars,
self._task.args,
)

return result
9 changes: 6 additions & 3 deletions plugins/action/network.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,11 +81,15 @@ def run(self, tmp=None, task_vars=None):
result = super(ActionModule, self).run(task_vars=task_vars)

if config_module and self._task.args.get("backup") and not result.get("failed"):
self._handle_backup_option(result, task_vars)
self._handle_backup_option(
result,
task_vars,
self._task.args.get("backup_options"),
)

return result

def _handle_backup_option(self, result, task_vars):
def _handle_backup_option(self, result, task_vars, backup_options):
filename = None
backup_path = None
try:
Expand All @@ -99,7 +103,6 @@ def _handle_backup_option(self, result, task_vars):
except KeyError:
raise AnsibleError("Failed while reading configuration backup")

backup_options = self._task.args.get("backup_options")
if backup_options:
filename = backup_options.get("filename")
backup_path = backup_options.get("dir_path")
Expand Down
126 changes: 126 additions & 0 deletions plugins/modules/cli_backup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-

# (c) 2018, Ansible by Red Hat, inc
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later

from __future__ import absolute_import, division, print_function


__metaclass__ = type


DOCUMENTATION = """
module: cli_backup
author: Kate Case (@Qalthos)
short_description: Back up device configuration from network devices over network_cli
description:
- This module provides platform agnostic way of backing up text based configuration from
network devices over network_cli connection plugin.
version_added: 4.2.0
extends_documentation_fragment:
- ansible.netcommon.network_agnostic
options:
defaults:
description:
- The I(defaults) argument will influence how the running-config is collected
from the device. When the value is set to true, the command used to collect
the running-config is append with the all keyword. When the value is set to
false, the command is issued without the all keyword.
default: no
type: bool
filename:
description:
- The filename to be used to store the backup configuration. If the filename
is not given it will be generated based on the hostname, current time and
date in format defined by <hostname>_config.<current-date>@<current-time>
type: str
dir_path:
description:
- This option provides the path ending with directory name in which the backup
configuration file will be stored. If the directory does not exist it will
be first created and the filename is either the value of C(filename) or
default filename as described in C(filename) options description. If the
path value is not given in that case a I(backup) directory will be created
in the current working directory and backup configuration will be copied
in C(filename) within I(backup) directory.
type: path
"""

EXAMPLES = """
- name: configurable backup path
ansible.netcommon.cli_backup:
filename: backup.cfg
dir_path: /home/user
"""

RETURN = """
backup_path:
description: The full path to the backup file
returned: always
type: str
sample: /playbooks/ansible/backup/hostname_config.2016-07-16@22:28:34
"""

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.connection import Connection


def validate_args(module, device_operations):
"""validate param if it is supported on the platform"""
feature_list = [
"defaults",
]

for feature in feature_list:
if module.params[feature]:
supports_feature = device_operations.get("supports_%s" % feature)
if supports_feature is None:
module.fail_json(
msg="This platform does not specify whether %s is supported or not. "
"Please report an issue against this platform's cliconf plugin." % feature
)
elif not supports_feature:
module.fail_json(msg="Option %s is not supported on this platform" % feature)


def main():
"""main entry point for execution"""
argument_spec = dict(
defaults=dict(default=False, type="bool"),
filename=dict(),
dir_path=dict(type="path"),
)

module = AnsibleModule(
argument_spec=argument_spec,
)

result = {"changed": False}

connection = Connection(module._socket_path)
capabilities = module.from_json(connection.get_capabilities())

if capabilities:
device_operations = capabilities.get("device_operations", dict())
validate_args(module, device_operations)
else:
device_operations = dict()

if module.params["defaults"]:
if "get_default_flag" in capabilities.get("rpc"):
flags = connection.get_default_flag()
else:
flags = "all"
else:
flags = []

running = connection.get_config(flags=flags)
result["__backup__"] = running

module.exit_json(**result)


if __name__ == "__main__":
main()
Loading
Loading