cisco_node_utils 1.0.1 → 1.1.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.
Files changed (114) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +4 -0
  3. data/.rubocop.yml +81 -1
  4. data/.travis.yml +9 -0
  5. data/CHANGELOG.md +72 -6
  6. data/CONTRIBUTING.md +32 -7
  7. data/README.md +70 -7
  8. data/Rakefile +17 -0
  9. data/bin/check_metric_limits.rb +109 -0
  10. data/bin/git/hooks/commit-msg/enforce_style +81 -0
  11. data/bin/git/hooks/hook_lib +108 -0
  12. data/bin/git/hooks/hooks-wrapper +38 -0
  13. data/bin/git/hooks/post-flow-hotfix-start/update-version +24 -0
  14. data/bin/git/hooks/post-flow-release-finish/update-version +29 -0
  15. data/bin/git/hooks/post-flow-release-start/update-version +19 -0
  16. data/bin/git/hooks/post-merge/update-hooks +6 -0
  17. data/bin/git/hooks/post-rewrite/update-hooks +6 -0
  18. data/bin/git/hooks/pre-commit/rubocop +20 -0
  19. data/bin/git/hooks/pre-commit/validate-diffs +31 -0
  20. data/bin/git/hooks/pre-push/check-changelog +24 -0
  21. data/bin/git/hooks/pre-push/rubocop +7 -0
  22. data/bin/git/update-hooks +65 -0
  23. data/cisco_node_utils.gemspec +9 -3
  24. data/docs/README-develop-best-practices.md +404 -0
  25. data/docs/README-develop-node-utils-APIs.md +215 -365
  26. data/docs/README-maintainers.md +33 -3
  27. data/docs/template-router.rb +89 -91
  28. data/docs/template-test_router.rb +52 -55
  29. data/lib/.rubocop.yml +18 -0
  30. data/lib/cisco_node_utils.rb +2 -19
  31. data/lib/cisco_node_utils/README_YAML.md +1 -9
  32. data/lib/cisco_node_utils/bgp.rb +664 -0
  33. data/lib/cisco_node_utils/bgp_af.rb +530 -0
  34. data/lib/cisco_node_utils/bgp_neighbor.rb +425 -0
  35. data/lib/cisco_node_utils/bgp_neighbor_af.rb +709 -0
  36. data/lib/cisco_node_utils/cisco_cmn_utils.rb +59 -25
  37. data/lib/cisco_node_utils/command_reference.rb +72 -74
  38. data/lib/cisco_node_utils/command_reference_common.yaml +174 -9
  39. data/lib/cisco_node_utils/command_reference_common_bgp.yaml +535 -0
  40. data/lib/cisco_node_utils/command_reference_n7k.yaml +4 -0
  41. data/lib/cisco_node_utils/command_reference_n9k.yaml +0 -9
  42. data/lib/cisco_node_utils/configparser_lib.rb +152 -147
  43. data/lib/cisco_node_utils/dns_domain.rb +79 -0
  44. data/lib/cisco_node_utils/domain_name.rb +71 -0
  45. data/lib/cisco_node_utils/interface.rb +167 -161
  46. data/lib/cisco_node_utils/interface_ospf.rb +78 -81
  47. data/lib/cisco_node_utils/name_server.rb +64 -0
  48. data/lib/cisco_node_utils/node.rb +154 -198
  49. data/lib/cisco_node_utils/node_util.rb +61 -0
  50. data/lib/cisco_node_utils/ntp_config.rb +65 -0
  51. data/lib/cisco_node_utils/ntp_server.rb +76 -0
  52. data/lib/cisco_node_utils/platform.rb +174 -165
  53. data/lib/cisco_node_utils/radius_global.rb +146 -0
  54. data/lib/cisco_node_utils/radius_server.rb +295 -0
  55. data/lib/cisco_node_utils/router_ospf.rb +59 -63
  56. data/lib/cisco_node_utils/router_ospf_vrf.rb +226 -210
  57. data/lib/cisco_node_utils/snmpcommunity.rb +52 -58
  58. data/lib/cisco_node_utils/snmpgroup.rb +22 -23
  59. data/lib/cisco_node_utils/snmpserver.rb +99 -103
  60. data/lib/cisco_node_utils/snmpuser.rb +294 -274
  61. data/lib/cisco_node_utils/syslog_server.rb +92 -0
  62. data/lib/cisco_node_utils/syslog_settings.rb +69 -0
  63. data/lib/cisco_node_utils/tacacs_server.rb +137 -133
  64. data/lib/cisco_node_utils/tacacs_server_host.rb +84 -87
  65. data/lib/cisco_node_utils/version.rb +2 -1
  66. data/lib/cisco_node_utils/vlan.rb +28 -31
  67. data/lib/cisco_node_utils/vrf.rb +80 -0
  68. data/lib/cisco_node_utils/vtp.rb +100 -97
  69. data/lib/cisco_node_utils/yum.rb +15 -17
  70. data/tests/.rubocop.yml +15 -0
  71. data/tests/basetest.rb +81 -36
  72. data/tests/ciscotest.rb +38 -78
  73. data/{lib/cisco_node_utils → tests}/platform_info.rb +12 -8
  74. data/{lib/cisco_node_utils → tests}/platform_info.yaml +1 -1
  75. data/tests/test_bgp_af.rb +920 -0
  76. data/tests/test_bgp_neighbor.rb +403 -0
  77. data/tests/test_bgp_neighbor_af.rb +589 -0
  78. data/tests/test_command_config.rb +65 -62
  79. data/tests/test_command_reference.rb +31 -45
  80. data/tests/test_dns_domain.rb +113 -0
  81. data/tests/test_domain_name.rb +86 -0
  82. data/tests/test_interface.rb +424 -548
  83. data/tests/test_interface_ospf.rb +248 -432
  84. data/tests/test_interface_svi.rb +56 -79
  85. data/tests/test_interface_switchport.rb +196 -272
  86. data/tests/test_name_server.rb +85 -0
  87. data/tests/test_node.rb +7 -6
  88. data/tests/test_node_ext.rb +133 -186
  89. data/tests/test_ntp_config.rb +49 -0
  90. data/tests/test_ntp_server.rb +74 -0
  91. data/tests/test_platform.rb +58 -37
  92. data/tests/test_radius_global.rb +78 -0
  93. data/tests/test_radius_server.rb +185 -0
  94. data/tests/test_router_bgp.rb +838 -0
  95. data/tests/test_router_ospf.rb +49 -80
  96. data/tests/test_router_ospf_vrf.rb +274 -392
  97. data/tests/test_snmpcommunity.rb +128 -172
  98. data/tests/test_snmpgroup.rb +12 -14
  99. data/tests/test_snmpserver.rb +160 -189
  100. data/tests/test_snmpuser.rb +568 -717
  101. data/tests/test_syslog_server.rb +88 -0
  102. data/tests/test_syslog_settings.rb +54 -0
  103. data/tests/test_tacacs_server.rb +113 -148
  104. data/tests/test_tacacs_server_host.rb +108 -161
  105. data/tests/test_vlan.rb +63 -79
  106. data/tests/test_vrf.rb +92 -0
  107. data/tests/test_vtp.rb +108 -126
  108. data/tests/test_yum.rb +47 -41
  109. metadata +92 -56
  110. data/.rubocop_todo.yml +0 -293
  111. data/docs/.rubocop.yml +0 -13
  112. data/docs/template-feature.rb +0 -45
  113. data/docs/template-test_feature.rb +0 -51
  114. data/tests/test_all_cisco.rb +0 -46
@@ -1,6 +1,3 @@
1
- #
2
- # NXAPI implementation of SnmpCommunity class
3
- #
4
1
  # December 2014, Alex Hunsberger
5
2
  #
6
3
  # Copyright (c) 2014-2015 Cisco and/or its affiliates.
@@ -17,75 +14,72 @@
17
14
  # See the License for the specific language governing permissions and
18
15
  # limitations under the License.
19
16
 
20
- require File.join(File.dirname(__FILE__), 'node')
17
+ require_relative 'node_util'
21
18
 
22
19
  module Cisco
23
- class SnmpCommunity
24
- @@communities = nil
25
- @@node = Cisco::Node.instance
26
-
27
- def initialize(name, group, instantiate=true)
28
- raise TypeError unless name.is_a?(String) and group.is_a?(String)
29
- @name = name
20
+ # SnmpCommunity - node utility class for SNMP community config management
21
+ class SnmpCommunity < NodeUtil
22
+ @communities = nil
30
23
 
31
- if instantiate
32
- @@node.config_set("snmp_community", "community", "", name, group)
24
+ def initialize(name, group, instantiate=true)
25
+ fail TypeError unless name.is_a?(String) && group.is_a?(String)
26
+ @name = name
27
+ return unless instantiate
28
+ config_set('snmp_community', 'community', '', name, group)
33
29
  end
34
- end
35
30
 
36
- def SnmpCommunity.communities
37
- @@communities = {}
38
- comms = @@node.config_get("snmp_community", "all_communities")
39
- unless comms.nil?
40
- comms.each { |comm|
41
- @@communities[comm] = SnmpCommunity.new(comm, "", false)
42
- }
31
+ def self.communities
32
+ @communities = {}
33
+ comms = config_get('snmp_community', 'all_communities')
34
+ unless comms.nil?
35
+ comms.each do |comm|
36
+ @communities[comm] = SnmpCommunity.new(comm, '', false)
37
+ end
38
+ end
39
+ @communities
43
40
  end
44
- @@communities
45
- end
46
41
 
47
- def destroy
48
- # CLI requires specifying a group even for "no" commands
49
- @@node.config_set("snmp_community", "community", "no", @name, "null")
50
- @@communities.delete(@name) unless @@communities.nil?
51
- end
42
+ def destroy
43
+ # CLI requires specifying a group even for "no" commands
44
+ config_set('snmp_community', 'community', 'no', @name, 'null')
45
+ end
52
46
 
53
- # name is read only
54
- # def name
55
- # @name
56
- # end
47
+ # name is read only
48
+ # def name
49
+ # @name
50
+ # end
57
51
 
58
- def group
59
- result = @@node.config_get("snmp_community", "group", @name)
60
- result.nil? ? SnmpCommunity.default_group : result.first
61
- end
52
+ def group
53
+ result = config_get('snmp_community', 'group', @name)
54
+ result.nil? ? SnmpCommunity.default_group : result.first
55
+ end
62
56
 
63
- def group=(group)
64
- raise TypeError unless group.is_a?(String)
65
- @@node.config_set("snmp_community", "group", @name, group)
66
- end
57
+ def group=(group)
58
+ fail TypeError unless group.is_a?(String)
59
+ config_set('snmp_community', 'group', @name, group)
60
+ end
67
61
 
68
- def SnmpCommunity.default_group
69
- @@node.config_get_default("snmp_community", "group")
70
- end
62
+ def self.default_group
63
+ config_get_default('snmp_community', 'group')
64
+ end
71
65
 
72
- def acl
73
- result = @@node.config_get("snmp_community", "acl", @name)
74
- result.nil? ? SnmpCommunity.default_acl : result.first
75
- end
66
+ def acl
67
+ result = config_get('snmp_community', 'acl', @name)
68
+ result.nil? ? SnmpCommunity.default_acl : result.first
69
+ end
76
70
 
77
- def acl=(acl)
78
- raise TypeError unless acl.is_a?(String)
79
- if acl.empty?
80
- acl = self.acl
81
- @@node.config_set("snmp_community", "acl", "no", @name, acl) unless acl.empty?
82
- else
83
- @@node.config_set("snmp_community", "acl", "", @name, acl)
71
+ def acl=(acl)
72
+ fail TypeError unless acl.is_a?(String)
73
+ if acl.empty?
74
+ acl = self.acl
75
+ config_set('snmp_community', 'acl', 'no', @name, acl) unless acl.empty?
76
+ else
77
+ config_set('snmp_community', 'acl', '', @name, acl)
78
+ end
84
79
  end
85
- end
86
80
 
87
- def SnmpCommunity.default_acl
88
- @@node.config_get_default("snmp_community", "acl")
81
+ def self.default_acl
82
+ config_get_default('snmp_community', 'acl')
83
+ end
89
84
  end
90
85
  end
91
- end
@@ -21,35 +21,34 @@
21
21
  # purpose of group; thus this provider utility does not create snmp groups
22
22
  # and is limited to reporting group (role) existence only.
23
23
 
24
- require File.join(File.dirname(__FILE__), 'node')
24
+ require_relative 'node_util'
25
25
 
26
26
  module Cisco
27
- class SnmpGroup
28
- attr_reader :name
27
+ # SnmpGroup - node utility class for SNMP group configuration management
28
+ class SnmpGroup < NodeUtil
29
+ attr_reader :name
29
30
 
30
- @@node = Cisco::Node.instance
31
-
32
- def initialize(name)
33
- raise TypeError unless name.is_a?(String)
34
- @name = name
35
- end
31
+ def initialize(name)
32
+ fail TypeError unless name.is_a?(String)
33
+ @name = name
34
+ end
36
35
 
37
- def self.groups
38
- group_ids = @@node.config_get("snmp_group", "group")
39
- return {} if group_ids.nil?
36
+ def self.groups
37
+ group_ids = config_get('snmp_group', 'group')
38
+ return {} if group_ids.nil?
40
39
 
41
- hash = {}
42
- group_ids.each do |name|
43
- hash[name] = SnmpGroup.new(name)
40
+ hash = {}
41
+ group_ids.each do |name|
42
+ hash[name] = SnmpGroup.new(name)
43
+ end
44
+ hash
44
45
  end
45
- hash
46
- end
47
46
 
48
- def self.exists?(group)
49
- raise ArgumentError if group.empty?
50
- raise TypeError unless group.is_a? String
51
- groups = @@node.config_get("snmp_group", "group")
52
- (!groups.nil? and groups.include? group)
47
+ def self.exists?(group)
48
+ fail ArgumentError if group.empty?
49
+ fail TypeError unless group.is_a? String
50
+ groups = config_get('snmp_group', 'group')
51
+ (!groups.nil? && groups.include?(group))
52
+ end
53
53
  end
54
54
  end
55
- end
@@ -1,6 +1,3 @@
1
- #
2
- # NXAPI implementation of SnmpCommunity class
3
- #
4
1
  # November 2014, Alex Hunsberger
5
2
  #
6
3
  # Copyright (c) 2014-2015 Cisco and/or its affiliates.
@@ -17,134 +14,133 @@
17
14
  # See the License for the specific language governing permissions and
18
15
  # limitations under the License.
19
16
 
20
- require File.join(File.dirname(__FILE__), 'node')
17
+ require_relative 'node_util'
21
18
 
22
19
  module Cisco
23
- class SnmpServer
24
- @@node = Cisco::Node.instance
25
-
26
- def aaa_user_cache_timeout
27
- match = @@node.config_get("snmp_server", "aaa_user_cache_timeout")
28
- # regex in yaml returns an array result, use .first to get match
29
- match.nil? ? default_aaa_user_cache_timeout : match.first.to_i
30
- end
20
+ # SnmpServer - node utility class for SNMP server management
21
+ class SnmpServer < NodeUtil
22
+ def aaa_user_cache_timeout
23
+ match = config_get('snmp_server', 'aaa_user_cache_timeout')
24
+ # regex in yaml returns an array result, use .first to get match
25
+ match.nil? ? default_aaa_user_cache_timeout : match.first.to_i
26
+ end
31
27
 
32
- def aaa_user_cache_timeout=(timeout)
33
- if timeout == default_aaa_user_cache_timeout
34
- @@node.config_set("snmp_server", "aaa_user_cache_timeout", "no",
35
- aaa_user_cache_timeout)
36
- else
37
- @@node.config_set("snmp_server", "aaa_user_cache_timeout", "", timeout)
28
+ def aaa_user_cache_timeout=(timeout)
29
+ if timeout == default_aaa_user_cache_timeout
30
+ config_set('snmp_server', 'aaa_user_cache_timeout', 'no',
31
+ aaa_user_cache_timeout)
32
+ else
33
+ config_set('snmp_server', 'aaa_user_cache_timeout', '', timeout)
34
+ end
38
35
  end
39
- end
40
36
 
41
- def default_aaa_user_cache_timeout
42
- @@node.config_get_default("snmp_server", "aaa_user_cache_timeout")
43
- end
37
+ def default_aaa_user_cache_timeout
38
+ config_get_default('snmp_server', 'aaa_user_cache_timeout')
39
+ end
44
40
 
45
- def location
46
- match = @@node.config_get("snmp_server", "location")
47
- match.nil? ? default_location : match
48
- end
41
+ def location
42
+ match = config_get('snmp_server', 'location')
43
+ match.nil? ? default_location : match
44
+ end
49
45
 
50
- def location=(location)
51
- raise TypeError unless location.is_a?(String)
52
- if location.empty?
53
- @@node.config_set("snmp_server", "location", "no", "")
54
- else
55
- @@node.config_set("snmp_server", "location", "", location)
46
+ def location=(location)
47
+ fail TypeError unless location.is_a?(String)
48
+ if location.empty?
49
+ config_set('snmp_server', 'location', 'no', '')
50
+ else
51
+ config_set('snmp_server', 'location', '', location)
52
+ end
56
53
  end
57
- end
58
54
 
59
- def default_location
60
- @@node.config_get_default("snmp_server", "location")
61
- end
55
+ def default_location
56
+ config_get_default('snmp_server', 'location')
57
+ end
62
58
 
63
- def contact
64
- match = @@node.config_get("snmp_server", "contact")
65
- match.nil? ? default_contact : match
66
- end
59
+ def contact
60
+ match = config_get('snmp_server', 'contact')
61
+ match.nil? ? default_contact : match
62
+ end
67
63
 
68
- def contact=(contact)
69
- raise TypeError unless contact.is_a?(String)
70
- if contact.empty?
71
- @@node.config_set("snmp_server", "contact", "no", "")
72
- else
73
- @@node.config_set("snmp_server", "contact", "", contact)
64
+ def contact=(contact)
65
+ fail TypeError unless contact.is_a?(String)
66
+ if contact.empty?
67
+ config_set('snmp_server', 'contact', 'no', '')
68
+ else
69
+ config_set('snmp_server', 'contact', '', contact)
70
+ end
74
71
  end
75
- end
76
72
 
77
- def default_contact
78
- @@node.config_get_default("snmp_server", "contact")
79
- end
73
+ def default_contact
74
+ config_get_default('snmp_server', 'contact')
75
+ end
80
76
 
81
- def packet_size
82
- match = @@node.config_get("snmp_server", "packet_size")
83
- # regex in yaml returns an array result, use .first to get match
84
- match.nil? ? default_packet_size : match.first.to_i
85
- end
77
+ def packet_size
78
+ match = config_get('snmp_server', 'packet_size')
79
+ # regex in yaml returns an array result, use .first to get match
80
+ match.nil? ? default_packet_size : match.first.to_i
81
+ end
86
82
 
87
- def packet_size=(size)
88
- if size == 0
89
- ps = packet_size
90
- @@node.config_set("snmp_server", "packet_size", "no", ps) unless ps == 0
91
- else
92
- @@node.config_set("snmp_server", "packet_size", "", size)
83
+ def packet_size=(size)
84
+ if size == 0
85
+ ps = packet_size
86
+ config_set('snmp_server', 'packet_size', 'no', ps) unless ps == 0
87
+ else
88
+ config_set('snmp_server', 'packet_size', '', size)
89
+ end
93
90
  end
94
- end
95
91
 
96
- def default_packet_size
97
- @@node.config_get_default("snmp_server", "packet_size")
98
- end
92
+ def default_packet_size
93
+ config_get_default('snmp_server', 'packet_size')
94
+ end
99
95
 
100
- def global_enforce_priv?
101
- not @@node.config_get("snmp_server", "global_enforce_priv").nil?
102
- end
96
+ def global_enforce_priv?
97
+ !config_get('snmp_server', 'global_enforce_priv').nil?
98
+ end
103
99
 
104
- def global_enforce_priv=(enforce)
105
- if enforce
106
- @@node.config_set("snmp_server", "global_enforce_priv", "")
107
- else
108
- @@node.config_set("snmp_server", "global_enforce_priv", "no")
100
+ def global_enforce_priv=(enforce)
101
+ if enforce
102
+ config_set('snmp_server', 'global_enforce_priv', '')
103
+ else
104
+ config_set('snmp_server', 'global_enforce_priv', 'no')
105
+ end
109
106
  end
110
- end
111
107
 
112
- def default_global_enforce_priv
113
- @@node.config_get_default("snmp_server", "global_enforce_priv")
114
- end
108
+ def default_global_enforce_priv
109
+ config_get_default('snmp_server', 'global_enforce_priv')
110
+ end
115
111
 
116
- def protocol?
117
- match = @@node.config_get("snmp_server", "protocol")
118
- not match.nil? and match.include?("Enable")
119
- end
112
+ def protocol?
113
+ match = config_get('snmp_server', 'protocol')
114
+ !match.nil? && match.include?('Enable')
115
+ end
120
116
 
121
- def protocol=(enable)
122
- if enable
123
- @@node.config_set("snmp_server", "protocol", "")
124
- else
125
- @@node.config_set("snmp_server", "protocol", "no")
117
+ def protocol=(enable)
118
+ if enable
119
+ config_set('snmp_server', 'protocol', '')
120
+ else
121
+ config_set('snmp_server', 'protocol', 'no')
122
+ end
126
123
  end
127
- end
128
124
 
129
- def default_protocol
130
- @@node.config_get_default("snmp_server", "protocol")
131
- end
125
+ def default_protocol
126
+ config_get_default('snmp_server', 'protocol')
127
+ end
132
128
 
133
- def tcp_session_auth?
134
- match = @@node.config_get("snmp_server", "tcp_session_auth")
135
- not match.nil? and match.include?("Enabled")
136
- end
129
+ def tcp_session_auth?
130
+ match = config_get('snmp_server', 'tcp_session_auth')
131
+ !match.nil? && match.include?('Enabled')
132
+ end
137
133
 
138
- def tcp_session_auth=(enable)
139
- if enable
140
- @@node.config_set("snmp_server", "tcp_session_auth", "", "auth")
141
- else
142
- @@node.config_set("snmp_server", "tcp_session_auth", "no", "")
134
+ def tcp_session_auth=(enable)
135
+ if enable
136
+ config_set('snmp_server', 'tcp_session_auth', '', 'auth')
137
+ else
138
+ config_set('snmp_server', 'tcp_session_auth', 'no', '')
139
+ end
143
140
  end
144
- end
145
141
 
146
- def default_tcp_session_auth
147
- @@node.config_get_default("snmp_server", "tcp_session_auth")
142
+ def default_tcp_session_auth
143
+ config_get_default('snmp_server', 'tcp_session_auth')
144
+ end
148
145
  end
149
146
  end
150
- end
@@ -12,331 +12,351 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- require File.join(File.dirname(__FILE__), 'node')
15
+ require_relative 'node_util'
16
16
 
17
17
  module Cisco
18
- SNMP_USER_NAME_KEY = "user"
19
- SNMP_USER_GROUP_KEY = "group"
20
- SNMP_USER_AUTH_KEY = "auth"
21
- SNMP_USER_PRIV_KEY = "priv"
22
- SNMP_USER_ENGINE_ID = "engineID"
23
- SNMP_USER_ENGINE_ID_PATTERN = /([0-9]{1,3}(:[0-9]{1,3}){4,31})/
24
-
25
- class SnmpUser
26
- @@users = {}
27
- @@node = Cisco::Node.instance
28
-
29
- def initialize(name, groups, authproto, authpass, privproto,
30
- privpass, localizedkey, engineid, instantiate=true)
31
- raise TypeError unless name.is_a?(String)
32
- raise ArgumentError if name.empty?
33
- raise TypeError unless groups.is_a?(Array)
34
- raise TypeError unless authproto.is_a?(Symbol)
35
- raise TypeError unless authpass.is_a?(String)
36
- # empty password but protocol provided = bad
37
- # non-empty password and no protocol provided = bad
38
- raise ArgumentError if authpass.empty? and [:sha, :md5].include?(authproto) and instantiate
39
- raise ArgumentError if not authpass.empty? and not [:sha, :md5].include?(authproto)
40
- raise TypeError unless privproto.is_a?(Symbol)
41
- raise TypeError unless privpass.is_a?(String)
42
- raise ArgumentError if privpass.empty? and [:des, :aes128].include?(privproto) and instantiate
43
- raise ArgumentError if not privpass.empty? and not [:des, :aes128].include?(privproto)
44
- raise TypeError unless !!localizedkey == localizedkey # bool check
45
- raise TypeError unless engineid.is_a?(String)
46
-
47
- @name = name
48
- @engine_id = engineid
49
-
50
- @authproto = authproto
51
- @privproto = privproto
52
- @groups_arr = groups
53
-
54
- authprotostr = _auth_sym_to_str(authproto)
55
- privprotostr = _priv_sym_to_str(privproto)
56
-
57
- # Config string syntax:
58
- # [no] snmp-server user <user> [group] [auth {md5|sha} <passwd1> [priv [aes-128] <passwd2>] [localizedkey] [engineID <id>]]
59
- if instantiate
60
- # assume if multiple groups, apply all config to each
61
- groups = [""] if groups.empty?
62
- groups.each { |group|
63
- @@node.config_set("snmp_user", "user", "",
64
- name,
65
- group,
66
- authpass.empty? ? "" : "auth #{authprotostr} #{authpass}",
67
- privpass.empty? ? "" : "priv #{privprotostr} #{privpass}",
68
- localizedkey ? "localizedkey" : "",
69
- engineid.empty? ? "" : "engineID #{engineid}")
70
- }
18
+ # SnmpUser - node utility class for SNMP user configuration management
19
+ class SnmpUser < NodeUtil
20
+ def initialize(name, groups, authproto, authpass, privproto,
21
+ privpass, localizedkey, engineid, instantiate=true)
22
+ initialize_validator(name, groups, authproto, authpass, privproto,
23
+ privpass, engineid, instantiate)
24
+ @name = name
25
+ @engine_id = engineid
26
+
27
+ @authproto = authproto
28
+ @privproto = privproto
29
+ @groups_arr = groups
30
+
31
+ authprotostr = _auth_sym_to_str(authproto)
32
+ privprotostr = _priv_sym_to_str(privproto)
33
+
34
+ return unless instantiate
35
+ # Config string syntax:
36
+ # [no] snmp-server user <user> [group] ...
37
+ # [auth {md5|sha} <passwd1>
38
+ # [priv [aes-128] <passwd2>] [localizedkey] [engineID <id>]
39
+ # ]
40
+ # Assume if multiple groups, apply all config to each
41
+ groups = [''] if groups.empty?
42
+ groups.each do |group|
43
+ config_set('snmp_user', 'user', '',
44
+ name,
45
+ group,
46
+ authpass.empty? ? '' : "auth #{authprotostr} #{authpass}",
47
+ privpass.empty? ? '' : "priv #{privprotostr} #{privpass}",
48
+ localizedkey ? 'localizedkey' : '',
49
+ engineid.empty? ? '' : "engineID #{engineid}")
50
+ end
71
51
  end
72
- end
73
52
 
74
- def SnmpUser.users
75
- @@users = {}
76
- # config_get returns hash if 1 user, array if multiple, nil if none
77
- users = @@node.config_get("snmp_user", "user")
78
- unless users.nil?
53
+ def initialize_validator(name, groups, authproto, authpass, privproto,
54
+ privpass, engineid, instantiate)
55
+ fail TypeError unless name.is_a?(String) &&
56
+ groups.is_a?(Array) &&
57
+ authproto.is_a?(Symbol) &&
58
+ authpass.is_a?(String) &&
59
+ privproto.is_a?(Symbol) &&
60
+ privpass.is_a?(String) &&
61
+ engineid.is_a?(String)
62
+ fail ArgumentError if name.empty?
63
+ # empty password but protocol provided = bad
64
+ # non-empty password and no protocol provided = bad
65
+ if authpass.empty?
66
+ fail ArgumentError if [:sha, :md5].include?(authproto) && instantiate
67
+ else
68
+ fail ArgumentError unless [:sha, :md5].include?(authproto)
69
+ end
70
+ if privpass.empty?
71
+ fail ArgumentError if [:des, :aes128].include?(privproto) && instantiate
72
+ else
73
+ fail ArgumentError unless [:des, :aes128].include?(privproto)
74
+ end
75
+ end
76
+
77
+ ENGINE_ID_PATTERN = /([0-9]{1,3}(:[0-9]{1,3}){4,31})/
78
+ def self.users
79
+ users_hash = {}
80
+ # config_get returns hash if 1 user, array if multiple, nil if none
81
+ users = config_get('snmp_user', 'user')
82
+ return users_hash if users.nil?
79
83
  users = [users] if users.is_a?(Hash)
80
- users.each { |user|
81
- name = user[SNMP_USER_NAME_KEY]
82
- engineid = user[SNMP_USER_ENGINE_ID]
84
+ users.each do |user|
85
+ name = user['user']
86
+ engineid = user['engineID']
83
87
  if engineid.nil?
84
- index = name
88
+ index = name
85
89
  else
86
- engineid_str = engineid.match(SNMP_USER_ENGINE_ID_PATTERN)[1]
87
- index = name + " " + engineid_str
90
+ engineid_str = engineid.match(ENGINE_ID_PATTERN)[1]
91
+ index = name + ' ' + engineid_str
88
92
  end
89
- auth = _auth_str_to_sym(user[SNMP_USER_AUTH_KEY])
90
- priv = _priv_str_to_sym(user[SNMP_USER_PRIV_KEY])
93
+ auth = _auth_str_to_sym(user['auth'])
94
+ priv = _priv_str_to_sym(user['priv'])
91
95
 
92
96
  groups_arr = []
93
97
  groups = _user_to_groups(user)
94
- groups.each { |group| groups_arr << group[SNMP_USER_GROUP_KEY].strip }
98
+ groups.each { |group| groups_arr << group['group'].strip }
95
99
 
96
- @@users[index] = SnmpUser.new(name, groups_arr, auth,
97
- "", priv, "", false, engineid.nil? ? "": engineid_str, false)
98
- }
100
+ users_hash[index] = SnmpUser.new(name, groups_arr, auth,
101
+ '', priv, '', false,
102
+ engineid.nil? ? '' : engineid_str,
103
+ false)
104
+ end
105
+ users_hash
99
106
  end
100
- @@users
101
- end
102
107
 
103
- def destroy
104
- # the parser doesn't care what the real value is but need to come to the
105
- # end of the parser chain. Hence we just pass in some fake values for
106
- # auth method and password
107
- @@node.config_set("snmp_user", "user", "no",
108
- @name, "",
109
- (auth_password.nil? or auth_password.empty?) ?
110
- "": "auth #{_auth_sym_to_str(auth_protocol)} #{auth_password}",
111
- (priv_password.nil? or priv_password.empty?) ?
112
- "": "priv #{_priv_sym_to_str(priv_protocol)} #{priv_password}",
113
- (auth_password.nil? or auth_password.empty?) ?
114
- "" : "localizedkey",
115
- @engine_id.empty? ? "" : "engineID #{@engine_id}")
116
- @@users.delete(@name + " " + @engine_id)
117
- end
108
+ def destroy
109
+ # The parser doesn't care what the real value is but need to come to the
110
+ # end of the parser chain. Hence we just pass in some fake values for
111
+ # auth method and password
112
+ unless auth_password.nil? || auth_password.empty?
113
+ auth_str = "auth #{_auth_sym_to_str(auth_protocol)} #{auth_password}"
114
+ local_str = 'localizedkey'
115
+ end
116
+ unless priv_password.nil? || priv_password.empty?
117
+ priv_str = "priv #{_priv_sym_to_str(priv_protocol)} #{priv_password}"
118
+ end
119
+ config_set('snmp_user', 'user', 'no',
120
+ @name, '', auth_str, priv_str, local_str,
121
+ @engine_id.empty? ? '' : "engineID #{@engine_id}")
122
+ SnmpUser.users.delete(@name + ' ' + @engine_id)
123
+ end
118
124
 
119
- attr_reader :name
125
+ attr_reader :name
120
126
 
121
- def groups
122
- @groups_arr
123
- end
127
+ def groups
128
+ @groups_arr
129
+ end
124
130
 
125
- def SnmpUser.default_groups
126
- [@@node.config_get_default("snmp_user", "group")]
127
- end
131
+ def self.default_groups
132
+ [config_get_default('snmp_user', 'group')]
133
+ end
128
134
 
129
- def auth_protocol
130
- @authproto
131
- end
135
+ def auth_protocol
136
+ @authproto
137
+ end
132
138
 
133
- def SnmpUser.default_auth_protocol
134
- _auth_str_to_sym(@@node.config_get_default("snmp_user", "auth_protocol"))
135
- end
139
+ def self.default_auth_protocol
140
+ _auth_str_to_sym(config_get_default('snmp_user', 'auth_protocol'))
141
+ end
136
142
 
137
- def SnmpUser.default_auth_password
138
- @@node.config_get_default("snmp_user", "auth_password")
139
- end
143
+ def self.default_auth_password
144
+ config_get_default('snmp_user', 'auth_password')
145
+ end
140
146
 
141
- def SnmpUser.auth_password(name, engine_id)
142
- if engine_id.empty?
143
- users = @@node.config_get("snmp_user", "auth_password")
147
+ def self.auth_password(name, engine_id)
148
+ if engine_id.empty?
149
+ users = config_get('snmp_user', 'auth_password')
144
150
  return nil if users.nil?
145
- users.each_entry { |user|
146
- return user[1] if user[0] == name
147
- }
148
- else
149
- users = @@node.config_get("snmp_user", "auth_password_with_engine_id")
151
+ users.each_entry { |user| return user[1] if user[0] == name }
152
+ else
153
+ users = config_get('snmp_user', 'auth_password_with_engine_id')
150
154
  return nil if users.nil?
151
- users.each_entry { |user|
152
- return user[1] if user[0] == name and user[2] == engine_id
153
- }
155
+ users.each_entry do |user|
156
+ return user[1] if user[0] == name && user[2] == engine_id
157
+ end
158
+ end
159
+ nil
154
160
  end
155
- nil
156
- end
157
161
 
158
- def auth_password
159
- SnmpUser.auth_password(@name, @engine_id)
160
- end
162
+ def auth_password
163
+ SnmpUser.auth_password(@name, @engine_id)
164
+ end
161
165
 
162
- def priv_protocol
163
- @privproto
164
- end
166
+ def priv_protocol
167
+ @privproto
168
+ end
165
169
 
166
- def SnmpUser.priv_password(name, engine_id)
167
- if engine_id.empty?
168
- users = @@node.config_get("snmp_user", "priv_password")
169
- unless users.nil?
170
- users.each_entry { |user|
171
- return user[1] if user[0] == name
172
- }
173
- end
174
- else
175
- users = @@node.config_get("snmp_user", "priv_password_with_engine_id")
176
- unless users.nil?
177
- users.each_entry { |user|
178
- return user[1] if user[0] == name and user[2] == engine_id
179
- }
170
+ def self.priv_password(name, engine_id)
171
+ if engine_id.empty?
172
+ users = config_get('snmp_user', 'priv_password')
173
+ unless users.nil?
174
+ users.each_entry { |user| return user[1] if user[0] == name }
175
+ end
176
+ else
177
+ users = config_get('snmp_user', 'priv_password_with_engine_id')
178
+ unless users.nil?
179
+ users.each_entry do |user|
180
+ return user[1] if user[0] == name && user[2] == engine_id
181
+ end
182
+ end
180
183
  end
184
+ nil
181
185
  end
182
- nil
183
- end
184
186
 
185
- def priv_password
186
- SnmpUser.priv_password(@name, @engine_id)
187
- end
187
+ def priv_password
188
+ SnmpUser.priv_password(@name, @engine_id)
189
+ end
188
190
 
189
- def SnmpUser.default_priv_protocol
190
- _priv_str_to_sym(@@node.config_get_default("snmp_user", "priv_protocol"))
191
- end
191
+ def self.default_priv_protocol
192
+ _priv_str_to_sym(config_get_default('snmp_user', 'priv_protocol'))
193
+ end
192
194
 
193
- def SnmpUser.default_priv_password
194
- @@node.config_get_default("snmp_user", "priv_password")
195
- end
195
+ def self.default_priv_password
196
+ config_get_default('snmp_user', 'priv_password')
197
+ end
196
198
 
197
- attr_reader :engine_id
199
+ attr_reader :engine_id
198
200
 
199
- def SnmpUser.default_engine_id
200
- @@node.config_get_default("snmp_user", "engine_id")
201
- end
201
+ def self.default_engine_id
202
+ config_get_default('snmp_user', 'engine_id')
203
+ end
204
+
205
+ # Passwords are hashed and so cannot be retrieved directly, but can be
206
+ # checked for equality. This is done by creating a fake user with the
207
+ # password and then comparing the hashes
208
+ def auth_password_equal?(input_pw, is_localized=false)
209
+ input_pw = input_pw.to_s unless input_pw.is_a?(String)
210
+ # If we provide no password, and no password present, it's a match!
211
+ return true if input_pw.empty? && auth_protocol == :none
212
+ # If we provide no password, but a password is present, or vice versa...
213
+ return false if input_pw.empty? || auth_protocol == :none
214
+ # OK, we have an input password, and a password is configured
215
+ current_pw = auth_password
216
+ if current_pw.nil?
217
+ fail "SNMP user #{@name} #{@engine_id} has auth #{auth_protocol} " \
218
+ "but no password?\n" + @@node.show('show run snmp all')
219
+ end
202
220
 
203
- # passwords are hashed and so cannot be retrieved directly, but can be
204
- # checked for equality. this is done by creating a fake user with the
205
- # password and then comparing the hashes
206
- def auth_password_equal?(passwd, is_localized=false)
207
- throw TypeError unless passwd.is_a?(String)
208
- return false if passwd.empty? or _auth_sym_to_str(auth_protocol).empty?
209
- dummypw = passwd
210
- pw = nil
211
-
212
- if is_localized
213
- # In this case, the password is hashed. We only need to get current
214
- # running config to compare
215
- pw = auth_password
216
- else
221
+ if is_localized
222
+ # In this case, the password is already hashed.
223
+ hashed_pw = input_pw
224
+ else
217
225
  # In this case passed in password is clear text while the running
218
- # config is hashed value. We need to hash the
219
- # passed in clear text to hash
220
-
221
- # create dummy user
222
- @@node.config_set("snmp_user", "user", "", "dummy_user", "",
223
- "auth #{_auth_sym_to_str(auth_protocol)} #{dummypw}",
224
- "", "",
225
- @engine_id.empty? ? "" : "engineID #{@engine_id}")
226
-
227
- # retrieve password hashes
228
- dummypw = SnmpUser.auth_password("dummy_user", @engine_id)
229
- pw = auth_password
230
-
231
- # delete dummy user
232
- @@node.config_set("snmp_user", "user", "no", "dummy_user", "",
233
- "auth #{_auth_sym_to_str(auth_protocol)} #{dummypw}",
234
- "", "localizedkey",
235
- @engine_id.empty? ? "" : "engineID #{@engine_id}")
226
+ # config is hashed value. We need to hash the passed in clear text.
227
+
228
+ # Create dummy user
229
+ config_set('snmp_user', 'user', '', 'dummy_user', '',
230
+ "auth #{_auth_sym_to_str(auth_protocol)} #{input_pw}",
231
+ '', '',
232
+ @engine_id.empty? ? '' : "engineID #{@engine_id}")
233
+
234
+ # Retrieve password hashes
235
+ hashed_pw = SnmpUser.auth_password('dummy_user', @engine_id)
236
+ if hashed_pw.nil?
237
+ fail "SNMP dummy user #{dummy_user} #{@engine_id} was configured " \
238
+ "but password is missing?\n" + @@node.show('show run snmp all')
239
+ end
240
+
241
+ # Delete dummy user
242
+ config_set('snmp_user', 'user', 'no', 'dummy_user', '',
243
+ "auth #{_auth_sym_to_str(auth_protocol)} #{hashed_pw}",
244
+ '', 'localizedkey',
245
+ @engine_id.empty? ? '' : "engineID #{@engine_id}")
246
+ end
247
+ hashed_pw == current_pw
236
248
  end
237
- return false if pw.nil? or dummypw.nil?
238
- pw == dummypw
239
- end
240
249
 
241
- def priv_password_equal?(passwd, is_localized=false)
242
- throw TypeError unless passwd.is_a?(String)
243
- return false if passwd.empty? or _auth_sym_to_str(auth_protocol).empty?
244
- dummypw = passwd
245
- pw = nil
246
-
247
- if is_localized
248
- # In this case, the password is hashed. We only need to get current
249
- # and compare directly
250
- pw = priv_password
251
- else
250
+ # Passwords are hashed and so cannot be retrieved directly, but can be
251
+ # checked for equality. This is done by creating a fake user with the
252
+ # password and then comparing the hashes
253
+ def priv_password_equal?(input_pw, is_localized=false)
254
+ input_pw = input_pw.to_s unless input_pw.is_a?(String)
255
+ # If no input password, and no password present, true!
256
+ return true if input_pw.empty? && priv_protocol == :none
257
+ # Otherwise, if either one is missing, false!
258
+ return false if input_pw.empty? || priv_protocol == :none
259
+ # Otherwise, we have both input and configured passwords to compare
260
+ current_pw = priv_password
261
+ if current_pw.nil?
262
+ fail "SNMP user #{@name} #{@engine_id} has priv #{priv_protocol} " \
263
+ "but no password?\n" + @@node.show('show run snmp all')
264
+ end
265
+
266
+ if is_localized
267
+ # In this case, the password is already hashed.
268
+ hashed_pw = input_pw
269
+ else
252
270
  # In this case passed in password is clear text while the running
253
- # config is hashed value. We need to hash the
254
- # passed in clear text to hash
255
-
256
- # create dummy user
257
- @@node.config_set("snmp_user", "user", "", "dummy_user", "",
258
- "auth #{_auth_sym_to_str(auth_protocol)} #{dummypw}",
259
- "priv #{_priv_sym_to_str(priv_protocol)} #{dummypw}",
260
- "",
261
- @engine_id.empty? ? "" : "engineID #{@engine_id}")
262
-
263
- # retrieve password hashes
264
- dummypw = SnmpUser.priv_password("dummy_user", @engine_id)
265
- pw = priv_password
266
-
267
- # delete dummy user
268
- @@node.config_set("snmp_user", "user", "no", "dummy_user", "",
269
- "auth #{_auth_sym_to_str(auth_protocol)} #{dummypw}",
270
- "priv #{_priv_sym_to_str(priv_protocol)} #{dummypw}",
271
- "localizedkey",
272
- @engine_id.empty? ? "" : "engineID #{@engine_id}")
271
+ # config is hashed value. We need to hash the passed in clear text.
272
+
273
+ # Create dummy user
274
+ config_set('snmp_user', 'user', '', 'dummy_user', '',
275
+ "auth #{_auth_sym_to_str(auth_protocol)} #{input_pw}",
276
+ "priv #{_priv_sym_to_str(priv_protocol)} #{input_pw}",
277
+ '',
278
+ @engine_id.empty? ? '' : "engineID #{@engine_id}")
279
+
280
+ # Retrieve password hashes
281
+ dummyau = SnmpUser.auth_password('dummy_user', @engine_id)
282
+ hashed_pw = SnmpUser.priv_password('dummy_user', @engine_id)
283
+ if hashed_pw.nil?
284
+ fail "SNMP dummy user #{dummy_user} #{@engine_id} was configured " \
285
+ "but password is missing?\n" + @@node.show('show run snmp all')
286
+ end
287
+
288
+ # Delete dummy user
289
+ config_set('snmp_user', 'user', 'no', 'dummy_user', '',
290
+ "auth #{_auth_sym_to_str(auth_protocol)} #{dummyau}",
291
+ "priv #{_priv_sym_to_str(priv_protocol)} #{hashed_pw}",
292
+ 'localizedkey',
293
+ @engine_id.empty? ? '' : "engineID #{@engine_id}")
294
+ end
295
+ hashed_pw == current_pw
273
296
  end
274
- return false if pw.nil? or dummypw.nil?
275
- pw == dummypw
276
- end
277
297
 
278
- private
298
+ private
279
299
 
280
- def _auth_sym_to_str(sym)
281
- case sym
282
- when :sha
283
- return "sha"
284
- when :md5
285
- return "md5"
286
- else
287
- return ""
300
+ def _auth_sym_to_str(sym)
301
+ case sym
302
+ when :sha
303
+ return 'sha'
304
+ when :md5
305
+ return 'md5'
306
+ else
307
+ return ''
308
+ end
288
309
  end
289
- end
290
310
 
291
- def _priv_sym_to_str(sym)
292
- case sym
293
- when :des
294
- return "" # no protocol specified defaults to DES
295
- when :aes128
296
- return "aes-128"
297
- else
298
- return ""
311
+ def _priv_sym_to_str(sym)
312
+ case sym
313
+ when :des
314
+ return '' # no protocol specified defaults to DES
315
+ when :aes128
316
+ return 'aes-128'
317
+ else
318
+ return ''
319
+ end
299
320
  end
300
- end
301
321
 
302
- def _auth_str_to_sym(str)
303
- SnmpUser._auth_str_to_sym(str)
304
- end
322
+ def _auth_str_to_sym(str)
323
+ SnmpUser._auth_str_to_sym(str)
324
+ end
305
325
 
306
- # must be class method b/c it's used by default methods
307
- def SnmpUser._auth_str_to_sym(str)
308
- case str
309
- when /sha/i
310
- return :sha
311
- when /md5/i
312
- return :md5
313
- else
314
- return :none
326
+ # must be class method b/c it's used by default methods
327
+ def self._auth_str_to_sym(str)
328
+ case str
329
+ when /sha/i
330
+ return :sha
331
+ when /md5/i
332
+ return :md5
333
+ else
334
+ return :none
335
+ end
315
336
  end
316
- end
317
337
 
318
- def _priv_str_to_sym(str)
319
- SnmpUser._priv_str_to_sym(str)
320
- end
338
+ def _priv_str_to_sym(str)
339
+ SnmpUser._priv_str_to_sym(str)
340
+ end
321
341
 
322
- def SnmpUser._priv_str_to_sym(str)
323
- case str
324
- when /des/i
325
- return :des
326
- when /aes/i
327
- return :aes128
328
- else
329
- return :none
342
+ def self._priv_str_to_sym(str)
343
+ case str
344
+ when /des/i
345
+ return :des
346
+ when /aes/i
347
+ return :aes128
348
+ else
349
+ return :none
350
+ end
330
351
  end
331
- end
332
352
 
333
- def SnmpUser._user_to_groups(user_hash)
334
- return [] if user_hash.nil?
335
- groups = user_hash["TABLE_groups"]["ROW_groups"] unless
336
- user_hash["TABLE_groups"].nil?
337
- return [] if groups.nil?
338
- groups = [groups] if groups.is_a?(Hash)
339
- groups
353
+ def self._user_to_groups(user_hash)
354
+ return [] if user_hash.nil?
355
+ groups = user_hash['TABLE_groups']['ROW_groups'] unless
356
+ user_hash['TABLE_groups'].nil?
357
+ return [] if groups.nil?
358
+ groups = [groups] if groups.is_a?(Hash)
359
+ groups
360
+ end
340
361
  end
341
362
  end
342
- end