puppet_x_eos_eapi 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/Gemfile +24 -0
- data/LICENSE.txt +202 -0
- data/README.md +87 -0
- data/Rakefile +1 -0
- data/lib/puppet_x/eos/autoload.rb +57 -0
- data/lib/puppet_x/eos/eapi.rb +259 -0
- data/lib/puppet_x/eos/module_base.rb +37 -0
- data/lib/puppet_x/eos/modules/daemon.rb +109 -0
- data/lib/puppet_x/eos/modules/extension.rb +167 -0
- data/lib/puppet_x/eos/modules/interface.rb +180 -0
- data/lib/puppet_x/eos/modules/ipinterface.rb +133 -0
- data/lib/puppet_x/eos/modules/mlag.rb +268 -0
- data/lib/puppet_x/eos/modules/ntp.rb +129 -0
- data/lib/puppet_x/eos/modules/ospf.rb +129 -0
- data/lib/puppet_x/eos/modules/portchannel.rb +277 -0
- data/lib/puppet_x/eos/modules/radius.rb +367 -0
- data/lib/puppet_x/eos/modules/snmp.rb +177 -0
- data/lib/puppet_x/eos/modules/switchport.rb +255 -0
- data/lib/puppet_x/eos/modules/system.rb +138 -0
- data/lib/puppet_x/eos/modules/tacacs.rb +302 -0
- data/lib/puppet_x/eos/modules/vlan.rb +179 -0
- data/lib/puppet_x/eos/modules/vxlan.rb +132 -0
- data/lib/puppet_x/eos/provider.rb +71 -0
- data/lib/puppet_x/eos/version.rb +41 -0
- data/lib/puppet_x/net_dev/eos_api.rb +1011 -0
- data/lib/puppet_x/net_dev/eos_api/common_methods.rb +27 -0
- data/lib/puppet_x/net_dev/eos_api/snmp_methods.rb +647 -0
- data/lib/puppet_x/net_dev/eos_api/version.rb +8 -0
- data/lib/puppet_x_eos_eapi.rb +4 -0
- data/puppet_x_eos_eapi.gemspec +31 -0
- data/spec/fixtures/fixture_all_portchannel_modes.json +8 -0
- data/spec/fixtures/fixture_all_portchannels_detailed.json +15 -0
- data/spec/fixtures/fixture_create_vlan_error.json +17 -0
- data/spec/fixtures/fixture_create_vlan_success.json +12 -0
- data/spec/fixtures/fixture_eapi_conf.yaml +4 -0
- data/spec/fixtures/fixture_enable_configure_vlan_3111_name_foo.json +14 -0
- data/spec/fixtures/fixture_enable_configure_vlan_foo_name_bar.json +19 -0
- data/spec/fixtures/fixture_get_snmp_communities_non_existent_acl.yaml +2 -0
- data/spec/fixtures/fixture_get_snmp_location_westeros.json +5 -0
- data/spec/fixtures/fixture_portchannel_min_links_1.json +8 -0
- data/spec/fixtures/fixture_portchannel_min_links_2.json +8 -0
- data/spec/fixtures/fixture_running_config.yaml +1 -0
- data/spec/fixtures/fixture_running_configuration_radius_configured.yaml +30 -0
- data/spec/fixtures/fixture_running_configuration_radius_default.yaml +29 -0
- data/spec/fixtures/fixture_running_configuration_radius_server_groups.yaml +38 -0
- data/spec/fixtures/fixture_running_configuration_radius_servers.yaml +34 -0
- data/spec/fixtures/fixture_running_configuration_tacacs_configured.yaml +38 -0
- data/spec/fixtures/fixture_running_configuration_tacacs_default.yaml +38 -0
- data/spec/fixtures/fixture_running_configuration_tacacs_groups.yaml +1 -0
- data/spec/fixtures/fixture_running_configuration_tacacs_groups_3.yaml +43 -0
- data/spec/fixtures/fixture_running_configuration_tacacs_servers.yaml +41 -0
- data/spec/fixtures/fixture_s4_show_etherchannel_detailed.json +9 -0
- data/spec/fixtures/fixture_show_flowcontrol_et1.json +5 -0
- data/spec/fixtures/fixture_show_interfaces.json +297 -0
- data/spec/fixtures/fixture_show_interfaces_switchport_format_text.json +9 -0
- data/spec/fixtures/fixture_show_port_channel_summary_2_lags.json +9 -0
- data/spec/fixtures/fixture_show_port_channel_summary_static.json +9 -0
- data/spec/fixtures/fixture_show_snmp_community.yaml +2 -0
- data/spec/fixtures/fixture_show_snmp_contact_empty.json +5 -0
- data/spec/fixtures/fixture_show_snmp_contact_name.json +5 -0
- data/spec/fixtures/fixture_show_snmp_disabled.json +5 -0
- data/spec/fixtures/fixture_show_snmp_enabled.json +5 -0
- data/spec/fixtures/fixture_show_snmp_host.yaml +2 -0
- data/spec/fixtures/fixture_show_snmp_host_duplicates.yaml +2 -0
- data/spec/fixtures/fixture_show_snmp_host_more_duplicates.yaml +2 -0
- data/spec/fixtures/fixture_show_snmp_location_empty.json +5 -0
- data/spec/fixtures/fixture_show_snmp_trap.yaml +2 -0
- data/spec/fixtures/fixture_show_snmp_user.yaml +2 -0
- data/spec/fixtures/fixture_show_snmp_user_raw_text.yaml +1 -0
- data/spec/fixtures/fixture_show_vlan.json +37 -0
- data/spec/fixtures/fixture_show_vlan_3110.json +18 -0
- data/spec/fixtures/fixture_show_vlan_4000.json +18 -0
- data/spec/fixtures/fixture_snmp_host_opts.yaml +11 -0
- data/spec/spec_helper.rb +21 -0
- data/spec/support/fixtures.rb +104 -0
- data/spec/unit/puppet_x/eos/eapi_spec.rb +182 -0
- data/spec/unit/puppet_x/eos/module_base_spec.rb +26 -0
- data/spec/unit/puppet_x/eos/modules/daemon_spec.rb +110 -0
- data/spec/unit/puppet_x/eos/modules/extension_spec.rb +197 -0
- data/spec/unit/puppet_x/eos/modules/fixtures/daemon_getall.json +3 -0
- data/spec/unit/puppet_x/eos/modules/fixtures/extension_getall.json +28 -0
- data/spec/unit/puppet_x/eos/modules/fixtures/hostname.json +6 -0
- data/spec/unit/puppet_x/eos/modules/fixtures/interface_getall.json +509 -0
- data/spec/unit/puppet_x/eos/modules/fixtures/ipinterface_getall.json +56 -0
- data/spec/unit/puppet_x/eos/modules/fixtures/mlag_get.json +21 -0
- data/spec/unit/puppet_x/eos/modules/fixtures/mlag_get_interfaces.json +18 -0
- data/spec/unit/puppet_x/eos/modules/fixtures/ntp_get.json +5 -0
- data/spec/unit/puppet_x/eos/modules/fixtures/ospf_instance_getall.json +58 -0
- data/spec/unit/puppet_x/eos/modules/fixtures/portchannel_get.json +54 -0
- data/spec/unit/puppet_x/eos/modules/fixtures/portchannel_getlacpmode.json +5 -0
- data/spec/unit/puppet_x/eos/modules/fixtures/portchannel_getmembers.json +5 -0
- data/spec/unit/puppet_x/eos/modules/fixtures/portchannel_po1.json +7 -0
- data/spec/unit/puppet_x/eos/modules/fixtures/snmp_get.json +14 -0
- data/spec/unit/puppet_x/eos/modules/fixtures/switchport_get.json +5 -0
- data/spec/unit/puppet_x/eos/modules/fixtures/switchport_get_et1.json +7 -0
- data/spec/unit/puppet_x/eos/modules/fixtures/switchport_getall_interfaces.json +230 -0
- data/spec/unit/puppet_x/eos/modules/fixtures/system_domain_list.json +5 -0
- data/spec/unit/puppet_x/eos/modules/fixtures/system_domain_name.json +5 -0
- data/spec/unit/puppet_x/eos/modules/fixtures/system_hostname.json +6 -0
- data/spec/unit/puppet_x/eos/modules/fixtures/system_name_servers.json +5 -0
- data/spec/unit/puppet_x/eos/modules/fixtures/vlan_getall.json +123 -0
- data/spec/unit/puppet_x/eos/modules/fixtures/vxlan_get.json +24 -0
- data/spec/unit/puppet_x/eos/modules/interface_spec.rb +281 -0
- data/spec/unit/puppet_x/eos/modules/ipinterface_spec.rb +143 -0
- data/spec/unit/puppet_x/eos/modules/mlag_spec.rb +349 -0
- data/spec/unit/puppet_x/eos/modules/ntp_spec.rb +136 -0
- data/spec/unit/puppet_x/eos/modules/ospf_spec.rb +143 -0
- data/spec/unit/puppet_x/eos/modules/portchannel_spec.rb +357 -0
- data/spec/unit/puppet_x/eos/modules/radius_spec.rb +509 -0
- data/spec/unit/puppet_x/eos/modules/snmp_spec.rb +202 -0
- data/spec/unit/puppet_x/eos/modules/switchport_get_et1.json +7 -0
- data/spec/unit/puppet_x/eos/modules/switchport_spec.rb +307 -0
- data/spec/unit/puppet_x/eos/modules/system_spec.rb +170 -0
- data/spec/unit/puppet_x/eos/modules/tacacs_spec.rb +448 -0
- data/spec/unit/puppet_x/eos/modules/vlan_spec.rb +244 -0
- data/spec/unit/puppet_x/eos/modules/vxlan_spec.rb +189 -0
- data/spec/unit/puppet_x/eos/provider_spec.rb +35 -0
- data/spec/unit/puppet_x/net_dev/eos_api/common_methods_spec.rb +34 -0
- data/spec/unit/puppet_x/net_dev/eos_api/snmp_methods_spec.rb +842 -0
- data/spec/unit/puppet_x/net_dev/eos_api_spec.rb +1000 -0
- 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
|