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,170 @@
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
+ require 'spec_helper'
33
+ require 'puppet_x/eos/modules/system'
34
+
35
+ describe PuppetX::Eos::System do
36
+ let(:eapi) { double }
37
+ let(:instance) { PuppetX::Eos::System.new eapi }
38
+
39
+ context 'when initializing a new System instance' do
40
+ subject { instance }
41
+ it { is_expected.to be_a_kind_of PuppetX::Eos::System }
42
+ end
43
+
44
+ context 'with Eapi#enable' do
45
+ context '#get_hostname' do
46
+ subject { instance.get_hostname }
47
+
48
+ let :response do
49
+ dir = File.dirname(__FILE__)
50
+ file = File.join(dir, 'fixtures/system_hostname.json')
51
+ JSON.load(File.read(file))
52
+ end
53
+
54
+ before :each do
55
+ allow(eapi).to receive(:enable).with('show hostname')
56
+ .and_return(response)
57
+ end
58
+
59
+ it { is_expected.to eq 'localhost' }
60
+ end
61
+
62
+ context '#get_domain_name' do
63
+ subject { instance.get_domain_name }
64
+
65
+ let :response do
66
+ dir = File.dirname(__FILE__)
67
+ file = File.join(dir, 'fixtures/system_domain_name.json')
68
+ JSON.load(File.read(file))
69
+ end
70
+
71
+ before :each do
72
+ allow(eapi).to receive(:enable).with('show ip domain-name', 'text')
73
+ .and_return(response)
74
+ end
75
+
76
+ it { is_expected.to eq 'arista.com' }
77
+ end
78
+
79
+ context '#get_name_servers' do
80
+ subject { instance.get_name_servers }
81
+
82
+ let :response do
83
+ dir = File.dirname(__FILE__)
84
+ file = File.join(dir, 'fixtures/system_name_servers.json')
85
+ JSON.load(File.read(file))
86
+ end
87
+
88
+ before :each do
89
+ allow(eapi).to receive(:enable).with('show ip name-server', 'text')
90
+ .and_return(response)
91
+ end
92
+
93
+ it { is_expected.to eq %w(1.2.3.4 5.6.7.8) }
94
+ end
95
+
96
+ context '#get_domain_list' do
97
+ subject { instance.get_domain_list }
98
+
99
+ let :response do
100
+ dir = File.dirname(__FILE__)
101
+ file = File.join(dir, 'fixtures/system_domain_list.json')
102
+ JSON.load(File.read(file))
103
+ end
104
+
105
+ before :each do
106
+ allow(eapi).to receive(:enable)
107
+ .with('show running-config section ip\sdomain-list', 'text')
108
+ .and_return response
109
+ end
110
+
111
+ it { is_expected.to eq %w(arista.com arista.net) }
112
+ end
113
+ end
114
+
115
+ context 'with Eapi#config' do
116
+ context '#set_hostname' do
117
+ subject { instance.set_hostname(name) }
118
+
119
+ let(:name) { (0...50).map { ('a'..'z').to_a[rand(26)] }.join }
120
+
121
+ before :each do
122
+ allow(eapi).to receive(:config).with("hostname #{name}")
123
+ .and_return([{}])
124
+ end
125
+
126
+ it { is_expected.to be_truthy }
127
+ end
128
+
129
+ context '#set_domain_name' do
130
+ subject { instance.set_domain_name('arista.com') }
131
+
132
+ before :each do
133
+ allow(eapi).to receive(:config).with('ip domain-name arista.com')
134
+ .and_return([{}])
135
+ end
136
+
137
+ it { is_expected.to be_truthy }
138
+ end
139
+
140
+ context '#set_name_servers' do
141
+ subject { instance.set_name_servers(servers) }
142
+
143
+ let(:servers) { %w(1.2.3.4 5.6.7.8) }
144
+
145
+ before :each do
146
+ servers.each do |srv|
147
+ allow(eapi).to receive(:config).with("ip name-server #{srv}")
148
+ .and_return([{}])
149
+ end
150
+ end
151
+
152
+ it { is_expected.to be_truthy }
153
+ end
154
+
155
+ context '#set_domain_list' do
156
+ subject { instance.set_domain_list(domains) }
157
+
158
+ let(:domains) { %w(arista.com arista.net) }
159
+
160
+ before :each do
161
+ domains.each do |name|
162
+ allow(eapi).to receive(:config).with("ip domain-list #{name}")
163
+ .and_return([{}])
164
+ end
165
+ end
166
+
167
+ it { is_expected.to be_truthy }
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,448 @@
1
+ require 'spec_helper'
2
+
3
+ describe PuppetX::Eos::Tacacs do
4
+ let(:eapi) { PuppetX::Eos::Eapi.new }
5
+ let(:instance) { described_class.new(eapi) }
6
+
7
+ describe '#getall' do
8
+ subject { instance.getall }
9
+
10
+ context 'when all tacacs settings are the default' do
11
+ before :each do
12
+ allow(instance).to receive(:running_configuration)
13
+ .and_return(fixture(:running_configuration_tacacs_default))
14
+ end
15
+
16
+ describe 'the return value' do
17
+ it { is_expected.to be_an Array }
18
+ it 'has only one resource hash' do
19
+ expect(subject.size).to eq(1)
20
+ end
21
+ end
22
+
23
+ describe 'the single resource hash' do
24
+ subject { instance.getall.first }
25
+
26
+ it { is_expected.to include(name: 'settings') }
27
+ it { is_expected.to include(enable: true) }
28
+ it { is_expected.to_not include(:key) }
29
+ it { is_expected.to_not include(:key_format) }
30
+ it { is_expected.to include(timeout: 5) }
31
+ end
32
+ end
33
+
34
+ context 'when a global timeout and key are configured' do
35
+ before :each do
36
+ allow(instance).to receive(:running_configuration)
37
+ .and_return(fixture(:running_configuration_tacacs_configured))
38
+ end
39
+
40
+ describe 'the return value' do
41
+ it { is_expected.to be_an Array }
42
+ it 'has only one resource hash' do
43
+ expect(subject.size).to eq(1)
44
+ end
45
+ end
46
+
47
+ describe 'the single resource hash' do
48
+ subject { instance.getall.first }
49
+
50
+ it { is_expected.to include(name: 'settings') }
51
+ it { is_expected.to include(enable: true) }
52
+ it { is_expected.to include(key: '070E234F1F5B4A') }
53
+ it { is_expected.to include(key_format: 7) }
54
+ it { is_expected.to include(timeout: 7) }
55
+ end
56
+ end
57
+ end
58
+
59
+ describe '#set_global_key' do
60
+ let :opts do
61
+ { key: '070E234F1F5B4A', key_format: 7 }
62
+ end
63
+
64
+ before :each do
65
+ allow(instance.api).to receive(:config)
66
+ end
67
+
68
+ subject { instance.set_global_key(opts) }
69
+
70
+ context 'when key_format is 7 (hashed)' do
71
+ it 'uses Eapi#config to set the global key' do
72
+ expect(instance.api).to receive(:config)
73
+ .with('tacacs-server key 7 070E234F1F5B4A')
74
+ subject
75
+ end
76
+ end
77
+
78
+ context 'when key_format is not provided' do
79
+ let :opts do
80
+ { key: '070E234F1F5B4A' }
81
+ end
82
+
83
+ it 'assumes a default format of 7' do
84
+ expect(instance.api).to receive(:config)
85
+ .with('tacacs-server key 7 070E234F1F5B4A')
86
+ subject
87
+ end
88
+ end
89
+
90
+ context 'when key is not provided' do
91
+ let :opts do
92
+ { key_format: 7 }
93
+ end
94
+
95
+ it 'raises ArgumentError that key is required' do
96
+ expect { subject }
97
+ .to raise_error ArgumentError, /key option is required/
98
+ end
99
+ end
100
+
101
+ context 'when the API call returns [{}]' do
102
+ before :each do
103
+ allow(instance.api).to receive(:config)
104
+ .and_return([{}])
105
+ end
106
+
107
+ it { is_expected.to eq true }
108
+ end
109
+
110
+ context 'when the API call does not return [{}]' do
111
+ before :each do
112
+ allow(instance.api).to receive(:config)
113
+ .and_return([{'errors' => ['blarg']}])
114
+ end
115
+
116
+ it { is_expected.to eq false }
117
+ end
118
+ end
119
+
120
+ describe '#set_timeout' do
121
+ let :opts do
122
+ { timeout: 50 }
123
+ end
124
+
125
+ before :each do
126
+ allow(instance.api).to receive(:config).and_return([{}])
127
+ end
128
+
129
+ subject { instance.set_timeout(opts) }
130
+
131
+ context 'when timeout is not provided' do
132
+ let :opts do
133
+ {}
134
+ end
135
+
136
+ it 'raises ArgumentError' do
137
+ expect { subject }
138
+ .to raise_error ArgumentError, /timeout option is required/
139
+ end
140
+ end
141
+
142
+ context 'when timeout is provided' do
143
+ it 'calls Eapi#config to configure tacacs-server timeout' do
144
+ expect(instance.api).to receive(:config)
145
+ .with('tacacs-server timeout 50')
146
+ .and_return([{}])
147
+ subject
148
+ end
149
+ end
150
+
151
+ context 'when the API call returns [{}]' do
152
+ it { is_expected.to eq true }
153
+ end
154
+
155
+ context 'when the API call does not return [{}]' do
156
+ before :each do
157
+ allow(instance.api).to receive(:config)
158
+ .and_return([{'errors' => ['blarg']}])
159
+ end
160
+
161
+ it { is_expected.to eq false }
162
+ end
163
+ end
164
+
165
+ describe '#servers' do
166
+ subject { instance.servers }
167
+
168
+ context 'when there are tacacs servers defined' do
169
+ before :each do
170
+ allow(instance).to receive(:running_configuration)
171
+ .and_return(fixture(:running_configuration_tacacs_servers))
172
+ end
173
+ it { is_expected.to be_an Array }
174
+ it 'parses 4 results' do
175
+ expect(subject.size).to eq(4)
176
+ end
177
+ it 'includes only Hashes as elements of the Array' do
178
+ subject.each { |result| expect(result).to be_a Hash }
179
+ end
180
+ it 'includes hostname in every result' do
181
+ subject.each { |result| expect(result).to include(:hostname) }
182
+ end
183
+ it 'includes port in every result' do
184
+ subject.each { |result| expect(result).to include(:port) }
185
+ end
186
+ it 'includes one entry with multiplex true' do
187
+ expected = {
188
+ port: 4949,
189
+ hostname: "1.2.3.4",
190
+ timeout: 6,
191
+ key_format: 7,
192
+ key: "06070D221D1C5A",
193
+ multiplex: true
194
+ }
195
+ expect(subject).to include(expected)
196
+ end
197
+ end
198
+
199
+ context 'when there are no tacacs servers defined' do
200
+ before :each do
201
+ allow(instance).to receive(:running_configuration)
202
+ .and_return(fixture(:running_configuration_tacacs_default))
203
+ end
204
+ it { is_expected.to be_an Array }
205
+ it { is_expected.to be_empty }
206
+ end
207
+ end
208
+
209
+ describe '#update_server' do
210
+ subject { instance.update_server(opts) }
211
+
212
+ let :opts do
213
+ { hostname: '10.11.12.13' }
214
+ end
215
+
216
+ before :each do
217
+ allow(instance.api).to receive(:config).and_return([{}])
218
+ end
219
+
220
+ context 'when only hostname is provided' do
221
+ it 'calls Eapi#config to configure tacacs-server host' do
222
+ expect(instance.api).to receive(:config)
223
+ .with('tacacs-server host 10.11.12.13')
224
+ .and_return([{}])
225
+ subject
226
+ end
227
+ end
228
+
229
+ context 'when configuring a single-connection server' do
230
+ let :opts do
231
+ { hostname: '10.11.12.13', multiplex: true }
232
+ end
233
+ it 'calls Eapi#config to with single-connection' do
234
+ expect(instance.api).to receive(:config)
235
+ .with('tacacs-server host 10.11.12.13 single-connection')
236
+ .and_return([{}])
237
+ subject
238
+ end
239
+ end
240
+ end
241
+
242
+ describe '#remove_server' do
243
+ subject { instance.remove_server(opts) }
244
+
245
+ let :opts do
246
+ { hostname: '10.11.12.13' }
247
+ end
248
+
249
+ before :each do
250
+ allow(instance.api).to receive(:config).and_return([{}])
251
+ end
252
+
253
+ context 'when only hostname is provided' do
254
+ it 'calls Eapi#config to configure no tacacs-server host' do
255
+ expect(instance.api).to receive(:config)
256
+ .with('no tacacs-server host 10.11.12.13')
257
+ .and_return([{}])
258
+ subject
259
+ end
260
+ end
261
+
262
+ context 'when hostname and port are provided' do
263
+ let :opts do
264
+ { hostname: '10.11.12.13', port: 4949 }
265
+ end
266
+ it 'calls Eapi#config to configure no tacacs-server host port 4949' do
267
+ expect(instance.api).to receive(:config)
268
+ .with('no tacacs-server host 10.11.12.13 port 4949')
269
+ .and_return([{}])
270
+ subject
271
+ end
272
+ end
273
+ end
274
+
275
+ describe '#server_groups' do
276
+ context 'with two server groups defined' do
277
+ before :each do
278
+ allow(instance).to receive(:running_configuration)
279
+ .and_return(fixture(:running_configuration_tacacs_groups))
280
+ end
281
+
282
+ describe 'the return value' do
283
+ subject { instance.server_groups }
284
+
285
+ it { is_expected.to be_an Array }
286
+ it 'returns 2 server groups' do
287
+ expect(subject.size).to eq 2
288
+ end
289
+
290
+ describe 'each value of the return Array' do
291
+ it 'each value is a hash' do
292
+ subject.each {|v| expect(v).to be_a Hash }
293
+ end
294
+ it 'each value has a name attribute' do
295
+ subject.each {|v| expect(v).to include(name: /TAC-GR/) }
296
+ end
297
+ it 'each value has a servers attribute' do
298
+ subject.each {|v| expect(v).to include(servers: Array) }
299
+ end
300
+ end
301
+
302
+ describe 'each server attribute' do
303
+ it 'is a hash' do
304
+ subject.each do |group|
305
+ group[:servers].each do |server|
306
+ expect(server).to be_a Hash
307
+ end
308
+ end
309
+ end
310
+ it 'includes the hostname, port attributes' do
311
+ subject.each do |group|
312
+ group[:servers].each do |server|
313
+ expect(server).to include(hostname: String, port: Fixnum)
314
+ end
315
+ end
316
+ end
317
+ end
318
+ end
319
+ end
320
+
321
+ context 'with a server group with no servers' do
322
+ before :each do
323
+ allow(instance).to receive(:running_configuration)
324
+ .and_return(fixture(:running_configuration_tacacs_groups_3))
325
+ end
326
+
327
+ describe 'the return value' do
328
+ subject { instance.server_groups }
329
+
330
+ it { is_expected.to be_an Array }
331
+ it 'returns 3 server groups' do
332
+ expect(subject.size).to eq 3
333
+ end
334
+
335
+ describe 'each value of the return Array' do
336
+ it 'each value is a hash' do
337
+ subject.each {|v| expect(v).to be_a Hash }
338
+ end
339
+ it 'each value has a name attribute' do
340
+ subject.each {|v| expect(v).to include(name: /TAC-GR/) }
341
+ end
342
+ it 'each value has a servers attribute' do
343
+ subject.each {|v| expect(v).to include(servers: Array) }
344
+ end
345
+ end
346
+
347
+ describe 'each server attribute' do
348
+ it 'is a hash' do
349
+ subject.each do |group|
350
+ group[:servers].each do |server|
351
+ expect(server).to be_a Hash
352
+ end
353
+ end
354
+ end
355
+ it 'includes the hostname, port attributes' do
356
+ subject.each do |group|
357
+ group[:servers].each do |server|
358
+ expect(server).to include(hostname: String, port: Fixnum)
359
+ end
360
+ end
361
+ end
362
+ end
363
+ end
364
+ end
365
+
366
+ context 'with no server groups defined' do
367
+ before :each do
368
+ allow(instance).to receive(:running_configuration)
369
+ .and_return(fixture(:running_configuration_tacacs_default))
370
+ end
371
+
372
+ describe 'the return value' do
373
+ subject { instance.server_groups }
374
+
375
+ it { is_expected.to be_an Array }
376
+ it 'returns 0 server groups' do
377
+ expect(subject.size).to eq 0
378
+ end
379
+ end
380
+ end
381
+ end
382
+
383
+ describe '#update_server_group' do
384
+ before :each do
385
+ allow(instance.api).to receive(:config).and_return([{}])
386
+ end
387
+
388
+ subject { instance.update_server_group(opts) }
389
+
390
+ context 'with no servers specified' do
391
+ let :opts do
392
+ { name: 'TAC-GR-EMPTY', servers: [] }
393
+ end
394
+
395
+ it { is_expected.to eq(true) }
396
+
397
+ it 're-creates the server group after clearing it' do
398
+ expect(instance.api).to receive(:config)
399
+ .with('no aaa group server tacacs+ TAC-GR-EMPTY').ordered
400
+ expect(instance.api).to receive(:config)
401
+ .with(['aaa group server tacacs+ TAC-GR-EMPTY']).ordered
402
+ subject
403
+ end
404
+ end
405
+
406
+ context 'with two servers specified' do
407
+ let :opts do
408
+ { name: 'TAC-GR',
409
+ servers: [
410
+ { hostname: 'one' },
411
+ { hostname: 'two', port: 50 }
412
+ ]
413
+ }
414
+ end
415
+
416
+ it { is_expected.to eq(true) }
417
+ it 'uses the default port when not provided' do
418
+ expect(instance.api).to receive(:config)
419
+ .with([/TAC-GR/, 'server one port 49', String ])
420
+ subject
421
+ end
422
+ it 'creates the group of servers using a single config call' do
423
+ expect(instance.api).to receive(:config)
424
+ .with([/TAC-GR/, /server one/, /server two/])
425
+ subject
426
+ end
427
+ end
428
+ end
429
+
430
+ describe '#remove_server_group' do
431
+ let :opts do
432
+ { name: 'TAC-GR' }
433
+ end
434
+
435
+ subject { instance.remove_server_group(opts) }
436
+
437
+ before :each do
438
+ allow(instance.api).to receive(:config).and_return([{}])
439
+ end
440
+
441
+ it { is_expected.to eq true }
442
+ it 'removes the group specified by name' do
443
+ expect(instance.api).to receive(:config)
444
+ .with('no aaa group server tacacs+ TAC-GR')
445
+ subject
446
+ end
447
+ end
448
+ end