puppet_x_eos_eapi 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/Gemfile +24 -0
  4. data/LICENSE.txt +202 -0
  5. data/README.md +87 -0
  6. data/Rakefile +1 -0
  7. data/lib/puppet_x/eos/autoload.rb +57 -0
  8. data/lib/puppet_x/eos/eapi.rb +259 -0
  9. data/lib/puppet_x/eos/module_base.rb +37 -0
  10. data/lib/puppet_x/eos/modules/daemon.rb +109 -0
  11. data/lib/puppet_x/eos/modules/extension.rb +167 -0
  12. data/lib/puppet_x/eos/modules/interface.rb +180 -0
  13. data/lib/puppet_x/eos/modules/ipinterface.rb +133 -0
  14. data/lib/puppet_x/eos/modules/mlag.rb +268 -0
  15. data/lib/puppet_x/eos/modules/ntp.rb +129 -0
  16. data/lib/puppet_x/eos/modules/ospf.rb +129 -0
  17. data/lib/puppet_x/eos/modules/portchannel.rb +277 -0
  18. data/lib/puppet_x/eos/modules/radius.rb +367 -0
  19. data/lib/puppet_x/eos/modules/snmp.rb +177 -0
  20. data/lib/puppet_x/eos/modules/switchport.rb +255 -0
  21. data/lib/puppet_x/eos/modules/system.rb +138 -0
  22. data/lib/puppet_x/eos/modules/tacacs.rb +302 -0
  23. data/lib/puppet_x/eos/modules/vlan.rb +179 -0
  24. data/lib/puppet_x/eos/modules/vxlan.rb +132 -0
  25. data/lib/puppet_x/eos/provider.rb +71 -0
  26. data/lib/puppet_x/eos/version.rb +41 -0
  27. data/lib/puppet_x/net_dev/eos_api.rb +1011 -0
  28. data/lib/puppet_x/net_dev/eos_api/common_methods.rb +27 -0
  29. data/lib/puppet_x/net_dev/eos_api/snmp_methods.rb +647 -0
  30. data/lib/puppet_x/net_dev/eos_api/version.rb +8 -0
  31. data/lib/puppet_x_eos_eapi.rb +4 -0
  32. data/puppet_x_eos_eapi.gemspec +31 -0
  33. data/spec/fixtures/fixture_all_portchannel_modes.json +8 -0
  34. data/spec/fixtures/fixture_all_portchannels_detailed.json +15 -0
  35. data/spec/fixtures/fixture_create_vlan_error.json +17 -0
  36. data/spec/fixtures/fixture_create_vlan_success.json +12 -0
  37. data/spec/fixtures/fixture_eapi_conf.yaml +4 -0
  38. data/spec/fixtures/fixture_enable_configure_vlan_3111_name_foo.json +14 -0
  39. data/spec/fixtures/fixture_enable_configure_vlan_foo_name_bar.json +19 -0
  40. data/spec/fixtures/fixture_get_snmp_communities_non_existent_acl.yaml +2 -0
  41. data/spec/fixtures/fixture_get_snmp_location_westeros.json +5 -0
  42. data/spec/fixtures/fixture_portchannel_min_links_1.json +8 -0
  43. data/spec/fixtures/fixture_portchannel_min_links_2.json +8 -0
  44. data/spec/fixtures/fixture_running_config.yaml +1 -0
  45. data/spec/fixtures/fixture_running_configuration_radius_configured.yaml +30 -0
  46. data/spec/fixtures/fixture_running_configuration_radius_default.yaml +29 -0
  47. data/spec/fixtures/fixture_running_configuration_radius_server_groups.yaml +38 -0
  48. data/spec/fixtures/fixture_running_configuration_radius_servers.yaml +34 -0
  49. data/spec/fixtures/fixture_running_configuration_tacacs_configured.yaml +38 -0
  50. data/spec/fixtures/fixture_running_configuration_tacacs_default.yaml +38 -0
  51. data/spec/fixtures/fixture_running_configuration_tacacs_groups.yaml +1 -0
  52. data/spec/fixtures/fixture_running_configuration_tacacs_groups_3.yaml +43 -0
  53. data/spec/fixtures/fixture_running_configuration_tacacs_servers.yaml +41 -0
  54. data/spec/fixtures/fixture_s4_show_etherchannel_detailed.json +9 -0
  55. data/spec/fixtures/fixture_show_flowcontrol_et1.json +5 -0
  56. data/spec/fixtures/fixture_show_interfaces.json +297 -0
  57. data/spec/fixtures/fixture_show_interfaces_switchport_format_text.json +9 -0
  58. data/spec/fixtures/fixture_show_port_channel_summary_2_lags.json +9 -0
  59. data/spec/fixtures/fixture_show_port_channel_summary_static.json +9 -0
  60. data/spec/fixtures/fixture_show_snmp_community.yaml +2 -0
  61. data/spec/fixtures/fixture_show_snmp_contact_empty.json +5 -0
  62. data/spec/fixtures/fixture_show_snmp_contact_name.json +5 -0
  63. data/spec/fixtures/fixture_show_snmp_disabled.json +5 -0
  64. data/spec/fixtures/fixture_show_snmp_enabled.json +5 -0
  65. data/spec/fixtures/fixture_show_snmp_host.yaml +2 -0
  66. data/spec/fixtures/fixture_show_snmp_host_duplicates.yaml +2 -0
  67. data/spec/fixtures/fixture_show_snmp_host_more_duplicates.yaml +2 -0
  68. data/spec/fixtures/fixture_show_snmp_location_empty.json +5 -0
  69. data/spec/fixtures/fixture_show_snmp_trap.yaml +2 -0
  70. data/spec/fixtures/fixture_show_snmp_user.yaml +2 -0
  71. data/spec/fixtures/fixture_show_snmp_user_raw_text.yaml +1 -0
  72. data/spec/fixtures/fixture_show_vlan.json +37 -0
  73. data/spec/fixtures/fixture_show_vlan_3110.json +18 -0
  74. data/spec/fixtures/fixture_show_vlan_4000.json +18 -0
  75. data/spec/fixtures/fixture_snmp_host_opts.yaml +11 -0
  76. data/spec/spec_helper.rb +21 -0
  77. data/spec/support/fixtures.rb +104 -0
  78. data/spec/unit/puppet_x/eos/eapi_spec.rb +182 -0
  79. data/spec/unit/puppet_x/eos/module_base_spec.rb +26 -0
  80. data/spec/unit/puppet_x/eos/modules/daemon_spec.rb +110 -0
  81. data/spec/unit/puppet_x/eos/modules/extension_spec.rb +197 -0
  82. data/spec/unit/puppet_x/eos/modules/fixtures/daemon_getall.json +3 -0
  83. data/spec/unit/puppet_x/eos/modules/fixtures/extension_getall.json +28 -0
  84. data/spec/unit/puppet_x/eos/modules/fixtures/hostname.json +6 -0
  85. data/spec/unit/puppet_x/eos/modules/fixtures/interface_getall.json +509 -0
  86. data/spec/unit/puppet_x/eos/modules/fixtures/ipinterface_getall.json +56 -0
  87. data/spec/unit/puppet_x/eos/modules/fixtures/mlag_get.json +21 -0
  88. data/spec/unit/puppet_x/eos/modules/fixtures/mlag_get_interfaces.json +18 -0
  89. data/spec/unit/puppet_x/eos/modules/fixtures/ntp_get.json +5 -0
  90. data/spec/unit/puppet_x/eos/modules/fixtures/ospf_instance_getall.json +58 -0
  91. data/spec/unit/puppet_x/eos/modules/fixtures/portchannel_get.json +54 -0
  92. data/spec/unit/puppet_x/eos/modules/fixtures/portchannel_getlacpmode.json +5 -0
  93. data/spec/unit/puppet_x/eos/modules/fixtures/portchannel_getmembers.json +5 -0
  94. data/spec/unit/puppet_x/eos/modules/fixtures/portchannel_po1.json +7 -0
  95. data/spec/unit/puppet_x/eos/modules/fixtures/snmp_get.json +14 -0
  96. data/spec/unit/puppet_x/eos/modules/fixtures/switchport_get.json +5 -0
  97. data/spec/unit/puppet_x/eos/modules/fixtures/switchport_get_et1.json +7 -0
  98. data/spec/unit/puppet_x/eos/modules/fixtures/switchport_getall_interfaces.json +230 -0
  99. data/spec/unit/puppet_x/eos/modules/fixtures/system_domain_list.json +5 -0
  100. data/spec/unit/puppet_x/eos/modules/fixtures/system_domain_name.json +5 -0
  101. data/spec/unit/puppet_x/eos/modules/fixtures/system_hostname.json +6 -0
  102. data/spec/unit/puppet_x/eos/modules/fixtures/system_name_servers.json +5 -0
  103. data/spec/unit/puppet_x/eos/modules/fixtures/vlan_getall.json +123 -0
  104. data/spec/unit/puppet_x/eos/modules/fixtures/vxlan_get.json +24 -0
  105. data/spec/unit/puppet_x/eos/modules/interface_spec.rb +281 -0
  106. data/spec/unit/puppet_x/eos/modules/ipinterface_spec.rb +143 -0
  107. data/spec/unit/puppet_x/eos/modules/mlag_spec.rb +349 -0
  108. data/spec/unit/puppet_x/eos/modules/ntp_spec.rb +136 -0
  109. data/spec/unit/puppet_x/eos/modules/ospf_spec.rb +143 -0
  110. data/spec/unit/puppet_x/eos/modules/portchannel_spec.rb +357 -0
  111. data/spec/unit/puppet_x/eos/modules/radius_spec.rb +509 -0
  112. data/spec/unit/puppet_x/eos/modules/snmp_spec.rb +202 -0
  113. data/spec/unit/puppet_x/eos/modules/switchport_get_et1.json +7 -0
  114. data/spec/unit/puppet_x/eos/modules/switchport_spec.rb +307 -0
  115. data/spec/unit/puppet_x/eos/modules/system_spec.rb +170 -0
  116. data/spec/unit/puppet_x/eos/modules/tacacs_spec.rb +448 -0
  117. data/spec/unit/puppet_x/eos/modules/vlan_spec.rb +244 -0
  118. data/spec/unit/puppet_x/eos/modules/vxlan_spec.rb +189 -0
  119. data/spec/unit/puppet_x/eos/provider_spec.rb +35 -0
  120. data/spec/unit/puppet_x/net_dev/eos_api/common_methods_spec.rb +34 -0
  121. data/spec/unit/puppet_x/net_dev/eos_api/snmp_methods_spec.rb +842 -0
  122. data/spec/unit/puppet_x/net_dev/eos_api_spec.rb +1000 -0
  123. metadata +369 -0
@@ -0,0 +1,129 @@
1
+ #
2
+ # Copyright (c) 2014, Arista Networks, Inc.
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are
7
+ # met:
8
+ #
9
+ # Redistributions of source code must retain the above copyright notice,
10
+ # this list of conditions and the following disclaimer.
11
+ #
12
+ # Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in the
14
+ # documentation and/or other materials provided with the distribution.
15
+ #
16
+ # Neither the name of Arista Networks nor the names of its
17
+ # contributors may be used to endorse or promote products derived from
18
+ # this software without specific prior written permission.
19
+ #
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ARISTA NETWORKS
24
+ # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27
+ # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28
+ # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29
+ # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
30
+ # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
+ #
32
+
33
+ ##
34
+ # PuppetX is the toplevel namespace for working with Arista EOS nodes
35
+ module PuppetX
36
+ ##
37
+ # Eos is module namesapce for working with the EOS command API
38
+ module Eos
39
+ ##
40
+ # The Ospf class provides a base class instance for working with
41
+ # instances of OSPF
42
+ #
43
+ class Ospf
44
+ ##
45
+ # Initialize instance of Ospf
46
+ #
47
+ # @param [PuppetX::Eos::Eapi] api An instance of Eapi
48
+ #
49
+ # @return [PuppetX::Eos::Ospf]
50
+ def initialize(api)
51
+ @api = api
52
+ end
53
+
54
+ ##
55
+ # Returns the base interface hash representing physical and logical
56
+ # interfaces in EOS using eAPI
57
+ #
58
+ # Example
59
+ # {
60
+ # "instances": {
61
+ # "1": { "router_id": <String> }
62
+ # }
63
+ # }
64
+ #
65
+ # @return [Hash] returns an Hash
66
+ def getall
67
+ result = @api.enable('show ip ospf')
68
+ instances = {}
69
+ result[0]['vrfs']['default']['instList'].map do |inst, attrs|
70
+ instances[inst] = { router_id: attrs['routerId'] }
71
+ end
72
+ { instances: instances }
73
+ end
74
+
75
+ ##
76
+ # Creates a new instance of OSPF routing
77
+ #
78
+ # @param [String] inst The instance id to create
79
+ #
80
+ # @return [Boolean] True if the commands succeed otherwise False
81
+ def create(inst)
82
+ @api.config("router ospf #{inst}") == [{}]
83
+ end
84
+
85
+ ##
86
+ # Deletes an instance of OSPF routing
87
+ #
88
+ # @param [String] inst The instance id to delete
89
+ #
90
+ # @return [Boolean] True if the commands succeed otherwise False
91
+ def delete(inst)
92
+ @api.config("no router ospf #{inst}") == [{}]
93
+ end
94
+
95
+ ##
96
+ # Defaults an instance of OSPF routing
97
+ #
98
+ # @param [String] inst The instance id to delete
99
+ #
100
+ # @return [Boolean] True if the commands succeed otherwise False
101
+ def default(inst)
102
+ @api.config("default router ospf #{inst}") == [{}]
103
+ end
104
+
105
+ ##
106
+ # Configures the OSPF process router-id
107
+ #
108
+ # @param [String] inst The instance of ospf to configure
109
+ # @param [Hash] opts The configuration parameters
110
+ # @option opts [string] :value The value to set the router-id to
111
+ # @option opts [Boolean] :default The value should be set to default
112
+ #
113
+ # @return [Boolean] True if the commands succeed otherwise False
114
+ def set_router_id(inst, opts = {})
115
+ value = opts[:value] || false
116
+ default = opts[:default] || false
117
+
118
+ cmds = ["router ospf #{inst}"]
119
+ case default
120
+ when true
121
+ cmds << 'default router-id'
122
+ when false
123
+ cmds << (value ? "router-id #{value}" : 'no router-id')
124
+ end
125
+ @api.config(cmds) == [{}, {}]
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,277 @@
1
+ #
2
+ # Copyright (c) 2014, Arista Networks, Inc.
3
+ # All rights reserved.
4
+ #
5
+ # Redistribution and use in source and binary forms, with or without
6
+ # modification, are permitted provided that the following conditions are
7
+ # met:
8
+ #
9
+ # Redistributions of source code must retain the above copyright notice,
10
+ # this list of conditions and the following disclaimer.
11
+ #
12
+ # Redistributions in binary form must reproduce the above copyright
13
+ # notice, this list of conditions and the following disclaimer in the
14
+ # documentation and/or other materials provided with the distribution.
15
+ #
16
+ # Neither the name of Arista Networks nor the names of its
17
+ # contributors may be used to endorse or promote products derived from
18
+ # this software without specific prior written permission.
19
+ #
20
+ # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21
+ # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22
+ # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23
+ # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ARISTA NETWORKS
24
+ # BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25
+ # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26
+ # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27
+ # BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28
+ # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29
+ # OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
30
+ # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
+ #
32
+
33
+ ##
34
+ # PuppetX is the toplevel namespace for working with Arista EOS nodes
35
+ module PuppetX
36
+ ##
37
+ # Eos is module namesapce for working with the EOS command API
38
+ module Eos
39
+ ##
40
+ # The Portchannel class provides a base class instance for working with
41
+ # logical link aggregation interfaces.
42
+ #
43
+ class Portchannel
44
+ ##
45
+ # Initialize innstance of Portchannel
46
+ #
47
+ # @param [PuppetX::Eos::Eapi] api An instance of Eapi
48
+ #
49
+ # @return [PuppetX::Eos::Interface]
50
+ def initialize(api)
51
+ @api = api
52
+ end
53
+
54
+ ##
55
+ # Retrievess a port channel interface from the running-configuration
56
+ #
57
+ # Example
58
+ # {
59
+ # "name": <String>,
60
+ # "lacp_mode": [active, passive, off],
61
+ # "members": [Array],
62
+ # "lacp_fallback": [static, individual],
63
+ # "lacp_timeout": <0-900>
64
+ # }
65
+ #
66
+ # @param [String] name The name of the port-channel interface
67
+ #
68
+ # @return [Hash] A hash of the port channel attributes and properties
69
+ def get(name)
70
+ members = get_members name
71
+ result = @api.enable("show interfaces #{name}")
72
+ interface = result.first['interfaces']
73
+
74
+ attr_hash = { name: name }
75
+ attr_hash[:members] = members
76
+ attr_hash[:lacp_mode] = get_lacp_mode members
77
+ attr_hash[:lacp_fallback] = get_lacp_fallback interface
78
+ attr_hash[:lacp_timeout] = interface['fallbackTimeout']
79
+ attr_hash
80
+ end
81
+
82
+ ##
83
+ # Retrieves all logical port-channel interfaces from the running config
84
+ #
85
+ # @return [Array] an array of port-channel attribute hashes
86
+ def getall
87
+ result = @api.enable('show interfaces')
88
+ interfaces = result.first['interfaces']
89
+ resp = []
90
+ interfaces.each do |key, value|
91
+ resp << get(key) if value['hardware'] == 'portChannel'
92
+ end
93
+ resp
94
+ end
95
+
96
+ ##
97
+ # Retreives the member interfaces for the specified channel group
98
+ #
99
+ # @param [String] name The name of the port-channel interface to return
100
+ # members for
101
+ #
102
+ # @return [Array] An array of interface names that are members of the
103
+ # specified channel group id
104
+ def get_members(name)
105
+ result = @api.enable("show #{name} all-ports",
106
+ format: 'text')
107
+ result.first['output'].scan(/Ethernet\d+/)
108
+ end
109
+
110
+ ##
111
+ # Create a logical port-channel interface
112
+ #
113
+ # @param [String] name The name of the interface to create
114
+ #
115
+ # @return [Boolean] True if the create succeeds otherwise False
116
+ def create(name)
117
+ @api.config("interface #{name}") == [{}]
118
+ end
119
+
120
+ ##
121
+ # Deletes a logical port-channel interface
122
+ #
123
+ # @param [String] name The name of the interface to create
124
+ #
125
+ # @return [Boolean] True if the create succeeds otherwise False
126
+ def delete(name)
127
+ @api.config("no interface #{name}") == [{}]
128
+ end
129
+
130
+ ##
131
+ # Defaults a logical port-channel interface
132
+ #
133
+ # @param [String] name The name of the interface to create
134
+ #
135
+ # @return [Boolean] True if the create succeeds otherwise False
136
+ def default(name)
137
+ @api.config("default interface #{name}") == [{}]
138
+ end
139
+
140
+ ##
141
+ # Adds a new member interface to the channel group
142
+ #
143
+ # @param [String] name The name of the port channel to add the interface
144
+ # @param [String] member The name of the interface to add
145
+ #
146
+ # @return [Boolean] True if the create succeeds otherwise False
147
+ def add_member(name, member)
148
+ id = name.match(/\d+/)
149
+ @api.config(["interface #{member}",
150
+ "channel-group #{id} mode on"]) == [{}, {}]
151
+ end
152
+
153
+ ##
154
+ # Removes a member interface from the channel group
155
+ #
156
+ # @param [String] name The name of the port-channel to add the interface
157
+ # @param [String] member The name of the interface to remove
158
+ #
159
+ # @return [Boolean] True if the create succeeds otherwise False
160
+ def remove_member(_name, member)
161
+ @api.config(["interface #{member}", 'no channel-group']) == [{}, {}]
162
+ end
163
+
164
+ ##
165
+ # Configures the member interfaces for the port-channel interface
166
+ #
167
+ # @param [String] name The name of the port-channel to assign the
168
+ # the members to
169
+ # @param [Array] members The array of members to add to the port-channel
170
+ def set_members(name, members)
171
+ current = get_members(name)
172
+ (current - members).each do |member|
173
+ remove_member(name, member)
174
+ end
175
+ (members - current).each do |member|
176
+ add_member(name, member)
177
+ end
178
+ end
179
+
180
+ ##
181
+ # Configures the lacp mode for the interface
182
+ #
183
+ # @param [String] name The name of the port-channel interface
184
+ # @param [String] mode The LACP mode to configure
185
+ #
186
+ # @return [Boolean] True if the create succeeds otherwise False
187
+ def set_lacp_mode(name, mode)
188
+ id = name.match(/\d+/)
189
+ members = get_members name
190
+
191
+ commands = []
192
+ config = []
193
+
194
+ members.each do |member|
195
+ commands << "interface #{member}" << 'no channel-group'
196
+ config << "interface #{member}" << "channel-group #{id} mode #{mode}"
197
+ end
198
+
199
+ config.unshift(*commands)
200
+ result = @api.config(config)
201
+ config.size == result.size
202
+ end
203
+
204
+ ##
205
+ # Configures the lacp fallback value
206
+ #
207
+ # @param [String] name The name of the interface to configure
208
+ # @param [Hash] opts The configuration parameters for the interface
209
+ # @option opts [string] :value The value to set the value to
210
+ # @option opts [Boolean] :default The value should be set to default
211
+ #
212
+ # @return [Boolean] True if the commands succeed otherwise False
213
+ def set_lacp_fallback(name, opts = {})
214
+ value = opts[:value]
215
+ default = opts[:default] || false
216
+
217
+ cmds = ["interface #{name}"]
218
+ case default
219
+ when true
220
+ cmds << 'default port-channel lacp fallback'
221
+ when false
222
+ cmds << (value.nil? ? "no port-channel lacp fallback #{value}" : \
223
+ "port-channel lacp fallback #{value}")
224
+ end
225
+ @api.config(cmds) == [{}, {}]
226
+ end
227
+
228
+ ##
229
+ # Configures the lacp fallback timeout value
230
+ #
231
+ # @param [String] name The name of the interface to configure
232
+ # @param [Hash] opts The configuration parameters for the interface
233
+ # @option opts [string] :value The value to set the timeout to
234
+ # @option opts [Boolean] :default The value should be set to default
235
+ #
236
+ # @return [Boolean] True if the commands succeed otherwise False
237
+ def set_lacp_timeout(name, opts = {})
238
+ value = opts[:value]
239
+ default = opts[:default] || false
240
+
241
+ cmds = ["interface #{name}"]
242
+ case default
243
+ when true
244
+ cmds << 'default port-channel lacp fallback timeout'
245
+ when false
246
+ cmds << (value.nil? ? 'no port-channel lacp fallback timeout' : \
247
+ "port-channel lacp fallback timeout #{value}")
248
+ end
249
+ @api.config(cmds) == [{}, {}]
250
+ end
251
+
252
+ private
253
+
254
+ def get_lacp_mode(members)
255
+ return '' if members.empty?
256
+ name = members.first
257
+ result = @api.enable("show running-config interfaces #{name}",
258
+ format: 'text')
259
+ m = /channel-group\s\d+\smode\s(?<lacp>.*)/
260
+ .match(result.first['output'])
261
+ m['lacp']
262
+ end
263
+
264
+ def get_lacp_fallback(attr_hash)
265
+ if attr_hash['fallbackEnabled']
266
+ case attr_hash['fallbackEnabledType']
267
+ when 'fallbackStatic'
268
+ fallback = 'static'
269
+ when 'fallbackIndividual'
270
+ fallback = 'individual'
271
+ end
272
+ end
273
+ fallback || ''
274
+ end
275
+ end
276
+ end
277
+ end
@@ -0,0 +1,367 @@
1
+ # encoding: utf-8
2
+
3
+ module PuppetX
4
+ ##
5
+ # Eos is module namesapce for working with the EOS command API
6
+ module Eos
7
+ ##
8
+ # Radius provides instance methods to retrieve and set radius configuration
9
+ # values.
10
+ class Radius < ModuleBase
11
+ DEFAULT_AUTH_PORT = 1812
12
+ DEFAULT_ACCT_PORT = 1813
13
+
14
+ # Regular expression to extract a radius server's attributes from the
15
+ # running-configuration text. The explicit [ ] spaces enable line
16
+ # wrappping and indentation with the /x flag.
17
+ SERVER_REGEXP = /radius-server[ ]host[ ](.*?)
18
+ (?:[ ]auth-port[ ](\d+))?
19
+ (?:[ ]acct-port[ ](\d+))?
20
+ (?:[ ]timeout[ ](\d+))?
21
+ (?:[ ]deadtime[ ](\d+))?
22
+ (?:[ ]retransmit[ ](\d+))?
23
+ (?:[ ]key[ ](\d+)[ ](\w+))?\s/x
24
+
25
+ GROUP_MEMBER_REGEXP = /server[ ](.*?)
26
+ (?:[ ]auth-port[ ](\d+))?
27
+ (?:[ ]acct-port[ ](\d+))?\s/x
28
+
29
+ # Regular expression to extract a radius server's attributes from the
30
+ # running-configuration text. The explicit [ ] spaces enable line
31
+ # wrappping and indentation with the /x flag.
32
+ SERVER_GROUP_REGEXP = /aaa group server radius (.*)/
33
+
34
+ ##
35
+ # getall Returns an Array with a single resource Hash describing the
36
+ # current state of the global radius configuration on the target device.
37
+ # This method is intended to be used by a provider's instances class
38
+ # method.
39
+ #
40
+ # The resource hash returned contains the following information:
41
+ # * name: ('settings')
42
+ # * enable: (true | false) if radius functionality is enabled. This is
43
+ # always true for EOS.
44
+ # * key: (String) the key either in plaintext or hashed format
45
+ # * key_format: (Integer) e.g. 0 or 7
46
+ # * timeout: (Integer) seconds before the timeout period ends
47
+ # * retransmit_count: (Integer), e.g. 3, attempts after first timeout
48
+ # expiry.
49
+ #
50
+ # @api public
51
+ #
52
+ # @return [Array<Hash>] Single element Array of resource hashes
53
+ def getall
54
+ config = running_configuration
55
+ rsrc_hsh = radius_global_defaults
56
+ rsrc_hsh.merge!(parse_global_key(config))
57
+ rsrc_hsh.merge!(parse_global_timeout(config))
58
+ rsrc_hsh.merge!(parse_global_retransmit(config))
59
+ [rsrc_hsh]
60
+ end
61
+
62
+ ##
63
+ # servers returns an Array of radius server resource hashes. Each hash
64
+ # describes the current state of the radius server and is suitable for
65
+ # use in initializing a radius_server provider.
66
+ #
67
+ # The resource hash returned contains the following information:
68
+ # * hostname: hostname or ip address
69
+ # * key: (String) the key either in plaintext or hashed format
70
+ # * key_format: (Fixnum) e.g. 0 or 7
71
+ # * timeout: (Fixnum) seconds before the timeout period ends
72
+ # * retransmit_count: (Integer), e.g. 3, attempts after first timeout
73
+ # expiry.
74
+ # * group: (String) Server group associated with this server.
75
+ # * deadtime: (Fixnum) number of minutes to ignore an unresponsive
76
+ # server.
77
+ # * acct_port: (Fixnum) Port number to use for accounting.
78
+ # * accounting_only: (Boolean) Enable this server for accounting only.
79
+ # * auth_port: (Fixnum) Port number to use for authentication
80
+ #
81
+ # @api public
82
+ #
83
+ # @return [Array<Hash<Symbol,Object>>] Array of resource hashes
84
+ def servers
85
+ config = running_configuration
86
+ tuples = config.scan(SERVER_REGEXP)
87
+ tuples.map do |(host, authp, acctp, tout, dead, tries, keyfm, key)|
88
+ hsh = { auth_port: DEFAULT_AUTH_PORT, acct_port: DEFAULT_ACCT_PORT }
89
+ hsh[:hostname] = host if host
90
+ hsh[:auth_port] = authp.to_i if authp
91
+ hsh[:acct_port] = acctp.to_i if acctp
92
+ hsh[:timeout] = tout.to_i if tout
93
+ hsh[:retransmit_count] = tries.to_i if tries
94
+ hsh[:deadtime] = dead.to_i if dead
95
+ hsh[:key_format] = keyfm.to_i if keyfm
96
+ hsh[:key] = key if key
97
+ hsh
98
+ end
99
+ end
100
+
101
+ ##
102
+ # server_groups retrieves a list of radius server groups from the target
103
+ # device.
104
+ #
105
+ # @api public
106
+ #
107
+ # @return [Array<Hash<Symbol,Object>>] Array of resource hashes
108
+ def server_groups
109
+ config = running_configuration
110
+ tuples = config.scan(SERVER_GROUP_REGEXP)
111
+ tuples.map do |(name)|
112
+ { name: name, servers: parse_group_servers(config, name) }
113
+ end
114
+ end
115
+
116
+ ##
117
+ # parse_group_servers parses the list of servers associated with a radius
118
+ # server group given a group name and a running configuration text.
119
+ #
120
+ # @param [String] config The running configuration text.
121
+ #
122
+ # @param [String] name The name of the server group to parse.
123
+ #
124
+ # @api private
125
+ #
126
+ # @return [Array<Hash<Symbol,Object>] Array of server attributes
127
+ def parse_group_servers(config, name)
128
+ regexp = /aaa group server radius #{name}(.*?)!/m
129
+ mdata = regexp.match(config)
130
+ if mdata
131
+ tuples = mdata[1].scan(GROUP_MEMBER_REGEXP)
132
+ tuples.collect do |(hostname, auth_port, acct_port)|
133
+ {
134
+ hostname: hostname,
135
+ auth_port: auth_port ? auth_port.to_i : DEFAULT_AUTH_PORT,
136
+ acct_port: acct_port ? acct_port.to_i : DEFAULT_ACCT_PORT
137
+ }
138
+ end
139
+ else
140
+ Array.new
141
+ end
142
+ end
143
+
144
+ ##
145
+ # update_server_group updates a radius server group given an Array of
146
+ # server attributes and the name of the server group. The update happens
147
+ # by first deleting the existing group if it exists then creating it
148
+ # again with all of the specified servers.
149
+ #
150
+ # @param [String] name The name of the server group to update
151
+ #
152
+ # @param [Array<Hash<Symbol,Object>>] servers The array of servers to
153
+ # associate with the server group. This hash should have at least the
154
+ # :hostname key.
155
+ #
156
+ # @api public
157
+ #
158
+ # @return [Boolean] true if no errors
159
+ def update_server_group(opts = {})
160
+ cmd = "aaa group server radius #{opts[:name]}"
161
+ api.config("no #{cmd}")
162
+ cmds = [cmd]
163
+ opts[:servers].each do |hsh|
164
+ server = "server #{hsh[:hostname]}"
165
+ server << " auth-port #{hsh[:auth_port] || DEFAULT_AUTH_PORT}"
166
+ server << " acct-port #{hsh[:acct_port] || DEFAULT_ACCT_PORT}"
167
+ cmds << server
168
+ end
169
+ result = api.config(cmds)
170
+ !result.find { |r| r != {} }
171
+ end
172
+
173
+ ##
174
+ # remove_server_group removes a radius server group by name. This API
175
+ # call maps to the `no aaa group server radius <name>` command.
176
+ #
177
+ # @option opts [String] :name ('RAD-SV2') The name of the radius server
178
+ # group to remove.
179
+ #
180
+ # @api public
181
+ #
182
+ # @return [Boolean] true if no errors
183
+ def remove_server_group(opts = {})
184
+ result = api.config("no aaa group server radius #{opts[:name]}")
185
+ result == [{}]
186
+ end
187
+
188
+ ##
189
+ # update_server configures a radius server resource on the target device.
190
+ # This API method maps to the `radius server host` command, e.g.
191
+ # `radius-server host 10.11.12.13 auth-port 1024 acct-port 2048 timeout
192
+ # 30 retransmit 5 key 7 011204070A5955`
193
+ #
194
+ # @api public
195
+ #
196
+ # @return [Boolean] true if there are no errors
197
+ def update_server(opts = {})
198
+ retransmit = opts[:retransmit_count]
199
+ key_format = opts[:key_format] || 7
200
+ cmd = "radius-server host #{opts[:hostname]}"
201
+ cmd << " auth-port #{opts[:auth_port]}" if opts[:auth_port]
202
+ cmd << " acct-port #{opts[:acct_port]}" if opts[:acct_port]
203
+ cmd << " timeout #{opts[:timeout]}" if opts[:timeout]
204
+ cmd << " deadtime #{opts[:deadtime]}" if opts[:deadtime]
205
+ cmd << " retransmit #{retransmit}" if retransmit
206
+ cmd << " key #{key_format} #{opts[:key]}" if opts[:key]
207
+ result = api.config(cmd)
208
+ result == [{}]
209
+ end
210
+
211
+ ##
212
+ # remove_server removes the SNMP server identified by the hostname,
213
+ # auth_port, and acct_port attributes.
214
+ #
215
+ # @api public
216
+ #
217
+ # @return [Boolean] true if no errors
218
+ def remove_server(opts = {})
219
+ cmd = "no radius-server host #{opts[:hostname]}"
220
+ cmd << " auth-port #{opts[:auth_port]}" if opts[:auth_port]
221
+ cmd << " acct-port #{opts[:acct_port]}" if opts[:acct_port]
222
+ result = api.config(cmd)
223
+ result == [{}]
224
+ end
225
+
226
+ ##
227
+ # radius_global_defaults returns the default values for the radius_global
228
+ # resource. This is in a single method to keep the information in one
229
+ # place. If a value is explicitly configured to be the same as a default
230
+ # value it will not show up in the running configuration and as a result
231
+ # will not be parsed out by the parse instance methods. This method
232
+ # exposes the default values.
233
+ #
234
+ # @return [Array<Hash>] Single element Array of resource hashes
235
+ def radius_global_defaults
236
+ {
237
+ name: 'settings',
238
+ enable: true,
239
+ timeout: 5,
240
+ retransmit_count: 3
241
+ }
242
+ end
243
+ private :radius_global_defaults
244
+
245
+ ##
246
+ # parse_global_key takes a running configuration as a string and
247
+ # parses out the radius global key and global key format if it exists in
248
+ # the configuration. An empty Hash is returned if there is no global key
249
+ # configured. The intent of the Hash is to be merged into a property
250
+ # hash.
251
+ #
252
+ # @param [String] config The running configuration as a single string.
253
+ #
254
+ # @api private
255
+ #
256
+ # @return [Hash<Symbol,Object>] resource hash attributes
257
+ def parse_global_key(config)
258
+ rsrc_hsh = {}
259
+ (key_format, key) = config.scan(/radius-server key (\d+) (\w+)/).first
260
+ rsrc_hsh[:key_format] = key_format.to_i if key_format
261
+ rsrc_hsh[:key] = key if key
262
+ rsrc_hsh
263
+ end
264
+ private :parse_global_key
265
+
266
+ ##
267
+ # parse_global_timeout takes a running configuration as a string
268
+ # and parses out the radius global timeout if it exists in the
269
+ # configuration. An empty Hash is returned if there is no global timeout
270
+ # value configured. The intent of the Hash is to be merged into a
271
+ # property hash.
272
+ #
273
+ # @param [String] config The running configuration as a single string.
274
+ #
275
+ # @api private
276
+ #
277
+ # @return [Hash<Symbol,Object>] resource hash attributes
278
+ def parse_global_timeout(config)
279
+ rsrc_hsh = {}
280
+ timeout = config.scan(/radius-server timeout (\d+)/).first
281
+ # EOS default is 5 (does not show up in the running config)
282
+ rsrc_hsh[:timeout] = timeout.first.to_i if timeout
283
+ rsrc_hsh
284
+ end
285
+ private :parse_global_timeout
286
+
287
+ ##
288
+ # parse_global_retransmit takes a running configuration as a string and
289
+ # parses out the radius global retransmit count value if it exists in the
290
+ # configuration. An empty Hash is returned if there is no global timeout
291
+ # value configured. The intent of the Hash is to be merged into a
292
+ # property hash.
293
+ #
294
+ # @param [String] config The running configuration as a single string.
295
+ #
296
+ # @api private
297
+ #
298
+ # @return [Hash<Symbol,Object>] resource hash attributes
299
+ def parse_global_retransmit(config)
300
+ rsrc_hsh = {}
301
+ count = config.scan(/radius-server retransmit (\d+)/).first
302
+ # EOS default is 3 (does not show up in the running config)
303
+ rsrc_hsh[:retransmit_count] = count.first.to_i if count
304
+ rsrc_hsh
305
+ end
306
+ private :parse_global_retransmit
307
+
308
+ ##
309
+ # set_global_key configures the radius default key. This method maps to
310
+ # the `radius-server key` EOS configuration command, e.g. `radius-server
311
+ # key 7 070E234F1F5B4A`.
312
+ #
313
+ # @option opts [String] :key ('070E234F1F5B4A') The key value
314
+ #
315
+ # @option opts [Fixnum] :key_format (7) The key format, 0 for plaintext
316
+ # and 7 for a hashed value. 7 will be assumed if this option is not
317
+ # provided.
318
+ #
319
+ # @api public
320
+ #
321
+ # @return [Boolean] true if no errors
322
+ def set_global_key(opts = {})
323
+ format = opts[:key_format] || 7
324
+ key = opts[:key]
325
+ fail ArgumentError, 'key option is required' unless key
326
+ result = api.config("radius-server key #{format} #{key}")
327
+ result == [{}]
328
+ end
329
+
330
+ ##
331
+ # set_timeout configures the radius default timeout. This method maps to
332
+ # the `radius-server timeout` setting.
333
+ #
334
+ # @option opts [Fixnum] :timeout (50) The timeout in seconds to
335
+ # configure.
336
+ #
337
+ # @api public
338
+ #
339
+ # @return [Boolean] true if no errors
340
+ def set_timeout(opts = {})
341
+ timeout = opts[:timeout]
342
+ fail ArgumentError, 'timeout option is required' unless timeout
343
+ result = api.config("radius-server timeout #{timeout}")
344
+ result == [{}]
345
+ end
346
+
347
+ ##
348
+ # set_retransmit_count configures the radius default retransmit count.
349
+ # This method maps to the `radius-server retransmit` configuration
350
+ # command.
351
+ #
352
+ # @option opts [Fixnum] :retransmit_count (4) The number of times to
353
+ # retry an unresponsive server after the first timeout period.
354
+ #
355
+ # @api public
356
+ #
357
+ # @return [Boolean] true if no errors
358
+ def set_retransmit_count(opts = {})
359
+ retransmit_count = opts[:retransmit_count]
360
+ fail ArgumentError,
361
+ 'retransmit_count option is required' unless retransmit_count
362
+ result = api.config("radius-server retransmit #{retransmit_count}")
363
+ result == [{}]
364
+ end
365
+ end
366
+ end
367
+ end