Skip to content

Commit 485d09d

Browse files
author
kamatha1
committed
Creating a napalm_get_config module to fetch device configurations using NAPALM driver get_config method
1 parent 634e177 commit 485d09d

File tree

2 files changed

+234
-0
lines changed

2 files changed

+234
-0
lines changed
+233
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,233 @@
1+
"""
2+
(c) 2020 Kirk Byers <[email protected]>
3+
(c) 2016 Elisa Jasinska <[email protected]>
4+
Original prototype by David Barroso <[email protected]>
5+
6+
This file is part of Ansible
7+
8+
Ansible is free software: you can redistribute it and/or modify
9+
it under the terms of the GNU General Public License as published by
10+
the Free Software Foundation, either version 3 of the License, or
11+
(at your option) any later version.
12+
13+
Ansible is distributed in the hope that it will be useful,
14+
but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
GNU General Public License for more details.
17+
18+
You should have received a copy of the GNU General Public License
19+
along with Ansible. If not, see <http://www.gnu.org/licenses/>.
20+
"""
21+
from __future__ import unicode_literals, print_function
22+
import os.path
23+
from ansible.module_utils.basic import AnsibleModule
24+
25+
26+
# FIX for Ansible 2.8 moving this function and making it private
27+
# greatly simplified for napalm-ansible's use
28+
def return_values(obj):
29+
""" Return native stringified values from datastructures.
30+
31+
For use with removing sensitive values pre-jsonification."""
32+
yield str(obj)
33+
34+
35+
DOCUMENTATION = """
36+
---
37+
module: napalm_get_config
38+
author: "Anirudh Kamath (@anirudhkamath)"
39+
version_added: "2.9"
40+
short_description: "Gathers configuration from a network device via napalm"
41+
description:
42+
- "Gathers configuration from a network device via the Python module napalm"
43+
requirements:
44+
- napalm
45+
options:
46+
hostname:
47+
description:
48+
- IP or FQDN of the device you want to connect to
49+
required: False
50+
username:
51+
description:
52+
- Username
53+
required: False
54+
password:
55+
description:
56+
- Password
57+
required: False
58+
dev_os:
59+
description:
60+
- OS of the device
61+
required: False
62+
provider:
63+
description:
64+
- Dictionary which acts as a collection of arguments used to define the characteristics
65+
of how to connect to the device.
66+
Note - hostname, username, password and dev_os must be defined in either provider
67+
or local param
68+
Note - local param takes precedence, e.g. hostname is preferred to provider['hostname']
69+
required: False
70+
timeout:
71+
description:
72+
- Time in seconds to wait for the device to respond
73+
required: False
74+
default: 60
75+
optional_args:
76+
description:
77+
- Dictionary of additional arguments passed to underlying driver
78+
required: False
79+
default: None
80+
retrieve:
81+
description:
82+
- Which configuration type you want to populate, default is all of them.
83+
required: False
84+
full:
85+
description:
86+
- Retrieve all the configuration. For instance, on ios, "sh run all".
87+
required: False
88+
sanitized:
89+
description:
90+
- Remove secret data
91+
required: False
92+
"""
93+
94+
EXAMPLES = """
95+
- name: Collect device configuration object using NAPALM
96+
napalm_get_config:
97+
hostname: "{{ inventory_hostname }}"
98+
username: "{{ user }}"
99+
password: "{{ password }}"
100+
dev_os: "os"
101+
register: config_result
102+
103+
- name: Write running config to backup file
104+
copy:
105+
content: "{{ config_result.napalm_config.running }}"
106+
dest: "{{ file }}"
107+
"""
108+
109+
RETURN = """
110+
napalm_config:
111+
description: "The object returned is a dictionary with a key for each configuration store:
112+
- running
113+
- candidate
114+
- startup
115+
returned: always
116+
type: dict
117+
sample: "{
118+
"running": "",
119+
"startup": "",
120+
"candidate": "",
121+
}"
122+
"""
123+
124+
napalm_found = False
125+
try:
126+
from napalm import get_network_driver
127+
from napalm.base import ModuleImportError
128+
129+
napalm_found = True
130+
except ImportError:
131+
pass
132+
133+
134+
def main():
135+
module = AnsibleModule(
136+
argument_spec=dict(
137+
hostname=dict(type="str", required=False, aliases=["host"]),
138+
username=dict(type="str", required=False),
139+
password=dict(type="str", required=False, no_log=True),
140+
provider=dict(type="dict", required=False),
141+
timeout=dict(type="int", required=False, default=60),
142+
optional_args=dict(required=False, type="dict", default=None),
143+
dev_os=dict(type="str", required=False),
144+
retrieve=dict(type="str", required=False, default=None),
145+
full=dict(type="str", required=False, default=None),
146+
sanitized=dict(type="str", required=False, default=None),
147+
),
148+
)
149+
150+
if not napalm_found:
151+
module.fail_json(msg="the python module napalm is required")
152+
153+
provider = module.params["provider"] or {}
154+
155+
no_log = ["password", "secret"]
156+
for param in no_log:
157+
if provider.get(param):
158+
module.no_log_values.update(return_values(provider[param]))
159+
if provider.get("optional_args") and provider["optional_args"].get(param):
160+
module.no_log_values.update(
161+
return_values(provider["optional_args"].get(param))
162+
)
163+
if module.params.get("optional_args") and module.params["optional_args"].get(
164+
param
165+
):
166+
module.no_log_values.update(
167+
return_values(module.params["optional_args"].get(param))
168+
)
169+
170+
# allow host or hostname
171+
provider["hostname"] = provider.get("hostname", None) or provider.get("host", None)
172+
# allow local params to override provider
173+
for param, pvalue in provider.items():
174+
if module.params.get(param) is not False:
175+
module.params[param] = module.params.get(param) or pvalue
176+
177+
hostname = module.params["hostname"]
178+
username = module.params["username"]
179+
dev_os = module.params["dev_os"]
180+
password = module.params["password"]
181+
timeout = module.params["timeout"]
182+
retrieve = module.params["retrieve"]
183+
full = module.params["full"]
184+
sanitized = module.params["sanitized"]
185+
186+
argument_check = {"hostname": hostname, "username": username, "dev_os": dev_os}
187+
for key, val in argument_check.items():
188+
if val is None:
189+
module.fail_json(msg=str(key) + " is required")
190+
191+
if module.params["optional_args"] is None:
192+
optional_args = {}
193+
else:
194+
optional_args = module.params["optional_args"]
195+
196+
try:
197+
network_driver = get_network_driver(dev_os)
198+
except ModuleImportError as e:
199+
module.fail_json(msg="Failed to import napalm driver: " + str(e))
200+
201+
try:
202+
device = network_driver(
203+
hostname=hostname,
204+
username=username,
205+
password=password,
206+
timeout=timeout,
207+
optional_args=optional_args,
208+
)
209+
device.open()
210+
except Exception as e:
211+
module.fail_json(msg="cannot connect to device: " + str(e))
212+
213+
try:
214+
get_config_kwargs = {} # kwargs should match driver specific `get_config` method specs
215+
if retrieve is not None:
216+
get_config_kwargs["retrieve"] = retrieve
217+
if full is not None:
218+
get_config_kwargs["full"] = full
219+
if sanitized is not None:
220+
get_config_kwargs["sanitized"] = sanitized
221+
config_dict = device.get_config(**get_config_kwargs)
222+
results = {
223+
"changed": False,
224+
"napalm_config": config_dict,
225+
}
226+
except Exception as e:
227+
module.fail_json(msg="cannot retrieve device config:" + str(e))
228+
229+
module.exit_json(**results)
230+
231+
232+
if __name__ == "__main__":
233+
main()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
napalm.py

0 commit comments

Comments
 (0)