Skip to content

Commit 3f32732

Browse files
authored
Merge pull request #84 from napalm-automation/develop
Release 0.7.0
2 parents 71aa095 + ec855dd commit 3f32732

29 files changed

+542
-115
lines changed

.travis.yml

+14-11
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
language: python
2+
23
python:
34
- 2.7
45

@@ -7,19 +8,21 @@ env:
78
- ANSIBLE_VERSION=2.3
89

910
install:
11+
- pip install pylama
1012
- pip install napalm-base
1113
- pip install "ansible>=$ANSIBLE_VERSION.0,<$ANSIBLE_VERSION.99"
1214

1315
script:
16+
- pylama
1417
- cd tests
15-
# Test configuration dry-run
16-
- ansible-playbook -i napalm_install_config/hosts -l "*.dry_run.*" napalm_install_config/config.yaml -C
17-
# Test configuration commit
18-
- ansible-playbook -i napalm_install_config/hosts -l "*.commit.*" napalm_install_config/config.yaml
19-
# Test configuration errrors
20-
- ansible-playbook -i napalm_install_config/hosts -l "*.error*" napalm_install_config/config_error.yaml
21-
# Test get_facts
22-
- ansible-playbook -i napalm_get_facts/hosts napalm_get_facts/get_facts_ok.yaml -l multiple_facts.ok
23-
- ansible-playbook -i napalm_get_facts/hosts napalm_get_facts/get_facts_not_implemented.yaml -l multiple_facts.not_implemented -e "ignore_notimplemented=true"
24-
- ansible-playbook -i napalm_get_facts/hosts napalm_get_facts/get_facts_not_implemented.yaml -l multiple_facts.not_implemented -e "ignore_notimplemented=false"
25-
- ansible-playbook -i napalm_get_facts/hosts napalm_get_facts/get_facts_error.yaml -l multiple_facts.error
18+
- ./run_tests.sh
19+
- ./test_changelog.sh
20+
21+
deploy:
22+
provider: pypi
23+
user: dbarroso
24+
password:
25+
secure: cXZNckuwEv4qQbUz1uCx3mDnylSCPFTfTrxYISkuRJz6cgNBJZ64KGvKNdF5ygUGAXHLbx3+LtBGtYTei1Rc6Mi8L64+XAH5Johs0TZTnlor0FyezlutGZSnzJEsXSditCl31Ap2kXOtRY5u5lJi+sa/WnLDH/cAIslISsys0RmtAcfO6HYR8rhFXCuTwG4dhWoxVKwcQE2PWZcGWBV1y9vCqMYSVGNYWKXfAduZZnBXXOcHTvCvobz9KvYYYKShOK5j7D1SURXr9/qBKWnnSN4e16UKPfTgj8o/r/zS/K4gb7rONY5Tv1YkzcbN7u/YEO1fB4s43mB//Hv9gSrCZ95Xc5TPaqfUDs15s0t/mxIPNtOJmcxJwm+ewQm5HouO9U0/d7t4Aw5BXVLqVJCsOuz1xvqe5gsJeCIkwDyk2qtqPTYyuBpn3fMXJfHMCLIVcGxmmNjCdAMMdqhVZ4sJlUfTxmxPqU97KRvHlGRW2Cz3QtrVealjdN7+jNWVl7ERiQoKfbF2TjEzdQ4Tr+KZinygv7pst4TT2/wfyzf2YluPyPtISCUUMzLmEogATJbizoOZPSrN1FFrq8PCmsQzYRxxaMU+auTCoJY4gUOefEuQpZgM3m46pzpRpwuZVnvEYt1ffXUNmyggo2jaSYsRQ5wEtzpf8MGjnjDe878M4yA=
26+
on:
27+
tags: true
28+
branch: master

CHANGELOG.rst

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
0.7.0
2+
=====
3+
4+
- Minor internal improvements
5+
- [#77] Added ``napalm_cli`` module
6+
- Prepend 'napalm_' to NAPALM ansible facts generated by napalm_get_facts module
7+
- Make NAPALM 'get_facts' be directly accessible Ansible facts (e.g. napalm_model)
8+
- Change validate behavior to fail if 'complies' is False
9+
- Create run_tests.sh script to make it easier to run the unit tests
10+
11+
0.6.1
12+
=====
13+
14+
- First official version installable via pypi

MANIFEST.in

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
include requirements.txt

README.md

+31-21
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,50 @@
1-
napalm-ansible
2-
======
1+
# napalm-ansible
32

4-
Collection of ansible modules that use [napalm](https://github.com/napalm-automation/napalm) to retrieve data or modify configuration on netwroking devices.
3+
Collection of ansible modules that use [napalm](https://github.com/napalm-automation/napalm) to retrieve data or modify configuration on networking devices.
54

65
Modules
76
=======
8-
The following modules are currenty available:
9-
- napalm_get_facts
10-
- napalm_install_config
11-
- napalm_validate
7+
8+
The following modules are currently available:
9+
10+
- ``napalm_diff_yang``
11+
- ``napalm_get_facts``
12+
- ``napalm_install_config``
13+
- ``napalm_parse_yang``
14+
- ``napalm_ping``
15+
- ``napalm_translate_yang``
16+
- ``napalm_validate``
1217

1318
Install
1419
=======
15-
To install, clone the library directory into your ansible path.
1620

17-
OR
21+
To install just run the command:
1822

19-
Add the following in requirements.yml
20-
```
21-
- src: https://github.com/napalm-automation/napalm-ansible/
22-
version: master
23-
name: napalm
24-
path: roles
2523
```
26-
Then execute:
24+
pip install napalm-ansible
2725
```
28-
ansible-galaxy install -r requirements.yml --force
26+
27+
Configuring ansible
28+
===================
29+
30+
Once you have installed ``napalm-ansible`` run the command ``napalm-ansible`` and follow the instructions. For example::
31+
2932
```
33+
$ napalm-ansible
34+
To make sure ansible can make use of the napalm modules you will have
35+
to add the following configurtion to your ansible configureation
36+
file, i.e. `./ansible.cfg`:
3037
31-
Dependencies
32-
=======
33-
* [napalm](https://github.com/napalm-automation/napalm) 1.00.0 or later
38+
[defaults]
39+
library = /Users/dbarroso/workspace/napalm/napalm-ansible/napalm_ansible
3440
41+
For more details on ansible's configuration file visit:
42+
https://docs.ansible.com/ansible/latest/intro_configuration.html
43+
```
3544

3645
Examples
3746
=======
47+
3848
Example to retreive facts from a device
3949
```
4050
- name: get facts from device
@@ -76,4 +86,4 @@ Example to get compliance report
7686
hostname: "{{ inventory_hostname }}"
7787
dev_os: "{{ dev_os }}"
7888
validation_file: validate.yml
79-
```
89+
```

library

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
napalm_ansible

meta/main.yml

-17
This file was deleted.

napalm_ansible/__init__.py

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import os
2+
3+
message = """
4+
To make sure ansible can make use of the napalm modules you will have
5+
to add the following configurtion to your ansible configureation
6+
file, i.e. `./ansible.cfg`:
7+
8+
[defaults]
9+
library = {path}
10+
11+
For more details on ansible's configuration file visit:
12+
https://docs.ansible.com/ansible/latest/intro_configuration.html
13+
"""
14+
15+
16+
def main():
17+
path = os.path.dirname(__file__)
18+
print(message.format(path=path).strip())

napalm_ansible/napalm_cli.py

+146
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
from ansible.module_utils.basic import AnsibleModule, return_values
2+
3+
4+
DOCUMENTATION = '''
5+
---
6+
module: napalm_cli
7+
author: "Charlie Allom - based on napalm_ping Jason Edelman (@jedelman8)"
8+
version_added: "2.2"
9+
short_description: "Executes CLI commands and returns response using NAPALM"
10+
description:
11+
- "This module logs into the device, issues a ping request, and returns the response"
12+
requirements:
13+
- napalm
14+
options:
15+
args:
16+
description:
17+
- Keyword arguments to pass to the `cli` method
18+
required: True
19+
'''
20+
21+
EXAMPLES = '''
22+
vars:
23+
napalm_provider:
24+
hostname: "{{ inventory_hostname }}"
25+
username: "napalm"
26+
password: "napalm"
27+
dev_os: "eos"
28+
- napalm_cli:
29+
provider: "{{ napalm_provider }}"
30+
args:
31+
commands:
32+
- show version
33+
- show snmp chassis
34+
'''
35+
36+
RETURN = '''
37+
changed:
38+
description: ALWAYS RETURNS FALSE
39+
returned: always
40+
type: bool
41+
sample: True
42+
results:
43+
description: string of command output
44+
returned: always
45+
type: dict
46+
sample:
47+
{
48+
"show snmp chassis": "Chassis: 1234\n",
49+
"show version": "Arista vEOS\nHardware version: \nSerial number: \nSystem MAC address: 0800.27c3.5f28\n\nSoftware image version: 4.17.5M\nArchitecture: i386\nInternal build version: 4.17.5M-4414219.4175M\nInternal build ID: d02143c6-e42b-4fc3-99b6-97063bddb6b8\n\nUptime: 1 hour and 21 minutes\nTotal memory: 1893416 kB\nFree memory: 956488 kB\n\n" # noqa
50+
}
51+
'''
52+
53+
try:
54+
from napalm_base import get_network_driver
55+
except ImportError:
56+
napalm_found = False
57+
else:
58+
napalm_found = True
59+
60+
61+
def main():
62+
os_choices = ['eos', 'junos', 'iosxr', 'fortios',
63+
'ios', 'mock', 'nxos', 'panos', 'vyos', 'ros']
64+
module = AnsibleModule(
65+
argument_spec=dict(
66+
hostname=dict(type='str', required=False, aliases=['host']),
67+
username=dict(type='str', required=False),
68+
password=dict(type='str', required=False, no_log=True),
69+
provider=dict(type='dict', required=False),
70+
timeout=dict(type='int', required=False, default=60),
71+
dev_os=dict(type='str', required=False, choices=os_choices),
72+
optional_args=dict(required=False, type='dict', default=None),
73+
args=dict(required=True, type='dict', default=None),
74+
),
75+
supports_check_mode=False
76+
)
77+
78+
if not napalm_found:
79+
module.fail_json(msg="the python module napalm is required")
80+
81+
provider = module.params['provider'] or {}
82+
83+
no_log = ['password', 'secret']
84+
for param in no_log:
85+
if provider.get(param):
86+
module.no_log_values.update(return_values(provider[param]))
87+
if provider.get('optional_args') and provider['optional_args'].get(param):
88+
module.no_log_values.update(return_values(provider['optional_args'].get(param)))
89+
if module.params.get('optional_args') and module.params['optional_args'].get(param):
90+
module.no_log_values.update(return_values(module.params['optional_args'].get(param)))
91+
92+
# allow host or hostname
93+
provider['hostname'] = provider.get('hostname', None) or provider.get('host', None)
94+
# allow local params to override provider
95+
for param, pvalue in provider.items():
96+
if module.params.get(param) is not False:
97+
module.params[param] = module.params.get(param) or pvalue
98+
99+
hostname = module.params['hostname']
100+
username = module.params['username']
101+
dev_os = module.params['dev_os']
102+
password = module.params['password']
103+
timeout = module.params['timeout']
104+
args = module.params['args']
105+
106+
argument_check = {'hostname': hostname, 'username': username,
107+
'dev_os': dev_os, 'password': password}
108+
for key, val in argument_check.items():
109+
if val is None:
110+
module.fail_json(msg=str(key) + " is required")
111+
112+
# use checks outside of ansible defined checks, since params come can come from provider
113+
if dev_os not in os_choices:
114+
module.fail_json(msg="dev_os is not set to " + str(os_choices))
115+
116+
if module.params['optional_args'] is None:
117+
optional_args = {}
118+
else:
119+
optional_args = module.params['optional_args']
120+
121+
try:
122+
network_driver = get_network_driver(dev_os)
123+
device = network_driver(hostname=hostname,
124+
username=username,
125+
password=password,
126+
timeout=timeout,
127+
optional_args=optional_args)
128+
device.open()
129+
except Exception, e:
130+
module.fail_json(msg="cannot connect to device: " + str(e))
131+
132+
try:
133+
cli_response = device.cli(**args)
134+
except Exception as e:
135+
module.fail_json(msg="{}".format(e))
136+
137+
try:
138+
device.close()
139+
except Exception, e:
140+
module.fail_json(msg="cannot close device connection: " + str(e))
141+
142+
module.exit_json(changed=False, results=cli_response)
143+
144+
145+
if __name__ == '__main__':
146+
main()
File renamed without changes.

0 commit comments

Comments
 (0)