cisco_node_utils 0.9.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c811008424906279c5c89cb82653b6367c6ee8d8
4
- data.tar.gz: 7ffc3ebadb167bb07f35edc267dd44588b5c0d41
3
+ metadata.gz: 1c5b07b6e931c42203329e0218d507395d58bf0a
4
+ data.tar.gz: a52112854a11a4aa1053010a92edf7bbe2607c35
5
5
  SHA512:
6
- metadata.gz: f40b4f8cd2f4711511458b3a02b48e8a1488cdb02d2174bf9ad66a4febb78e5915317937b3ec701ebaa128edd50cf49216fa2d572e04c792bd81fa351b9bffca
7
- data.tar.gz: 5d4dd8cfdb95ccca0ab67e3fa18d20ce1bb336dc3a625e2d73c3cc1931df0192150ae0614f7b0ddba7165941416f831926e853ddaa0de9c6b79f46ffc2c205c5
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
- # Contributing
2
-
3
- ## Submitting an Issue
4
-
5
- Issues are tracked on GitHub (TODO).
6
-
7
- ## Developing a new Feature Provider
8
-
9
- 1. Create a new class file in `lib/cisco_node_utils/`.
10
- 2. Write the class.
11
- 3. Add the class to `lib/cisco_node_utils.rb`.
12
- 4. Create a new minitest file in `tests/`.
13
- 5. Write the minitest. We recommend subclassing the provided `CiscoTestCase`
14
- class as it provides numerous helper methods.
15
- 6. Run the minitest. `ruby test_my_feature.rb -- <NX-OS node IP> <user> <pass>`
16
- 7. Once minitest is passing, add the test to `tests/test_all_cisco.rb`.
17
- 8. Run rubocop (`rake rubocop`) and fix any failures.
18
- 9. Proceed to submit a pull request as described below.
19
-
20
- ## Submitting a Pull Request
21
-
22
- 1. Fork the code (https://github.com/cisco/cisco_node_utils/fork) (TODO)
23
- 2. Create your feature branch (`git checkout -b my-new-feature`)
24
- 3. Write your code
25
- 4. Write minitest cases to cover your new code
26
- 5. Verify that minitest passes in full (`ruby tests/test_all_cisco.rb --
27
- n3k_test.mycompany.com username password`)
28
- 6. Verify that rubocop also passes (`rake rubocop`).
29
- 7. Commit your changes (`git commit -am 'Add some feature'`)
30
- 8. Push to the branch (`git push origin my-new-feature`)
31
- 9. Create a new Pull Request
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
@@ -0,0 +1,3 @@
1
+ Cisco Node Utils GEM is supported by Cisco Partners and Cisco Systems.
2
+
3
+ Please report any issues with this module to [https://github.com/cisco/cisco-network-node-utils/issues](https://github.com/cisco/cisco-network-node-utils/issues)
@@ -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', '>= 0.9'
29
+ spec.add_runtime_dependency 'cisco_nxapi', '~> 1.0'
30
30
  end
data/docs/.rubocop.yml ADDED
@@ -0,0 +1,13 @@
1
+ # Rubocop configuration
2
+
3
+ inherit_from: ../.rubocop.yml
4
+
5
+ Style/ClassAndModuleCamelCase:
6
+ Enabled: false
7
+
8
+ Style/FileName:
9
+ Enabled: false
10
+
11
+ Metrics/LineLength:
12
+ Enabled: false
13
+
@@ -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
+ ![1](agent_files.png)
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.