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.
@@ -0,0 +1,78 @@
1
+ # Maintainers Guide
2
+
3
+ Guidelines for the core maintainers of the cisco-network-node-utils project - above and beyond the [general developer guidelines](https://github.com/cisco/cisco-network-node-utils/blob/master/CONTRIBUTING.md).
4
+
5
+ ## Accepting Pull Requests
6
+
7
+ * Is the pull request correctly submitted against `develop`?
8
+ * Does `rubocop` pass? (TODO - this will be part of our CI integration to run automatically)
9
+ * Is `CHANGELOG.md` updated appropriately?
10
+ * Are new minitests added? Do they provide sufficient coverage and consistent results?
11
+ * Do minitests pass on both N9K and N3K?
12
+
13
+ ## Setting up git-flow
14
+
15
+ If you don't already have [`git-flow`](https://github.com/petervanderdoes/gitflow/) installed, install it.
16
+
17
+ Either run `git flow init` from the repository root directory, or manually edit your `.git/config` file. Either way, when done, you should have the following in your config:
18
+
19
+ ```ini
20
+ [gitflow "branch"]
21
+ master = master
22
+ develop = develop
23
+ [gitflow "prefix"]
24
+ feature = feature/
25
+ release = release/
26
+ hotfix = hotfix/
27
+ support = support/
28
+ versiontag = v
29
+ ```
30
+
31
+ Most of these are default for git-flow except for the `versiontag` setting.
32
+
33
+ ## Release Process
34
+
35
+ When we agree as a team that a new release should be published, the process is as follows:
36
+
37
+ 1. Create a release branch. Follow [semantic versioning](http://semver.org) - a bugfix release is a 0.0.x version bump, a new feature is a 0.x.0 bump, and a backward-incompatible change is a new x.0.0 version.
38
+
39
+ ```
40
+ git flow release start 1.0.1
41
+ ```
42
+
43
+ 2. In the newly created release branch, update `CHANGELOG.md`:
44
+
45
+ ```diff
46
+ Changelog
47
+ =========
48
+
49
+ -(unreleased)
50
+ -------------
51
+ +1.0.1
52
+ +-----
53
+ ```
54
+
55
+ and also update `version.rb`:
56
+
57
+ ```diff
58
+ - VERSION = '1.0.0'
59
+ + VERSION = '1.0.1'
60
+ ```
61
+
62
+ 3. Finish the release and push it to GitHub:
63
+
64
+ ```
65
+ git flow release finish 1.0.1
66
+ git push origin master
67
+ git push origin develop
68
+ git push --tags
69
+ ```
70
+
71
+ 4. Add release notes on GitHub, for example `https://github.com/cisco/cisco-network-node-utils/releases/new?tag=v1.0.1`. Usually this will just be a copy-and-paste of the relevant section of the `CHANGELOG.md`.
72
+
73
+ 5. Publish the new gem version to rubygems.org:
74
+
75
+ ```
76
+ gem build cisco_node_utils.gemspec
77
+ gem push cisco_node_utils-0.9.0.gem
78
+ ```
Binary file
@@ -0,0 +1,45 @@
1
+ #
2
+ # NXAPI implementation of X__CLASS_NAME__X class
3
+ #
4
+ # Copyright (c) 2014-2015 Cisco and/or its affiliates.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ require File.join(File.dirname(__FILE__), 'node')
19
+ module Cisco
20
+ # Class name syntax will typically be the resource name in camelCase
21
+ # format; for example: 'tacacs server host' becomes TacacsServerHost.
22
+ class X__CLASS_NAME__X
23
+ # Establish connection to node
24
+ @@node = Cisco::Node.instance
25
+
26
+ def feature_enable
27
+ @@node.config_set('X__RESOURCE_NAME__X', 'feature', { :state => '' })
28
+ end
29
+
30
+ def feature_disable
31
+ @@node.config_set('X__RESOURCE_NAME__X', 'feature', { :state => 'no' })
32
+ end
33
+
34
+ # Check current state of the configuration
35
+ def X__CLASS_NAME__X.feature_enabled
36
+ feat = @@node.config_get('X__RESOURCE_NAME__X', 'feature')
37
+ return (!feat.nil? and !feat.empty?)
38
+ rescue Cisco::CliError => e
39
+ # This cmd will syntax reject if feature is not
40
+ # enabled. Just catch the reject and return false.
41
+ return false if e.clierror =~ /Syntax error/
42
+ raise
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,125 @@
1
+ #
2
+ # NXAPI implementation of X__CLASS_NAME__X class
3
+ #
4
+ # Copyright (c) 2014-2015 Cisco and/or its affiliates.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ require File.join(File.dirname(__FILE__), 'node')
19
+
20
+ module Cisco
21
+ class X__CLASS_NAME__X
22
+ attr_reader :name
23
+
24
+ # Establish connection to node
25
+ @@node = Cisco::Node.instance
26
+
27
+ # name: name of the router instance
28
+ # instantiate: true = create router instance
29
+ def initialize(name, instantiate=true)
30
+ raise ArgumentError unless name.length > 0
31
+ @name = name
32
+ create if instantiate
33
+ end
34
+
35
+ # Create a hash of all current router instances.
36
+ def X__CLASS_NAME__X.routers
37
+ instances = @@node.config_get('X__RESOURCE_NAME__X', 'router')
38
+ return {} if instances.nil?
39
+ hash = {}
40
+ instances.each do |name|
41
+ hash[name] = X__CLASS_NAME__X.new(name, false)
42
+ end
43
+ return hash
44
+ rescue Cisco::CliError => e
45
+ # cmd will syntax reject when feature is not enabled
46
+ raise unless e.clierror =~ /Syntax error/
47
+ return {}
48
+ end
49
+
50
+ def feature_enabled
51
+ feat = @@node.config_get('X__RESOURCE_NAME__X', 'feature')
52
+ return (!feat.nil? and !feat.empty?)
53
+ rescue Cisco::CliError => e
54
+ # This cmd will syntax reject if feature is not
55
+ # enabled. Just catch the reject and return false.
56
+ return false if e.clierror =~ /Syntax error/
57
+ raise
58
+ end
59
+
60
+ def feature_enable
61
+ @@node.config_set('X__RESOURCE_NAME__X', 'feature', { :state => '' })
62
+ end
63
+
64
+ def feature_disable
65
+ @@node.config_set('X__RESOURCE_NAME__X', 'feature', { :state => 'no' })
66
+ end
67
+
68
+ # Enable feature and create router instance
69
+ def create
70
+ feature_enable unless feature_enabled
71
+ X__RESOURCE_NAME__X_router
72
+ end
73
+
74
+ # Destroy a router instance; disable feature on last instance
75
+ def destroy
76
+ ids = @@node.config_get('X__RESOURCE_NAME__X', 'router')
77
+ return if ids.nil?
78
+ if ids.size == 1
79
+ feature_disable
80
+ else
81
+ X__RESOURCE_NAME__X_router('no')
82
+ end
83
+ rescue Cisco::CliError => e
84
+ # cmd will syntax reject when feature is not enabled
85
+ raise unless e.clierror =~ /Syntax error/
86
+ end
87
+
88
+ def X__RESOURCE_NAME__X_router(state='')
89
+ @@node.config_set('X__RESOURCE_NAME__X', 'router', { :name => @name, :state => state })
90
+ end
91
+
92
+ # ----------
93
+ # PROPERTIES
94
+ # ----------
95
+
96
+ # Property methods for boolean property
97
+ def default_X__PROPERTY_BOOL__X
98
+ @@node.config_get_default('X__RESOURCE_NAME__X', 'X__PROPERTY_BOOL__X')
99
+ end
100
+
101
+ def X__PROPERTY_BOOL__X
102
+ state = @@node.config_get('X__RESOURCE_NAME__X', 'X__PROPERTY_BOOL__X', { :name => @name })
103
+ state ? true : false
104
+ end
105
+
106
+ def X__PROPERTY_BOOL__X=(state)
107
+ state = (state ? '' : 'no')
108
+ @@node.config_set('X__RESOURCE_NAME__X', 'X__PROPERTY_BOOL__X', { :name => @name, :state => state })
109
+ end
110
+
111
+ # Property methods for integer property
112
+ def default_X__PROPERTY_INT__X
113
+ @@node.config_get_default('X__RESOURCE_NAME__X', 'X__PROPERTY_INT__X')
114
+ end
115
+
116
+ def X__PROPERTY_INT__X
117
+ val = @@node.config_get('X__RESOURCE_NAME__X', 'X__PROPERTY_INT__X', { :name => @name })
118
+ val.nil? ? default_X__PROPERTY_INT__X : val.first.to_i
119
+ end
120
+
121
+ def X__PROPERTY_INT__X=(val)
122
+ @@node.config_set('X__RESOURCE_NAME__X', 'X__PROPERTY_INT__X', { :name => @name, :val => val })
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,51 @@
1
+ #
2
+ # Minitest for X__CLASS_NAME__X class
3
+ #
4
+ # Copyright (c) 2014-2015 Cisco and/or its affiliates.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ require File.expand_path("../ciscotest", __FILE__)
19
+ require File.expand_path("../../lib/cisco_node_utils/X__RESOURCE_NAME__X", __FILE__)
20
+
21
+ class TestX__CLASS_NAME__X < CiscoTestCase
22
+ def setup
23
+ # setup automatically runs at the beginning of each test
24
+ super
25
+ no_feature
26
+ end
27
+
28
+ def teardown
29
+ # teardown automatically runs at the end of each test
30
+ no_feature
31
+ super
32
+ end
33
+
34
+ def no_feature
35
+ # setup/teardown helper. Turn the feature off for a clean testbed.
36
+ @device.cmd('conf t ; no feature X__CLI_NAME__X ; end')
37
+ # Flush the cache since we've modified the device outside of the node_utils APIs
38
+ node.cache_flush()
39
+ end
40
+
41
+ # TESTS
42
+
43
+ def test_feature_on_off
44
+ feat = X__CLASS_NAME__X.new()
45
+ feat.feature_enable
46
+ assert(BashShell.feature_enabled)
47
+
48
+ feat.feature_disable
49
+ refute(BashShell.feature_enabled)
50
+ end
51
+ end
@@ -0,0 +1,107 @@
1
+ #
2
+ # Minitest for __CLASS_NAME__ class
3
+ #
4
+ # Copyright (c) 2014-2015 Cisco and/or its affiliates.
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+
18
+ require File.expand_path("../ciscotest", __FILE__)
19
+ require File.expand_path("../../lib/cisco_node_utils/router___RESOURCE_NAME__", __FILE__)
20
+
21
+ class Test__CLASS_NAME__ < CiscoTestCase
22
+ def setup
23
+ # setup runs at the beginning of each test
24
+ super
25
+ no_feature___RESOURCE_NAME__
26
+ end
27
+
28
+ def teardown
29
+ # teardown runs at the end of each test
30
+ no_feature___RESOURCE_NAME__
31
+ super
32
+ end
33
+
34
+ def no_feature___RESOURCE_NAME__
35
+ # Turn the feature off for a clean test.
36
+ @device.cmd("conf t ; no feature __RESOURCE_NAME__ ; end")
37
+ # Flush the cache since we've modified the device outside of the node_utils APIs
38
+ node.cache_flush()
39
+ end
40
+
41
+ # TESTS
42
+
43
+ def test_router_create_destroy_one
44
+ id = "blue"
45
+ rtr = __CLASS_NAME__.new(id)
46
+ s = @device.cmd("show runn | i 'router __RESOURCE_NAME__ #{id}'")
47
+ assert_match(s, /^router __RESOURCE_NAME__ #{id}$/,
48
+ "Error: failed to create router __RESOURCE_NAME__ #{id}")
49
+
50
+ rtr.destroy
51
+ s = @device.cmd("show runn | i 'router __RESOURCE_NAME__ #{id}'")
52
+ refute_match(s, /^router __RESOURCE_NAME__ #{id}$/,
53
+ "Error: failed to destroy router __RESOURCE_NAME__ #{id}")
54
+
55
+ s = @device.cmd("show runn | i 'feature __RESOURCE_NAME__'")
56
+ refute_match(s, /^feature __RESOURCE_NAME__$/,
57
+ "Error: failed to disable feature __RESOURCE_NAME__")
58
+ end
59
+
60
+ def test_router_create_destroy_multiple
61
+ id1 = "blue"
62
+ rtr1 = __CLASS_NAME__.new(id1)
63
+ id2 = "red"
64
+ rtr2 = __CLASS_NAME__.new(id2)
65
+
66
+ s = @device.cmd("show runn | i 'router __RESOURCE_NAME__'")
67
+ assert_match(s, /^router __RESOURCE_NAME__ #{id1}$/)
68
+ assert_match(s, /^router __RESOURCE_NAME__ #{id2}$/)
69
+
70
+ rtr1.destroy
71
+ s = @device.cmd("show runn | i 'router __RESOURCE_NAME__ #{id1}'")
72
+ refute_match(s, /^router __RESOURCE_NAME__ #{id1}$/,
73
+ "Error: failed to destroy router __RESOURCE_NAME__ #{id1}")
74
+
75
+ rtr2.destroy
76
+ s = @device.cmd("show runn | i 'router __RESOURCE_NAME__ #{id2}'")
77
+ refute_match(s, /^router __RESOURCE_NAME__ #{id2}$/,
78
+ "Error: failed to destroy router __RESOURCE_NAME__ #{id2}")
79
+
80
+ s = @device.cmd("show runn | i 'feature __RESOURCE_NAME__'")
81
+ refute_match(s, /^feature __RESOURCE_NAME__$/,
82
+ "Error: failed to disable feature __RESOURCE_NAME__")
83
+ end
84
+
85
+ def test_router___PROPERTY_INT__
86
+ id = "blue"
87
+ rtr = __CLASS_NAME__.new(id)
88
+ val = 5 # This value depends on property bounds
89
+ rtr.__PROPERTY_INT__ = val
90
+ assert_equal(rtr.__PROPERTY_INT__, val, "__PROPERTY_INT__ is not #{val}")
91
+
92
+ # Get default value from yaml
93
+ val = node.config_get_default("__RESOURCE_NAME__", "__PROPERTY_INT__")
94
+ rtr.__PROPERTY_INT__ = val
95
+ assert_equal(rtr.__PROPERTY_INT__, val, "__PROPERTY_INT__ is not #{val}")
96
+ end
97
+
98
+ def test_router___PROPERTY_BOOL__
99
+ id = "blue"
100
+ rtr = __CLASS_NAME__.new(id)
101
+ rtr.__PROPERTY_BOOL__ = true
102
+ assert(rtr.__PROPERTY_BOOL__, "__PROPERTY_BOOL__ state is not true")
103
+
104
+ rtr.__PROPERTY_BOOL__ = false
105
+ refute(rtr.__PROPERTY_BOOL__, "__PROPERTY_BOOL__ state is not false")
106
+ end
107
+ end
@@ -142,6 +142,17 @@ interface:
142
142
  destroy:
143
143
  config_set: "no interface %s"
144
144
 
145
+ encapsulation_dot1q:
146
+ config_get: "show running interface all"
147
+ config_get_token: ['/^interface %s$/i', '/^encapsulation dot1q (.*)/']
148
+ config_set: ["interface %s", "%s encapsulation dot1q %s"]
149
+ default_value: ""
150
+
151
+ feature_lacp:
152
+ config_get: "show running | i ^feature"
153
+ config_get_token: '/^feature lacp$/'
154
+ config_set: "%s feature lacp"
155
+
145
156
  feature_vlan:
146
157
  config_get: "show running | i ^feature"
147
158
  config_get_token: '/^feature interface-vlan$/'
@@ -196,6 +207,12 @@ interface:
196
207
  false: false
197
208
  true: true
198
209
 
210
+ mtu:
211
+ config_get: "show running interface all"
212
+ config_get_token: ['/^interface %s$/i', '/^mtu (.*)$/']
213
+ config_set: ["interface %s", "%s mtu %s"]
214
+ default_value: ""
215
+
199
216
  negotiate_auto_ethernet:
200
217
  config_get: "show running interface all"
201
218
  config_get_token: [
@@ -303,6 +320,24 @@ interface:
303
320
  test_config_result:
304
321
  false: RuntimeError
305
322
 
323
+ switchport_trunk_allowed_vlan:
324
+ config_get: "show running interface all"
325
+ config_get_token: [
326
+ '/^interface %s$/i',
327
+ '/^switchport trunk allowed vlan (.*)$/'
328
+ ]
329
+ config_set: ["interface %s", "%s switchport trunk allowed vlan %s"]
330
+ default_value: "all"
331
+
332
+ switchport_trunk_native_vlan:
333
+ config_get: "show running interface all"
334
+ config_get_token: [
335
+ '/^interface %s$/i',
336
+ '/^switchport trunk native vlan (.*)$/'
337
+ ]
338
+ config_set: ["interface %s", "%s switchport trunk native vlan %s"]
339
+ default_value: 1
340
+
306
341
  svi_autostate:
307
342
  config_get: "show running interface all"
308
343
  config_get_token: ['/^interface %s$/i', '/^autostate$/']
@@ -318,6 +353,12 @@ interface:
318
353
  config_set: ["interface %s", "%s management"]
319
354
  default_value: false
320
355
 
356
+ vrf:
357
+ config_get: "show running interface all"
358
+ config_get_token: ['/^interface %s$/i', '/^vrf member (.*)/']
359
+ config_set: ["interface %s", "%s vrf member %s"]
360
+ default_value: ""
361
+
321
362
  vtp:
322
363
  config_get: "show running interface all"
323
364
  config_get_token: ['/^interface %s$/i', '/^vtp *$/']
@@ -835,7 +876,7 @@ vtp:
835
876
 
836
877
  yum:
837
878
  install:
838
- config_set: "install add %s activate"
879
+ config_set: "install add %s %s activate"
839
880
  query:
840
881
  config_get: "show install packages"
841
882
  # pass in the pkg name, retrieve version