cisco_node_utils 0.9.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +22 -0
- data/CONTRIBUTING.md +33 -31
- data/SUPPORT.md +3 -0
- data/cisco_node_utils.gemspec +1 -1
- data/docs/.rubocop.yml +13 -0
- data/docs/README-develop-node-utils-APIs.md +659 -0
- data/docs/README-maintainers.md +78 -0
- data/docs/agent_files.png +0 -0
- data/docs/template-feature.rb +45 -0
- data/docs/template-router.rb +125 -0
- data/docs/template-test_feature.rb +51 -0
- data/docs/template-test_router.rb +107 -0
- data/lib/cisco_node_utils/command_reference_common.yaml +42 -1
- data/lib/cisco_node_utils/interface.rb +106 -0
- data/lib/cisco_node_utils/interface_ospf.rb +17 -3
- data/lib/cisco_node_utils/node.rb +2 -2
- data/lib/cisco_node_utils/router_ospf_vrf.rb +12 -0
- data/lib/cisco_node_utils/version.rb +1 -1
- data/lib/cisco_node_utils/vtp.rb +21 -12
- data/lib/cisco_node_utils/yum.rb +16 -6
- data/tests/n9000_sample-1.0.0-7.0.3.x86_64.rpm +0 -0
- data/tests/test_interface.rb +149 -7
- data/tests/test_interface_ospf.rb +33 -1
- data/tests/test_interface_switchport.rb +104 -1
- data/tests/test_router_ospf_vrf.rb +12 -0
- data/tests/test_snmpuser.rb +1 -1
- data/tests/test_vtp.rb +64 -48
- data/tests/test_yum.rb +11 -7
- metadata +32 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1c5b07b6e931c42203329e0218d507395d58bf0a
|
4
|
+
data.tar.gz: a52112854a11a4aa1053010a92edf7bbe2607c35
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2af0852642d24be931c1700b685d236a123717496c7526dc10753725c85a62f31981017b98ce82022e2117481f88273a989e078c83fd32f54e1b2c4d65b94d04
|
7
|
+
data.tar.gz: 866dd382c29fd0cecfb9162fae84980dd35138b926a2d72ee34caad204df691d7db0eec1056a9cb2f8eb2406b97643a67b1f17958627033c41c93d7e52ad9a71
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,25 @@
|
|
1
|
+
Changelog
|
2
|
+
=========
|
3
|
+
|
4
|
+
1.0.0
|
5
|
+
-----
|
6
|
+
|
7
|
+
* Improved logic in Vtp class to handle the presence or absence of
|
8
|
+
'feature vtp' and 'vtp domain' configuration.
|
9
|
+
* Fixed missing `default_timer_throttle_*` APIs in RouterOspfVrf class.
|
10
|
+
* Fixed idempotency and area update issues in interface_ospf class.
|
11
|
+
* Updated CliError class definition to make it easier to troubleshoot such
|
12
|
+
errors when running Puppet modules that use this gem.
|
13
|
+
* Added dotted-decimal munging for the area getter in interface_ospf.
|
14
|
+
* Added n9000_sample*.rpm to /tests for use with minitests.
|
15
|
+
* Updated yum install method to include vrf, fixes minitest issue.
|
16
|
+
* Extended cisco_interface with the following attributes:
|
17
|
+
* encapsulation dot1q
|
18
|
+
* mtu
|
19
|
+
* switchport trunk allowed and native vlans
|
20
|
+
* vrf member
|
21
|
+
* Move misc READMEs into /docs
|
22
|
+
|
1
23
|
0.9.0
|
2
24
|
-----
|
3
25
|
|
data/CONTRIBUTING.md
CHANGED
@@ -1,31 +1,33 @@
|
|
1
|
-
#
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
1
|
+
# How to contribute
|
2
|
+
Cisco Network Elements support a rich set of features to make networks robust, efficient and secure. The GitHub project [cisco-network-puppet-module](https://github.com/cisco/cisco-network-puppet-module) defines a set of Puppet resource types and providers to manage the network element. Similarly, the GitHub project [cisco-network-chef-cookbook](https://github.com/cisco/cisco-network-chef-cookbook) defines a set of Chef resources and providers for network element management. The providers defined in these projects leverage a common set of Ruby API Objects defined in this project. This object set is expected to grow with contributions from Cisco, Cisco-Partners and third-party alike. Contributions to this project are welcome. To ensure code quality, contributors will be requested to follow few guidelines.
|
3
|
+
|
4
|
+
## Getting Started
|
5
|
+
|
6
|
+
* Create a [GitHub account](https://github.com/signup/free)
|
7
|
+
* Create a [cisco.com](http://cisco.com) account if you need access to a Network Simulator to test your code.
|
8
|
+
|
9
|
+
## Making Changes
|
10
|
+
|
11
|
+
* Fork the repository
|
12
|
+
* Pull a branch under the "develop" branch for your changes.
|
13
|
+
* Follow all guidelines documented in [README-creating-node_utils-APIs](#README-creating-node_utils-APIs.md)
|
14
|
+
* Make changes in your branch.
|
15
|
+
* Testing
|
16
|
+
* Create a minitest for new APIs or new functionality
|
17
|
+
* Run all the tests to ensure there was no collateral damage to existing code
|
18
|
+
* Committing
|
19
|
+
* Check for unnecessary whitespace with `git diff --check` before committing.
|
20
|
+
* Run `rubocop --lint` against all changed files. See [https://rubygems.org/gems/rubocop](https://rubygems.org/gems/rubocop)
|
21
|
+
* Make sure your commit messages clearly describe the problem you are trying to solve and the proposed solution.
|
22
|
+
|
23
|
+
## Submitting Changes
|
24
|
+
|
25
|
+
* All contributions you submit to this project are voluntary and subject to the terms of the Apache 2.0 license
|
26
|
+
* Submit a pull request to the repository
|
27
|
+
* A core team consisting of Cisco and Cisco-Partner employees will looks at Pull Request and provide feedback.
|
28
|
+
* After feedback has been given we expect responses within two weeks. After two weeks we may close the pull request if it isn't showing any activity.
|
29
|
+
|
30
|
+
# Additional Resources
|
31
|
+
|
32
|
+
* [General GitHub documentation](http://help.github.com/)
|
33
|
+
* [GitHub pull request documentation](http://help.github.com/send-pull-requests/)
|
data/SUPPORT.md
ADDED
data/cisco_node_utils.gemspec
CHANGED
@@ -26,5 +26,5 @@ Currently supports NX-OS nodes.
|
|
26
26
|
spec.add_development_dependency 'bundler', '~> 1.7'
|
27
27
|
spec.add_development_dependency 'rake', '~> 10.0'
|
28
28
|
spec.add_development_dependency 'rubocop', '>= 0.32'
|
29
|
-
spec.add_runtime_dependency 'cisco_nxapi', '
|
29
|
+
spec.add_runtime_dependency 'cisco_nxapi', '~> 1.0'
|
30
30
|
end
|
data/docs/.rubocop.yml
ADDED
@@ -0,0 +1,659 @@
|
|
1
|
+
# How To Create New node_utils APIs
|
2
|
+
|
3
|
+
#### Table of Contents
|
4
|
+
|
5
|
+
* [Overview](#overview)
|
6
|
+
* [Start here: Clone the Repo](#clone)
|
7
|
+
* [Basic Example: feature bash-shell](#simple)
|
8
|
+
* [Step 1. YAML Definitions: feature bash-shell](#yaml)
|
9
|
+
* [Step 2. Create the node_utils API: feature bash-shell](#api)
|
10
|
+
* [Step 3. Create the Minitest: feature bash-shell](#minitest)
|
11
|
+
* [Step 4. rubocop / lint: feature bash-shell](#lint)
|
12
|
+
* [Advanced Example: router eigrp](#complex)
|
13
|
+
* [Step 1. YAML Definitions: router eigrp](#comp_yaml)
|
14
|
+
* [Step 2. Create the node_utils API: router eigrp](#comp_api)
|
15
|
+
* [Step 3. Create the Minitest: router eigrp](#comp_minitest)
|
16
|
+
* [Step 4. rubocop / lint: router eigrp](#comp_lint)
|
17
|
+
|
18
|
+
## <a name="overview">Overview</a>
|
19
|
+
|
20
|
+
This document is a HowTo guide for writing new cisco node_utils APIs. The node_utils APIs act as an interface between the NX-OS CLI and an agent's resource/provider. If written properly the new API will work as a common framework for multiple providers (Puppet, Chef, etc).
|
21
|
+
|
22
|
+
There are multiple components involved when creating new resources. This document focuses on the cisco node_utils API, command reference YAML files, and minitests.
|
23
|
+
|
24
|
+

|
25
|
+
|
26
|
+
## <a name="clone">Start here: Clone the Repo</a>
|
27
|
+
|
28
|
+
First install the code base. Clone the cisco_node_utils repo into a workspace:
|
29
|
+
|
30
|
+
```bash
|
31
|
+
git clone https://github.com/cisco/cisco-network-node-utils.git
|
32
|
+
```
|
33
|
+
|
34
|
+
## <a name="simple">Basic Example: feature bash-shell</a>
|
35
|
+
|
36
|
+
Writing a new node_utils API is often easier to understand through example code. The NX-OS CLI for `feature bash-shell` is a simple on / off style configuration and therefore a good candidate for a simple API:
|
37
|
+
|
38
|
+
`[no] feature bash-shell`
|
39
|
+
|
40
|
+
### <a name="yaml">Step 1. YAML Definitions: feature bash-shell</a>
|
41
|
+
|
42
|
+
The new API will need some basic YAML definitions. These are used with the `CommandReference` module as a way to abstract away platform CLI differences.
|
43
|
+
|
44
|
+
`command_reference_common.yaml` is used for settings that are common across all platforms while other files are used for settings that are unique to a given platform. Our `feature bash-shell` example uses the same cli syntax on all platforms, thus we only need to edit the common file:
|
45
|
+
|
46
|
+
`cisco_network_node_utils/lib/cisco_node_utils/command_reference_common.yaml`
|
47
|
+
|
48
|
+
Four basic command_reference parameters will be defined for each resource property:
|
49
|
+
|
50
|
+
1. `config_get:` This defines the NX-OS CLI command (usually a 'show...' command) used to retrieve the property's current configuration state. Note that some commands may not be present until a feature is enabled.
|
51
|
+
2. `config_get_token:` A regexp pattern for extracting state values from the config_get output.
|
52
|
+
3. `config_set:` The NX-OS CLI configuration command(s) used to set the property configuration. May contain wildcards for variable parameters.
|
53
|
+
4. `default_value:` This is typically the "factory" default state of the property, expressed as an actual value (true, 12, "off", etc)
|
54
|
+
|
55
|
+
There are additional YAML command parameters available which are not covered by this document. Please see the [README_YAML.md](../lib/cisco_node_utils/README_YAML.md) document for more information on the structure and semantics of these files.
|
56
|
+
|
57
|
+
#### Example: YAML Property Definitions for feature bash-shell
|
58
|
+
|
59
|
+
The `feature bash-shell` configuration is displayed with the `show running-config` command. Anchor the config_get_token regexp pattern carefully as it may match on unwanted configurations.
|
60
|
+
|
61
|
+
*Note: YAML syntax has strict indentation rules. Do not use TABs.*
|
62
|
+
|
63
|
+
```
|
64
|
+
bash_shell:
|
65
|
+
feature:
|
66
|
+
config_get: 'show running' # get current bash config state
|
67
|
+
config_get_token: '/^feature bash-shell$/' # Match only 'feature bash-shell'
|
68
|
+
config_set: '<state> feature bash-shell' # Config needed to enable/disable
|
69
|
+
```
|
70
|
+
|
71
|
+
### <a name="api">Step 2. cisco_node_utils API file: feature bash-shell</a>
|
72
|
+
|
73
|
+
* Before creating the new API, first add a new entry: `require "cisco_node_utils/bash_shell"` to the master list of resources in:
|
74
|
+
|
75
|
+
```
|
76
|
+
cisco_network_node_utils/lib/cisco_node_utils.rb
|
77
|
+
```
|
78
|
+
|
79
|
+
* There are template files in /docs that may help when writing new APIs. These templates provide most of the necessary code with just a few customizations required for a new resource. Copy the `template-feature.rb` file to use as the basis for `bash_shell.rb`:
|
80
|
+
|
81
|
+
```bash
|
82
|
+
cp docs/template-feature.rb cisco_network_node_utils/bash_shell.rb
|
83
|
+
```
|
84
|
+
|
85
|
+
* Edit `bash_shell.rb` and substitute the placeholder text as shown here:
|
86
|
+
|
87
|
+
```bash
|
88
|
+
/X__CLASS_NAME__X/BashShell/
|
89
|
+
|
90
|
+
/X__RESOURCE_NAME__X/bash_shell/
|
91
|
+
```
|
92
|
+
|
93
|
+
#### Example: bash_shell.rb API
|
94
|
+
|
95
|
+
This is the completed bash_shell API based on `template-feature.rb`:
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
|
99
|
+
require File.join(File.dirname(__FILE__), 'node')
|
100
|
+
module Cisco
|
101
|
+
# Class name syntax will typically be the resource name in camelCase
|
102
|
+
# format; for example: 'tacacs server host' becomes TacacsServerHost.
|
103
|
+
class BashShell
|
104
|
+
# Establish connection to node
|
105
|
+
@@node = Cisco::Node.instance
|
106
|
+
|
107
|
+
def feature_enable
|
108
|
+
@@node.config_set('bash_shell', 'feature', { :state => '' })
|
109
|
+
end
|
110
|
+
|
111
|
+
def feature_disable
|
112
|
+
@@node.config_set('bash_shell', 'feature', { :state => 'no' })
|
113
|
+
end
|
114
|
+
|
115
|
+
# Check current state of the configuration
|
116
|
+
def BashShell.feature_enabled
|
117
|
+
feat = @@node.config_get('bash_shell', 'feature')
|
118
|
+
return (!feat.nil? and !feat.empty?)
|
119
|
+
rescue Cisco::CliError => e
|
120
|
+
# This cmd will syntax reject if feature is not
|
121
|
+
# enabled. Just catch the reject and return false.
|
122
|
+
return false if e.clierror =~ /Syntax error/
|
123
|
+
raise
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
```
|
128
|
+
|
129
|
+
### <a name="minitest">Step 3. Minitest: feature bash-shell</a>
|
130
|
+
|
131
|
+
* A minitest should be created to validate the new APIs. Minitests are stored in the tests directory: `cisco_network_node_utils/tests/`
|
132
|
+
|
133
|
+
* Tests may use `@device.cmd("show ...")` to access the CLI directly set up tests and validate expected outcomes. The tests directory contains many examples of how these are used.
|
134
|
+
|
135
|
+
* Our minitest will be very basic since the API itself is very basic. Use `template-test_feature.rb` to create a minitest for the bash_shell resource:
|
136
|
+
|
137
|
+
```bash
|
138
|
+
cp docs/template-test_feature.rb cisco_network_node_utils/tests/test_bash_shell.rb
|
139
|
+
```
|
140
|
+
|
141
|
+
* As with the API code, edit `test_bash_shell.rb` and change the placeholder names as shown:
|
142
|
+
|
143
|
+
```bash
|
144
|
+
/X__CLASS_NAME__X/BashShell/
|
145
|
+
|
146
|
+
/X__RESOURCE_NAME__X/bash_shell/
|
147
|
+
|
148
|
+
/X__CLI_NAME__X/bash-shell/
|
149
|
+
```
|
150
|
+
|
151
|
+
#### Example: test_bash_shell.rb
|
152
|
+
|
153
|
+
This is the completed `bash_shell` minitest based on `template-test_feature.rb`:
|
154
|
+
|
155
|
+
```ruby
|
156
|
+
#
|
157
|
+
# Minitest for BashShell class
|
158
|
+
#
|
159
|
+
# Copyright (c) 2014-2015 Cisco and/or its affiliates.
|
160
|
+
#
|
161
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
162
|
+
# you may not use this file except in compliance with the License.
|
163
|
+
# You may obtain a copy of the License at
|
164
|
+
#
|
165
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
166
|
+
#
|
167
|
+
# Unless required by applicable law or agreed to in writing, software
|
168
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
169
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
170
|
+
# See the License for the specific language governing permissions and
|
171
|
+
# limitations under the License.
|
172
|
+
|
173
|
+
require File.expand_path("../ciscotest", __FILE__)
|
174
|
+
require File.expand_path("../../lib/cisco_node_utils/bash_shell", __FILE__)
|
175
|
+
|
176
|
+
class TestBashShell < CiscoTestCase
|
177
|
+
def setup
|
178
|
+
# setup automatically runs at the beginning of each test
|
179
|
+
super
|
180
|
+
no_feature
|
181
|
+
end
|
182
|
+
|
183
|
+
def teardown
|
184
|
+
# teardown automatically runs at the end of each test
|
185
|
+
no_feature
|
186
|
+
super
|
187
|
+
end
|
188
|
+
|
189
|
+
def no_feature
|
190
|
+
# setup/teardown helper. Turn the feature off for a clean testbed.
|
191
|
+
@device.cmd('conf t ; no feature bash-shell ; end')
|
192
|
+
node.cache_flush()
|
193
|
+
end
|
194
|
+
|
195
|
+
def test_feature_on_off
|
196
|
+
feat = BashShell.new()
|
197
|
+
feat.feature_enable
|
198
|
+
assert(BashShell.feature_enabled)
|
199
|
+
|
200
|
+
feat.feature_disable
|
201
|
+
refute(BashShell.feature_enabled)
|
202
|
+
end
|
203
|
+
|
204
|
+
end
|
205
|
+
```
|
206
|
+
|
207
|
+
|
208
|
+
We can now run the new minitest against our NX-OS device using this syntax:
|
209
|
+
|
210
|
+
```bash
|
211
|
+
ruby test_bash_shell.rb -- <node_ip_address> <user> <passwd>
|
212
|
+
```
|
213
|
+
*Note. The minitest requires that the NX-OS device have 'feature nxapi' enabled. This will typically be enabled by default.*
|
214
|
+
|
215
|
+
#### Example: Running bash_shell minitest
|
216
|
+
|
217
|
+
```bash
|
218
|
+
% ruby test_bash_shell.rb -- 192.168.0.1 admin admin
|
219
|
+
Run options: -v -- --seed 23392
|
220
|
+
|
221
|
+
# Running tests:
|
222
|
+
|
223
|
+
CiscoTestCase#test_placeholder =
|
224
|
+
Ruby Version - 1.9.3
|
225
|
+
Node in CiscoTestCase Class: 192.168.0.1
|
226
|
+
Platform:
|
227
|
+
- name - my_n9k
|
228
|
+
- type - N9K-C9504
|
229
|
+
- image - bootflash:///n9000-dk9.7.0.3.I2.0.509.bin
|
230
|
+
|
231
|
+
1.79 s = .
|
232
|
+
TestBashShell#test_feature_on_off = 1.42 s = .
|
233
|
+
TestBashShell#test_placeholder = 0.95 s = .
|
234
|
+
TestCase#test_placeholder = 0.81 s = .
|
235
|
+
|
236
|
+
Finished tests in 4.975186s, 0.8040 tests/s, 0.4020 assertions/s.
|
237
|
+
|
238
|
+
4 tests, 2 assertions, 0 failures, 0 errors, 0 skips
|
239
|
+
```
|
240
|
+
|
241
|
+
*Note. The minitest harness counts the helper methods as tests which is why the final tally shows 4 tests instead of just 2 tests.*
|
242
|
+
|
243
|
+
### <a name="lint">Step 3. rubocop / lint: feature bash-shell</a>
|
244
|
+
|
245
|
+
rubocop is a Ruby static analysis tool. Run rubocop with the --lint option to validate the new API:
|
246
|
+
|
247
|
+
```bash
|
248
|
+
% rubocop --lint bash_shell.rb
|
249
|
+
Inspecting 1 file
|
250
|
+
.
|
251
|
+
|
252
|
+
1 file inspected, no offenses detected
|
253
|
+
```
|
254
|
+
|
255
|
+
## <a name="complex">Advanced Example: router eigrp</a>
|
256
|
+
|
257
|
+
Now that we have a basic example working we can move on to a slightly more complex cli.
|
258
|
+
`router eigrp` requires feature enablement and supports multiple eigrp instances. It also has multiple configuration levels for vrf and address-family.
|
259
|
+
|
260
|
+
For the purposes of this example we will only implement the following properties:
|
261
|
+
|
262
|
+
```bash
|
263
|
+
[no] feature eigrp (boolean)
|
264
|
+
[no] router eigrp [name] (string)
|
265
|
+
maximum-paths [n] (integer)
|
266
|
+
[no] shutdown (boolean)
|
267
|
+
|
268
|
+
Example:
|
269
|
+
feature eigrp
|
270
|
+
router eigrp Blue
|
271
|
+
maximum-paths 5
|
272
|
+
shutdown
|
273
|
+
```
|
274
|
+
|
275
|
+
### <a name="comp_yaml">Step 1. YAML Definitions: router eigrp</a>
|
276
|
+
|
277
|
+
As with the earlier example, `router eigrp` will need YAML definitions in the common file:
|
278
|
+
|
279
|
+
`cisco_network_node_utils/lib/cisco_node_utils/command_reference_common.yaml`
|
280
|
+
|
281
|
+
The properties in this example require additional context for their config_get_token values because they need to differentiate between different eigrp instances. Most properties will also have a default value.
|
282
|
+
|
283
|
+
*Note: Eigrp also has vrf and address-family contexts. These contexts require additional coding and are beyond the scope of this document.*
|
284
|
+
|
285
|
+
#### Example: YAML Property Definitions for router eigrp
|
286
|
+
|
287
|
+
*Note: The basic token definitions for multi-level commands can become long and complicated. A better solution for these commands is to use a command_reference _template: definition to simplify the configuration. The example below will use the basic syntax; see the ospf definitions in the YAML file for an example of _template: usage.*
|
288
|
+
|
289
|
+
```yaml
|
290
|
+
eigrp:
|
291
|
+
feature:
|
292
|
+
# feature eigrp must be enabled before configuring router eigrp
|
293
|
+
config_get: 'show running eigrp all'
|
294
|
+
config_get_token: '/^feature eigrp$/'
|
295
|
+
config_set: '<state> feature eigrp'
|
296
|
+
|
297
|
+
router:
|
298
|
+
# There can be multiple eigrp instances
|
299
|
+
config_get: 'show running eigrp all' # all eigrp-related configs
|
300
|
+
config_get_token: '/^router eigrp (\S+)$/' # Match instance name
|
301
|
+
config_set: '<state> router eigrp <name>' # config to add or remove
|
302
|
+
|
303
|
+
maximum_paths:
|
304
|
+
# This is an integer property
|
305
|
+
config_get: 'show running eigrp all'
|
306
|
+
config_get_token: ['/^router eigrp <name>$/', '/^maximum-paths (\d+)/']
|
307
|
+
config_set: ['router eigrp <name>', 'maximum-paths <val>']
|
308
|
+
default_value: 8
|
309
|
+
|
310
|
+
shutdown:
|
311
|
+
# This is a boolean property
|
312
|
+
config_get: 'show running eigrp all'
|
313
|
+
config_get_token: ['/^router eigrp <name>$/', '/^shutdown$/']
|
314
|
+
config_set: ['router eigrp <name>', '<state> shutdown']
|
315
|
+
default_value: false
|
316
|
+
```
|
317
|
+
|
318
|
+
### <a name="comp_api">Step 2. cisco_node_utils API: router eigrp</a>
|
319
|
+
|
320
|
+
* Add a new entry: `require "cisco_node_utils/router_eigrp"` to the master list in:
|
321
|
+
|
322
|
+
```
|
323
|
+
cisco_network_node_utils/lib/cisco_node_utils.rb
|
324
|
+
```
|
325
|
+
|
326
|
+
* The `template-router.rb` file provides a basic router API that we will use as the basis for `router_eigrp.rb`:
|
327
|
+
|
328
|
+
```bash
|
329
|
+
cp docs/template-router.rb cisco_network_node_utils/router_eigrp.rb
|
330
|
+
```
|
331
|
+
|
332
|
+
* Our new `router_eigrp.rb` requires changes from the original template. Edit `router_eigrp.rb` and change the placeholder names as shown.
|
333
|
+
|
334
|
+
```
|
335
|
+
/X__CLASS_NAME__X/RouterEigrp/
|
336
|
+
|
337
|
+
/X__RESOURCE_NAME__X/eigrp/
|
338
|
+
|
339
|
+
/X__PROPERTY_BOOL__X/shutdown/
|
340
|
+
|
341
|
+
/X__PROPERTY_INT__X/maximum_paths/
|
342
|
+
```
|
343
|
+
|
344
|
+
*Note that this template only provides example property methods for a few properties. Copy the example methods for additional properties as needed.*
|
345
|
+
|
346
|
+
#### Example: router_eigrp.rb
|
347
|
+
This is the completed `router_eigrp` API based on `template-router.rb`:
|
348
|
+
|
349
|
+
```ruby
|
350
|
+
#
|
351
|
+
# NXAPI implementation of RouterEigrp class
|
352
|
+
#
|
353
|
+
# Copyright (c) 2014-2015 Cisco and/or its affiliates.
|
354
|
+
#
|
355
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
356
|
+
# you may not use this file except in compliance with the License.
|
357
|
+
# You may obtain a copy of the License at
|
358
|
+
#
|
359
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
360
|
+
#
|
361
|
+
# Unless required by applicable law or agreed to in writing, software
|
362
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
363
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
364
|
+
# See the License for the specific language governing permissions and
|
365
|
+
# limitations under the License.
|
366
|
+
|
367
|
+
require File.join(File.dirname(__FILE__), 'node')
|
368
|
+
|
369
|
+
module Cisco
|
370
|
+
class RouterEigrp
|
371
|
+
attr_reader :name
|
372
|
+
|
373
|
+
# Establish connection to node
|
374
|
+
@@node = Cisco::Node.instance
|
375
|
+
|
376
|
+
# name: name of the router instance
|
377
|
+
# instantiate: true = create router instance
|
378
|
+
def initialize(name, instantiate=true)
|
379
|
+
raise ArgumentError unless name.length > 0
|
380
|
+
@name = name
|
381
|
+
create if instantiate
|
382
|
+
end
|
383
|
+
|
384
|
+
# Create a hash of all current router instances.
|
385
|
+
def RouterEigrp.routers
|
386
|
+
instances = @@node.config_get('eigrp', 'router')
|
387
|
+
return {} if instances.nil?
|
388
|
+
hash = {}
|
389
|
+
instances.each do |name|
|
390
|
+
hash[name] = RouterEigrp.new(name, false)
|
391
|
+
end
|
392
|
+
return hash
|
393
|
+
rescue Cisco::CliError => e
|
394
|
+
# cmd will syntax reject when feature is not enabled
|
395
|
+
raise unless e.clierror =~ /Syntax error/
|
396
|
+
return {}
|
397
|
+
end
|
398
|
+
|
399
|
+
def feature_enabled
|
400
|
+
feat = @@node.config_get('eigrp', 'feature')
|
401
|
+
return (!feat.nil? and !feat.empty?)
|
402
|
+
rescue Cisco::CliError => e
|
403
|
+
# This cmd will syntax reject if feature is not
|
404
|
+
# enabled. Just catch the reject and return false.
|
405
|
+
return false if e.clierror =~ /Syntax error/
|
406
|
+
raise
|
407
|
+
end
|
408
|
+
|
409
|
+
def feature_enable
|
410
|
+
@@node.config_set('eigrp', 'feature', { :state => '' })
|
411
|
+
end
|
412
|
+
|
413
|
+
def feature_disable
|
414
|
+
@@node.config_set('eigrp', 'feature', { :state => 'no' })
|
415
|
+
end
|
416
|
+
|
417
|
+
# Enable feature and create router instance
|
418
|
+
def create
|
419
|
+
feature_enable unless feature_enabled
|
420
|
+
eigrp_router
|
421
|
+
end
|
422
|
+
|
423
|
+
# Destroy a router instance; disable feature on last instance
|
424
|
+
def destroy
|
425
|
+
ids = @@node.config_get('eigrp', 'router')
|
426
|
+
return if ids.nil?
|
427
|
+
if ids.size == 1
|
428
|
+
feature_disable
|
429
|
+
else
|
430
|
+
eigrp_router('no')
|
431
|
+
end
|
432
|
+
rescue Cisco::CliError => e
|
433
|
+
# cmd will syntax reject when feature is not enabled
|
434
|
+
raise unless e.clierror =~ /Syntax error/
|
435
|
+
end
|
436
|
+
|
437
|
+
def eigrp_router(state='')
|
438
|
+
@@node.config_set('eigrp', 'router', { :name => @name, :state => state })
|
439
|
+
end
|
440
|
+
|
441
|
+
# ----------
|
442
|
+
# PROPERTIES
|
443
|
+
# ----------
|
444
|
+
|
445
|
+
# Property methods for boolean property
|
446
|
+
def default_shutdown
|
447
|
+
@@node.config_get_default('eigrp', 'shutdown')
|
448
|
+
end
|
449
|
+
|
450
|
+
def shutdown
|
451
|
+
state = @@node.config_get('eigrp', 'shutdown', { :name => @name })
|
452
|
+
state ? true : false
|
453
|
+
end
|
454
|
+
|
455
|
+
def shutdown=(state)
|
456
|
+
state = (state ? '' : 'no')
|
457
|
+
@@node.config_set('eigrp', 'shutdown', { :name => @name, :state => state })
|
458
|
+
end
|
459
|
+
|
460
|
+
# Property methods for integer property
|
461
|
+
def default_maximum_paths
|
462
|
+
@@node.config_get_default('eigrp', 'maximum_paths')
|
463
|
+
end
|
464
|
+
|
465
|
+
def maximum_paths
|
466
|
+
val = @@node.config_get('eigrp', 'maximum_paths', { :name => @name })
|
467
|
+
val.nil? ? default_maximum_paths : val.first.to_i
|
468
|
+
end
|
469
|
+
|
470
|
+
def maximum_paths=(val)
|
471
|
+
@@node.config_set('eigrp', 'maximum_paths', { :name => @name, :val => val })
|
472
|
+
end
|
473
|
+
|
474
|
+
end
|
475
|
+
end
|
476
|
+
```
|
477
|
+
|
478
|
+
### <a name="comp_api">Step 3. Minitest: router eigrp</a>
|
479
|
+
|
480
|
+
* Use `template-test_router.rb` to build the minitest for `router_eigrp.rb`:
|
481
|
+
|
482
|
+
```
|
483
|
+
cp docs/template-test_router.rb cisco_network_node_utils/tests/test_router_eigrp.rb
|
484
|
+
```
|
485
|
+
* As with the API code, edit `test_router_eigrp.rb` and change the placeholder names as shown:
|
486
|
+
|
487
|
+
```
|
488
|
+
/X__CLASS_NAME__X/RouterEigrp/
|
489
|
+
|
490
|
+
/X__RESOURCE_NAME__X/eigrp/
|
491
|
+
|
492
|
+
/X__PROPERTY_BOOL__X/shutdown/
|
493
|
+
|
494
|
+
/X__PROPERTY_INT__X/maximum_paths/
|
495
|
+
```
|
496
|
+
|
497
|
+
* At a minimum, the tests should include coverage for:
|
498
|
+
* creating & destroying a single `router eigrp` instance
|
499
|
+
* creating & destroying multiple `router eigrp` instances
|
500
|
+
* feature disablement when removing last `router eigrp`
|
501
|
+
* testing each property state
|
502
|
+
|
503
|
+
#### Example: test_router_eigrp.rb
|
504
|
+
This is the completed `test_router_eigrp` minitest based on `template-test_router.rb`:
|
505
|
+
|
506
|
+
```ruby
|
507
|
+
#
|
508
|
+
# Minitest for RouterEigrp class
|
509
|
+
#
|
510
|
+
# Copyright (c) 2014-2015 Cisco and/or its affiliates.
|
511
|
+
#
|
512
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
513
|
+
# you may not use this file except in compliance with the License.
|
514
|
+
# You may obtain a copy of the License at
|
515
|
+
#
|
516
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
517
|
+
#
|
518
|
+
# Unless required by applicable law or agreed to in writing, software
|
519
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
520
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
521
|
+
# See the License for the specific language governing permissions and
|
522
|
+
# limitations under the License.
|
523
|
+
|
524
|
+
require File.expand_path("../ciscotest", __FILE__)
|
525
|
+
require File.expand_path("../../lib/cisco_node_utils/router_eigrp", __FILE__)
|
526
|
+
|
527
|
+
class TestRouterEigrp < CiscoTestCase
|
528
|
+
def setup
|
529
|
+
# setup runs at the beginning of each test
|
530
|
+
super
|
531
|
+
no_feature_eigrp
|
532
|
+
end
|
533
|
+
|
534
|
+
def teardown
|
535
|
+
# teardown runs at the end of each test
|
536
|
+
no_feature_eigrp
|
537
|
+
super
|
538
|
+
end
|
539
|
+
|
540
|
+
def no_feature_eigrp
|
541
|
+
# Turn the feature off for a clean test.
|
542
|
+
@device.cmd("conf t ; no feature eigrp ; end")
|
543
|
+
node.cache_flush()
|
544
|
+
end
|
545
|
+
|
546
|
+
# TESTS
|
547
|
+
|
548
|
+
def test_router_create_destroy_one
|
549
|
+
id = "blue"
|
550
|
+
rtr = RouterEigrp.new(id)
|
551
|
+
s = @device.cmd("show runn | i 'router eigrp #{id}'")
|
552
|
+
assert_match(s, /^router eigrp #{id}$/,
|
553
|
+
"Error: failed to create router eigrp #{id}")
|
554
|
+
|
555
|
+
rtr.destroy
|
556
|
+
s = @device.cmd("show runn | i 'router eigrp #{id}'")
|
557
|
+
refute_match(s, /^router eigrp #{id}$/,
|
558
|
+
"Error: failed to destroy router eigrp #{id}")
|
559
|
+
|
560
|
+
s = @device.cmd("show runn | i 'feature eigrp'")
|
561
|
+
refute_match(s, /^feature eigrp$/,
|
562
|
+
"Error: failed to disable feature eigrp")
|
563
|
+
end
|
564
|
+
|
565
|
+
def test_router_create_destroy_multiple
|
566
|
+
id1 = "blue"
|
567
|
+
rtr1 = RouterEigrp.new(id1)
|
568
|
+
id2 = "red"
|
569
|
+
rtr2 = RouterEigrp.new(id2)
|
570
|
+
|
571
|
+
s = @device.cmd("show runn | i 'router eigrp'")
|
572
|
+
assert_match(s, /^router eigrp #{id1}$/)
|
573
|
+
assert_match(s, /^router eigrp #{id2}$/)
|
574
|
+
|
575
|
+
rtr1.destroy
|
576
|
+
s = @device.cmd("show runn | i 'router eigrp #{id1}'")
|
577
|
+
refute_match(s, /^router eigrp #{id1}$/,
|
578
|
+
"Error: failed to destroy router eigrp #{id1}")
|
579
|
+
|
580
|
+
rtr2.destroy
|
581
|
+
s = @device.cmd("show runn | i 'router eigrp #{id2}'")
|
582
|
+
refute_match(s, /^router eigrp #{id2}$/,
|
583
|
+
"Error: failed to destroy router eigrp #{id2}")
|
584
|
+
|
585
|
+
s = @device.cmd("show runn | i 'feature eigrp'")
|
586
|
+
refute_match(s, /^feature eigrp$/,
|
587
|
+
"Error: failed to disable feature eigrp")
|
588
|
+
end
|
589
|
+
|
590
|
+
def test_router_maximum_paths
|
591
|
+
id = "blue"
|
592
|
+
rtr = RouterEigrp.new(id)
|
593
|
+
val = 5 # This value depends on property bounds
|
594
|
+
rtr.maximum_paths = val
|
595
|
+
assert_equal(rtr.maximum_paths, val, "maximum_paths is not #{val}")
|
596
|
+
|
597
|
+
# Get default value from yaml
|
598
|
+
val = node.config_get_default("eigrp", "maximum_paths")
|
599
|
+
rtr.maximum_paths = val
|
600
|
+
assert_equal(rtr.maximum_paths, val, "maximum_paths is not #{val}")
|
601
|
+
end
|
602
|
+
|
603
|
+
def test_router_shutdown
|
604
|
+
id = "blue"
|
605
|
+
rtr = RouterEigrp.new(id)
|
606
|
+
rtr.shutdown = true
|
607
|
+
assert(rtr.shutdown, "shutdown state is not true")
|
608
|
+
|
609
|
+
rtr.shutdown = false
|
610
|
+
refute(rtr.shutdown, "shutdown state is not false")
|
611
|
+
end
|
612
|
+
end
|
613
|
+
```
|
614
|
+
|
615
|
+
Now run the test:
|
616
|
+
|
617
|
+
```bash
|
618
|
+
% ruby-1.9.3-p0 test_router_eigrp.rb -v -- 192.168.0.1 admin admin
|
619
|
+
Run options: -v -- --seed 56593
|
620
|
+
|
621
|
+
# Running tests:
|
622
|
+
|
623
|
+
CiscoTestCase#test_placeholder =
|
624
|
+
Ruby Version - 1.9.3
|
625
|
+
Node in CiscoTestCase Class: 192.168.0.1
|
626
|
+
Platform:
|
627
|
+
- name - my_n3k
|
628
|
+
- type - N3K-C3132Q-40GX
|
629
|
+
- image -
|
630
|
+
|
631
|
+
2.90 s = .
|
632
|
+
TestCase#test_placeholder = 0.92 s = .
|
633
|
+
TestRouterEigrp#test_placeholder = 0.97 s = .
|
634
|
+
TestRouterEigrp#test_router_create_destroy_multiple = 10.77 s = .
|
635
|
+
TestRouterEigrp#test_router_create_destroy_one = 6.14 s = .
|
636
|
+
TestRouterEigrp#test_router_maximum_paths = 9.41 s = .
|
637
|
+
TestRouterEigrp#test_router_shutdown = 6.40 s = .
|
638
|
+
|
639
|
+
|
640
|
+
Finished tests in 37.512356s, 0.1866 tests/s, 0.3199 assertions/s.
|
641
|
+
|
642
|
+
7 tests, 12 assertions, 0 failures, 0 errors, 0 skips
|
643
|
+
```
|
644
|
+
|
645
|
+
### <a name="comp_lint">Step 4. rubocop / lint: router eigrp</a>
|
646
|
+
|
647
|
+
rubocop is a Ruby static analysis tool. Run rubocop with the --lint option to validate the new API:
|
648
|
+
|
649
|
+
```bash
|
650
|
+
% rubocop --lint router_eigrp.rb
|
651
|
+
Inspecting 1 file
|
652
|
+
.
|
653
|
+
|
654
|
+
1 file inspected, no offenses detected
|
655
|
+
```
|
656
|
+
|
657
|
+
## Conclusion
|
658
|
+
|
659
|
+
This was hopefully a good introduction to writing a Cisco node_utils API. At this point you could continue adding properties or try your hand at writing Puppet or Chef provider code to utilize your new API.
|