vagrant-cloudstack 1.4.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -1
  3. data/.travis.yml +13 -9
  4. data/CHANGELOG.md +30 -0
  5. data/Docker/Dockerfile +5 -8
  6. data/Docker/Dockerfile.chefdk_0_17 +2 -2
  7. data/Docker/Dockerfile.latest_dependencies +2 -2
  8. data/Docker/README.md +63 -35
  9. data/Gemfile +2 -2
  10. data/Gemfile.lock +307 -0
  11. data/README.md +3 -3
  12. data/Rakefile +2 -2
  13. data/build_rpm.sh +1 -1
  14. data/functional-tests/rsync/Vagrantfile.advanced_networking +1 -0
  15. data/functional-tests/vmlifecycle/Vagrantfile.advanced_networking +5 -7
  16. data/functional-tests/vmlifecycle/vmlifecycle_spec.rb +14 -2
  17. data/lib/vagrant-cloudstack/action/read_rdp_info.rb +9 -43
  18. data/lib/vagrant-cloudstack/action/read_ssh_info.rb +10 -44
  19. data/lib/vagrant-cloudstack/action/read_transport_info.rb +59 -0
  20. data/lib/vagrant-cloudstack/action/read_winrm_info.rb +10 -44
  21. data/lib/vagrant-cloudstack/action/run_instance.rb +607 -498
  22. data/lib/vagrant-cloudstack/action/terminate_instance.rb +17 -41
  23. data/lib/vagrant-cloudstack/config.rb +41 -166
  24. data/lib/vagrant-cloudstack/exceptions/exceptions.rb +7 -2
  25. data/lib/vagrant-cloudstack/service/cloudstack_resource_service.rb +17 -5
  26. data/lib/vagrant-cloudstack/version.rb +1 -1
  27. data/spec/spec_helper.rb +45 -0
  28. data/spec/vagrant-cloudstack/action/retrieve_public_ip_port_spec.rb +94 -0
  29. data/spec/vagrant-cloudstack/action/run_instance_spec.rb +609 -0
  30. data/spec/vagrant-cloudstack/action/terminate_instance_spec.rb +248 -0
  31. data/spec/vagrant-cloudstack/config_spec.rb +7 -7
  32. data/vagrant-cloudstack.gemspec +2 -1
  33. metadata +22 -10
  34. data/bootstrap.key +0 -27
@@ -0,0 +1,94 @@
1
+ require 'spec_helper'
2
+ require 'vagrant-cloudstack/action/read_transport_info'
3
+ require 'vagrant-cloudstack/config'
4
+ require 'fog'
5
+
6
+ describe VagrantPlugins::Cloudstack::Action::ReadTransportInfo do
7
+ let(:action) {VagrantPlugins::Cloudstack::Action::ReadTransportInfo.new }
8
+
9
+ describe '#retrieve_public_ip_port' do
10
+ subject { action.retrieve_public_ip_port(cloudstack_compute, domain_config, machine) }
11
+
12
+ let(:cloudstack_compute) { double('Fog::Compute::Cloudstack') }
13
+ let(:machine) { double('Vagrant::Machine')}
14
+
15
+ let(:data_dir) { double('Pathname') }
16
+ let(:pf_public_port_file) { double('Pathname') }
17
+
18
+ let(:pf_ip_address) { 'ip_address_in_config' }
19
+ let(:pf_ip_address_from_server) { 'ip_address_from_server' }
20
+ let(:pf_ip_address_id) { 'ID of ip_address_in_config' }
21
+ let(:pf_public_port) { 'public_port_in_config' }
22
+ let(:pf_public_port_from_file) { 'public_port_from_file' }
23
+
24
+ let(:domain_config) do
25
+ config = VagrantPlugins::Cloudstack::Config.new
26
+ config.domain_config :cloudstack do |cfg|
27
+ cfg.pf_ip_address = pf_ip_address
28
+ cfg.pf_public_port = pf_public_port
29
+ cfg.pf_ip_address_id = pf_ip_address_id
30
+ end
31
+ config.finalize!
32
+ config.get_domain_config(:cloudstack)
33
+ end
34
+
35
+ context 'without both ip address and port in config' do
36
+ it 'retrieves those configured values' do
37
+ should eq [pf_ip_address, pf_public_port]
38
+ end
39
+ end
40
+
41
+ context 'port not configured' do
42
+ let(:pf_public_port) { nil }
43
+
44
+ it 'retrieves the active port stored on filesystem' do
45
+ expect(machine).to receive(:data_dir).and_return(data_dir)
46
+ expect(data_dir).to receive(:join).and_return(pf_public_port_file)
47
+ expect(pf_public_port_file).to receive(:file?).and_return(true)
48
+ expect(File).to receive(:read).and_return(pf_public_port_from_file)
49
+
50
+ expect(subject).to eq [pf_ip_address, pf_public_port_from_file]
51
+ end
52
+ end
53
+
54
+ context 'only ID of ip address specified (and public port)' do
55
+ let(:pf_ip_address) { nil }
56
+
57
+ it 'resolves, and returns, the ip address from the ID' do
58
+ response = {
59
+ 'listpublicipaddressesresponse' => {
60
+ 'count' =>1,
61
+ 'publicipaddress' =>[{
62
+ 'id' => pf_ip_address_id,
63
+ 'ipaddress' => pf_ip_address_from_server,
64
+ 'allocated' => '2016-05-06T13:58:04+0200',
65
+ 'zoneid' => 'UUID',
66
+ 'zonename' => 'Name',
67
+ 'issourcenat' =>false,
68
+ 'account' => 'Name',
69
+ 'domainid' => 'UUID',
70
+ 'domain' => 'Name',
71
+ 'forvirtualnetwork' =>true,
72
+ 'isstaticnat' =>false,
73
+ 'issystem' =>false,
74
+ 'associatednetworkid' => 'UUID',
75
+ 'associatednetworkname' => 'Name',
76
+ 'networkid' => 'UUID',
77
+ 'aclid' => 'UUID',
78
+ 'state' => 'Allocated',
79
+ 'physicalnetworkid' => 'UUID',
80
+ 'vpcid' => 'UUID',
81
+ 'tags' =>[],
82
+ 'isportable' =>false
83
+ }]
84
+ }
85
+ }
86
+ expect(cloudstack_compute).to receive(:list_public_ip_addresses)
87
+ .with(:id => pf_ip_address_id)
88
+ .and_return(response)
89
+
90
+ expect(subject).to eq [pf_ip_address_from_server, pf_public_port]
91
+ end
92
+ end
93
+ end
94
+ end
@@ -0,0 +1,609 @@
1
+ require 'spec_helper'
2
+ require 'vagrant-cloudstack/action/run_instance'
3
+ require 'vagrant-cloudstack/config'
4
+
5
+ require 'vagrant'
6
+ require 'fog'
7
+
8
+ describe VagrantPlugins::Cloudstack::Action::RunInstance do
9
+ let(:action) { VagrantPlugins::Cloudstack::Action::RunInstance.new(app, env) }
10
+
11
+ let(:create_servers_parameters) do
12
+ {
13
+ :display_name => DISPLAY_NAME,
14
+ :group => nil,
15
+ :zone_id => ZONE_ID,
16
+ :flavor_id => SERVICE_OFFERING_ID,
17
+ :image_id => TEMPLATE_ID,
18
+ 'network_ids' => NETWORK_ID
19
+ }
20
+ end
21
+
22
+ let(:fake_job_result) do
23
+ {
24
+ 'queryasyncjobresultresponse' => {
25
+ 'jobstatus' => 1,
26
+ 'jobresult' => {
27
+ 'portforwardingrule' => {
28
+ 'id' => PORT_FORWARDING_RULE_ID
29
+ },
30
+ 'networkacl' => {
31
+ 'id' => ACL_ID
32
+ },
33
+ 'virtualmachine' => {
34
+ 'password' => GENERATED_PASSWORD
35
+ }
36
+ }
37
+ }
38
+ }
39
+ end
40
+
41
+ let(:list_public_ip_addresses_response) do
42
+ {
43
+ 'listpublicipaddressesresponse' => {
44
+ 'count' => 1,
45
+ 'publicipaddress' =>
46
+ [
47
+ {
48
+ 'id' => PF_IP_ADDRESS_ID,
49
+ 'ipaddress' => PF_IP_ADDRESS,
50
+ 'associatednetworkid' => NETWORK_ID,
51
+ 'associatednetworkname' => NETWORK_NAME,
52
+ 'vpcid' => VPC_ID
53
+ }
54
+ ]
55
+ }
56
+ }
57
+ end
58
+
59
+ let(:network_type) { NETWORK_TYPE_ADVANCED }
60
+ let(:security_groups_enabled) { SECURITY_GROUPS_DISABLED }
61
+ let(:list_zones_response) do
62
+ {
63
+ 'listzonesresponse' => {
64
+ 'count' => 1,
65
+ 'zone' =>
66
+ [
67
+ {
68
+ 'tags' => [],
69
+ 'id' => ZONE_ID,
70
+ 'name' => ZONE_NAME,
71
+ 'networktype' => network_type,
72
+ 'securitygroupsenabled' => security_groups_enabled
73
+ }
74
+ ]
75
+ }
76
+ }
77
+ end
78
+
79
+ let(:list_service_offerings_response) do
80
+ {
81
+ 'listserviceofferingsresponse' => {
82
+ 'count' => 1,
83
+ 'serviceoffering' => [
84
+ {
85
+ 'id' => SERVICE_OFFERING_ID,
86
+ 'name' => SERVICE_OFFERING_NAME,
87
+ 'displaytext' => "Display version of #{SERVICE_OFFERING_NAME}"
88
+ }
89
+ ]
90
+ }
91
+ }
92
+ end
93
+
94
+ let(:list_templates_response) do
95
+ {
96
+ 'listtemplatesresponse' => {
97
+ 'count' => 1,
98
+ 'template' => [
99
+ {
100
+ 'id' => TEMPLATE_ID,
101
+ 'name' => TEMPLATE_NAME
102
+ }
103
+ ]
104
+ }
105
+ }
106
+ end
107
+
108
+ let(:list_networks_response) do
109
+ {
110
+ 'listnetworksresponse' => {
111
+ 'count' => 1,
112
+ 'network' => [
113
+ {
114
+ 'id' => NETWORK_ID,
115
+ 'name' => NETWORK_NAME,
116
+ 'vpcid' => VPC_ID,
117
+ 'aclid' => ACL_ID
118
+ }
119
+ ]
120
+ }
121
+ }
122
+ end
123
+
124
+ let(:list_network_acl_lists_response) do
125
+ {
126
+ 'listnetworkacllistsresponse' => {
127
+ 'count' => 3,
128
+ 'networkacllist' => [
129
+ {
130
+ 'id' => ACL_ID,
131
+ 'name' => NETWORK_NAME,
132
+ 'vpcid' => VPC_ID
133
+ },
134
+ {
135
+ 'id' => '13fa8945-9248-13e5-4afa-525405b8977a', 'name' => 'default_allow',
136
+ 'description' => 'Default Network ACL Allow All'
137
+ },
138
+ {
139
+ 'id' => '13fa283b-9248-13e5-4afa-525405b8977a', 'name' => 'default_deny',
140
+ 'description' => 'Default Network ACL Deny All'
141
+ }
142
+ ]
143
+ }
144
+ }
145
+ end
146
+ let(:list_disk_offerings_response) do
147
+ {
148
+ 'listdiskofferingsresponse' => {
149
+ 'count' => 1,
150
+ 'diskoffering' => [
151
+ {
152
+ 'id' => DISK_OFFERING_ID,
153
+ 'name' => DISK_OFFERING_NAME
154
+ }
155
+ ]
156
+ }
157
+ }
158
+ end
159
+
160
+ let(:create_port_forwarding_rule_parameters) do
161
+ {
162
+ networkid: NETWORK_ID,
163
+ ipaddressid: PF_IP_ADDRESS_ID,
164
+ publicport: 49_152,
165
+ privateport: GUEST_PORT_SSH,
166
+ protocol: 'tcp',
167
+ virtualmachineid: SERVER_ID
168
+ }
169
+ end
170
+
171
+ let(:create_port_forwarding_rule_respones) do
172
+ {
173
+ 'createportforwardingruleresponse' => {
174
+ 'id' => PORT_FORWARDING_RULE_ID,
175
+ 'jobid' => JOB_ID
176
+ }
177
+ }
178
+ end
179
+
180
+ let(:create_network_acl_request) do
181
+ {
182
+ command: 'createNetworkACL',
183
+ aclid: ACL_ID,
184
+ action: 'Allow',
185
+ protocol: 'tcp',
186
+ cidrlist: PF_TRUSTED_NETWORKS,
187
+ startport: GUEST_PORT_SSH,
188
+ endport: GUEST_PORT_SSH,
189
+ icmpcode: nil,
190
+ icmptype: nil,
191
+ traffictype: 'Ingress'
192
+ }
193
+ end
194
+
195
+ let(:createNetworkACL_response) do
196
+ {
197
+ 'createnetworkaclresponse' => {
198
+ 'id' => '5dcb96b5-7785-463d-9a11-d8388c98e4ee',
199
+ 'jobid' => JOB_ID
200
+ }
201
+ }
202
+ end
203
+
204
+ let(:create_ssh_key_pair_response) do
205
+ {
206
+ 'createsshkeypairresponse' => {
207
+ 'keypair' => {
208
+ 'privatekey' => "#{SSH_GENERATED_PRIVATE_KEY}\n",
209
+ 'name' => SSH_GENERATED_KEY_NAME
210
+ }
211
+ }
212
+ }
213
+ end
214
+
215
+ describe 'run_instance' do
216
+ subject { action.call(env) }
217
+ let(:app) { double('Vagrant::Action::Warden') }
218
+ let(:ssh_key) { '/some/path' }
219
+
220
+ let(:template_name) { TEMPLATE_NAME }
221
+ let(:machine) { double('Vagrant::Machine') }
222
+ let(:data_dir) { double('Pathname') }
223
+ let(:a_path) { double('Pathname') }
224
+ let(:file) { double('File') }
225
+ let(:communicator) { double('VagrantPlugins::CommunicatorSSH::Communicator') }
226
+ let(:communicator_config) { double('VagrantPlugins::...::...Config') }
227
+ let(:cloudstack_compute) { double('Fog::Compute::Cloudstack') }
228
+ let(:servers) { double('Fog::Compute::Cloudstack::Servers') }
229
+ let(:server) { double('Fog::Compute::Cloudstack::Server') }
230
+ let(:ui) { double('Vagrant::UI::Prefixed') }
231
+ let(:root_path) { double('Pathname') }
232
+ let(:env) do
233
+ {
234
+ root_path: root_path,
235
+ ui: ui,
236
+ machine: machine,
237
+ cloudstack_compute: cloudstack_compute
238
+ }
239
+ end
240
+
241
+ let(:cloudstack_zone) do
242
+ instance_double('Fog::Compute::Cloudstack::Zone',
243
+ id: ZONE_ID,
244
+ name: ZONE_NAME,
245
+ network_type: network_type,
246
+ security_groups_enabled: security_groups_enabled)
247
+ end
248
+
249
+ before(:each) do
250
+ allow(app).to receive(:call).and_return(true)
251
+ allow(ui).to receive(:info)
252
+ allow(ui).to receive(:detail)
253
+
254
+ allow(machine).to receive(:data_dir).and_return(data_dir)
255
+ allow(data_dir).to receive(:join).and_return(a_path)
256
+ allow(a_path).to receive(:open).and_yield(file)
257
+
258
+ allow(machine).to receive(:communicate).and_return(communicator)
259
+ allow(machine).to receive_message_chain(:communicate, :ready?).and_return(true)
260
+
261
+ allow(machine).to receive(:provider_config).and_return(provider_config)
262
+ expect(server).to receive(:wait_for).and_return(ready = true)
263
+ allow(server).to receive(:password_enabled).and_return(false)
264
+ expect(cloudstack_compute).to receive(:servers).and_return(servers)
265
+ allow(cloudstack_compute).to receive(:send).with(:list_zones, available: true).and_return(list_zones_response)
266
+ allow(cloudstack_compute).to receive(:send).with(:list_service_offerings, listall: true)
267
+ .and_return(list_service_offerings_response)
268
+ allow(cloudstack_compute).to receive(:send)
269
+ .with(:list_templates, zoneid: ZONE_ID, templatefilter: 'executable', listall: true)
270
+ .and_return(list_templates_response)
271
+ allow(cloudstack_compute).to receive(:zones).and_return([cloudstack_zone])
272
+ allow(servers).to receive(:create).with(create_servers_parameters).and_return(server)
273
+ expect(server).to receive(:id).and_return(SERVER_ID)
274
+ expect(machine).to receive(:id=).with(SERVER_ID)
275
+
276
+ allow(cloudstack_compute).to receive(:volumes).and_return([])
277
+ end
278
+
279
+ context 'in basic zone' do
280
+ let(:security_groups) { [] }
281
+ let(:network_name) { nil }
282
+ let(:provider_config) do
283
+ config = VagrantPlugins::Cloudstack::Config.new
284
+ config.domain_config :cloudstack do |cfg|
285
+ cfg.zone_name = ZONE_NAME
286
+ cfg.service_offering_name = SERVICE_OFFERING_NAME
287
+ cfg.template_name = template_name
288
+ cfg.display_name = DISPLAY_NAME
289
+ cfg.ssh_key = ssh_key
290
+ cfg.security_groups = security_groups
291
+ cfg.network_name = network_name
292
+ end
293
+ config.finalize!
294
+ config.get_domain_config(:cloudstack)
295
+ end
296
+ let(:network_type) { NETWORK_TYPE_BASIC }
297
+ let(:security_groups_enabled) { SECURITY_GROUPS_ENABLED }
298
+
299
+ let(:create_servers_parameters) do
300
+ {
301
+ display_name: DISPLAY_NAME,
302
+ group: nil,
303
+ zone_id: ZONE_ID,
304
+ flavor_id: SERVICE_OFFERING_ID,
305
+ image_id: TEMPLATE_ID
306
+ }
307
+ end
308
+
309
+ context 'a basic configuration' do
310
+ it 'starts a vm' do
311
+ should eq true
312
+ end
313
+ end
314
+
315
+ context 'with inline security groups' do
316
+ let(:sg_rule) { { protocol: 'TCP', startport: 23, endport: 23, cidrlist: '0.0.0.0/0' } }
317
+
318
+ let(:create_servers_parameters) { super().merge('security_group_ids' => SECURITY_GROUP_ID) }
319
+ let(:security_groups) do
320
+ [
321
+ {
322
+ name: SECURITY_GROUP_NAME, description: SECURITY_GROUP_DESC,
323
+ rules: [sg_rule.merge(type: 'ingress')]
324
+ }
325
+ ]
326
+ end
327
+
328
+ before(:each) do
329
+ allow(cloudstack_compute).to receive(:create_security_group)
330
+ .with(name: SECURITY_GROUP_NAME, description: SECURITY_GROUP_DESC)
331
+ .and_return('createsecuritygroupresponse' => { 'securitygroup' => { 'id' => SECURITY_GROUP_ID } })
332
+
333
+ allow(cloudstack_compute).to receive(:send).with(:authorize_security_group_ingress,
334
+ { securityGroupId: SECURITY_GROUP_ID }.merge(sg_rule))
335
+ .and_return(
336
+ 'authorizesecuritygroupingressresponse' => { 'jobid' => '0b6c2c41-f0c8-43b5-be1d-9d5957873cf9' }
337
+ )
338
+ expect(file).to receive(:write).with("#{SECURITY_GROUP_ID}\n")
339
+ end
340
+
341
+ it 'starts a vm' do
342
+ should eq true
343
+ end
344
+ end
345
+
346
+ context 'with advanced zone parameters give warnings' do
347
+ let(:network_name) { NETWORK_NAME }
348
+
349
+ before(:each) do
350
+ expect(ui).to receive(:warn).with("Network name or id defined but zone Zone Name is of network type 'Basic'"\
351
+ "\nNetwork name or id will be ignored")
352
+ end
353
+ it 'starts a vm' do
354
+ should eq true
355
+ end
356
+ end
357
+ end
358
+
359
+ context 'in advanced zone' do
360
+ let(:pf_ip_address) { nil }
361
+ let(:pf_trusted_networks) { nil }
362
+ let(:pf_public_port_randomrange) { { start: 49_152, end: 65_535 } }
363
+ let(:pf_open_firewall) { true }
364
+ let(:disk_offering_name) { nil }
365
+
366
+ let(:provider_config) do
367
+ config = VagrantPlugins::Cloudstack::Config.new
368
+ config.domain_config :cloudstack do |cfg|
369
+ cfg.zone_name = ZONE_NAME
370
+ cfg.network_name = NETWORK_NAME
371
+ cfg.service_offering_name = SERVICE_OFFERING_NAME
372
+ cfg.template_name = template_name
373
+ cfg.display_name = DISPLAY_NAME
374
+ cfg.pf_ip_address = pf_ip_address
375
+ cfg.pf_trusted_networks = pf_trusted_networks
376
+ cfg.pf_public_port_randomrange = pf_public_port_randomrange
377
+ cfg.pf_open_firewall = pf_open_firewall
378
+ cfg.ssh_key = ssh_key
379
+ cfg.disk_offering_name = disk_offering_name
380
+ end
381
+ config.finalize!
382
+ config.get_domain_config(:cloudstack)
383
+ end
384
+
385
+ let(:winrm_config) { double('VagrantPlugins::VagrantWinRM::WinRMConfig') }
386
+
387
+ before(:each) do
388
+ allow(cloudstack_compute).to receive(:query_async_job_result).with(jobid: JOB_ID).and_return(fake_job_result)
389
+
390
+ allow(cloudstack_compute).to receive(:send).with(:list_networks, {}).and_return(list_networks_response)
391
+ end
392
+
393
+ context 'a basic configuration' do
394
+ it 'starts a vm' do
395
+ should eq true
396
+ end
397
+ end
398
+
399
+ context 'with template specified from Vagrant(file)' do
400
+ let(:template_name) { nil }
401
+
402
+ before(:each) do
403
+ expect(machine).to receive_message_chain(:config, :vm, :box).and_return(TEMPLATE_NAME)
404
+ end
405
+ it 'starts a vm' do
406
+ should eq true
407
+ end
408
+ end
409
+
410
+ context 'with additional data disk' do
411
+ let(:disk_offering_name) { DISK_OFFERING_NAME }
412
+ let(:create_servers_parameters) { super().merge('disk_offering_id' => DISK_OFFERING_ID) }
413
+ let(:volume) { double('Fog::Compute::Cloudstack::Volume') }
414
+
415
+ before(:each) do
416
+ allow(cloudstack_compute).to receive(:send).with(:list_disk_offerings, listall: true)
417
+ .and_return(list_disk_offerings_response)
418
+ expect(cloudstack_compute).to receive(:volumes).and_return([volume])
419
+ allow(volume).to receive(:server_id).and_return(SERVER_ID)
420
+ allow(volume).to receive(:type).and_return('DATADISK')
421
+ allow(volume).to receive(:id).and_return(VOLUME_ID)
422
+ expect(file).to receive(:write).with("#{VOLUME_ID}\n")
423
+ allow(server).to receive(:id).and_return(SERVER_ID)
424
+ end
425
+ it 'starts a vm' do
426
+ should eq true
427
+ end
428
+ end
429
+
430
+ context 'with generated password' do
431
+ before(:each) do
432
+ expect(server).to receive(:password_enabled).and_return(true)
433
+ allow(server).to receive(:job_id).and_return(JOB_ID)
434
+ expect(file).to receive(:write).with(GENERATED_PASSWORD)
435
+ end
436
+
437
+ it 'starts a vm' do
438
+ should eq true
439
+ end
440
+ end
441
+
442
+ context 'with SSH key generation' do
443
+ let(:ssh_key) { nil }
444
+ let(:create_servers_parameters) { super().merge('key_name' => SSH_GENERATED_KEY_NAME) }
445
+
446
+ before(:each) do
447
+ expect(ui).to receive(:warn)
448
+ .with('No keypair or ssh_key specified to launch your instance with.' \
449
+ "\n" + 'Generating a temporary keypair for this instance...')
450
+ expect(cloudstack_compute).to receive(:create_ssh_key_pair).with(/vagacs_#{DISPLAY_NAME}/, nil, nil, nil)
451
+ .and_return(create_ssh_key_pair_response)
452
+ expect(file).to receive(:write).with("#{SSH_GENERATED_PRIVATE_KEY}\n")
453
+ expect(file).to receive(:write).with(SSH_GENERATED_KEY_NAME)
454
+ end
455
+
456
+ it 'starts a vm' do
457
+ should eq true
458
+ end
459
+ end
460
+
461
+ context 'with autogenerated firewall and port forward' do
462
+ let(:pf_ip_address) { PF_IP_ADDRESS }
463
+ let(:pf_trusted_networks) { PF_TRUSTED_NETWORKS }
464
+ let(:pf_public_port_randomrange) { { start: PF_RANDOM_START, end: PF_RANDOM_START + 1 } }
465
+ let(:pf_open_firewall) { false }
466
+
467
+ before(:each) do
468
+ allow(cloudstack_compute).to receive(:send).with(:list_public_ip_addresses, {})
469
+ .and_return(list_public_ip_addresses_response)
470
+ expect(communicator_config).to receive(:port).and_return(nil)
471
+ expect(communicator_config).to receive(:guest_port).and_return(nil)
472
+
473
+ allow(machine).to receive_message_chain(:config, :vm, :rdp, :port).and_return(3389)
474
+ allow(machine).to receive_message_chain(:config, :vm, :guest).and_return(nil)
475
+ allow(machine).to receive(:id).and_return(SERVER_ID)
476
+
477
+ allow(cloudstack_compute).to receive(:send).with(:list_public_ip_addresses, 'id' => PF_IP_ADDRESS_ID)
478
+ .and_return(list_public_ip_addresses_response)
479
+ allow(cloudstack_compute).to receive(:list_network_acl_lists).with(id: nil)
480
+ .and_return(list_network_acl_lists_response)
481
+
482
+ expect(file).to receive(:write).with(PORT_FORWARDING_RULE_ID + "\n")
483
+ expect(file).to receive(:write).with(PF_RANDOM_START.to_s)
484
+ expect(file).to receive(:write).with("#{ACL_ID},networkacl\n")
485
+ end
486
+
487
+ context 'for the SSH communicator' do
488
+ before(:each) do
489
+ allow(communicator).to receive_message_chain(:class, :name).and_return(COMMUNICATOR_SSH)
490
+ expect(machine).to receive_message_chain(:config, :ssh).and_return(communicator_config)
491
+
492
+ allow(communicator_config).to receive_message_chain(:default, :port).and_return(GUEST_PORT_SSH)
493
+ expect(cloudstack_compute).to receive(:create_port_forwarding_rule)
494
+ .with(create_port_forwarding_rule_parameters)
495
+ .and_return(create_port_forwarding_rule_respones)
496
+ expect(cloudstack_compute).to receive(:request)
497
+ .with(create_network_acl_request)
498
+ .and_return(createNetworkACL_response)
499
+ end
500
+ it 'starts a vm' do
501
+ should eq true
502
+ end
503
+
504
+ context 'with a port conflict' do
505
+ let(:pf_public_port_randomrange) { { start: PF_RANDOM_START - 1, end: PF_RANDOM_START + 1 } }
506
+
507
+ before(:each) do
508
+ allow(Kernel).to receive(:rand).with((PF_RANDOM_START - 1)...(PF_RANDOM_START + 1))
509
+ .and_return(PF_RANDOM_START - 1, PF_RANDOM_START)
510
+ expect(cloudstack_compute).to receive(:create_port_forwarding_rule)
511
+ .with(create_port_forwarding_rule_parameters.merge(publicport: PF_RANDOM_START - 1))
512
+ .and_raise(
513
+ Fog::Compute::Cloudstack::Error,
514
+ 'The range specified, CONFLICTINGRANGE, conflicts with rule SOMERULE which has THESAME'
515
+ )
516
+ end
517
+
518
+ it 'starts a vm' do
519
+ should eq true
520
+ end
521
+ end
522
+ end
523
+
524
+ context 'for the WinRM (and RDP) communicator' do
525
+ PF_RDP_RULE_ID = 'UUID RDP port forwarding rule'.freeze
526
+ PF_RDP_JOB_ID = 'UUID RDP Port Forward Job'.freeze
527
+ FW_RDP_JOB_ID = 'UUID RDP Port Firewall Job'.freeze
528
+ FW_RDP_ACL_ID = 'UUID of RDP ACL'.freeze
529
+
530
+ let(:pf_public_port_randomrange) { { start: PF_RANDOM_START, end: PF_RANDOM_START + 2 } }
531
+
532
+ let(:create_port_forwarding_rule_parameters) { super().merge(privateport: GUEST_PORT_WINRM) }
533
+ let(:create_port_forwarding_rule_rdp_parameters) do
534
+ create_port_forwarding_rule_parameters.merge(privateport: GUEST_PORT_RDP, publicport: PF_RANDOM_START + 1)
535
+ end
536
+
537
+ let(:create_network_acl_winrm_request) do
538
+ create_network_acl_request.merge(startport: GUEST_PORT_WINRM, endport: GUEST_PORT_WINRM)
539
+ end
540
+ let(:create_network_acl_rdp_request) do
541
+ create_network_acl_request.merge(startport: GUEST_PORT_RDP, endport: GUEST_PORT_RDP)
542
+ end
543
+
544
+ before(:each) do
545
+ allow(Kernel).to receive(:rand).with(PF_RANDOM_START...(PF_RANDOM_START + 2))
546
+ .and_return(PF_RANDOM_START, PF_RANDOM_START + 1)
547
+
548
+ allow(communicator).to receive_message_chain(:class, :name).and_return(COMMUNICATOR_WINRM)
549
+ expect(machine).to receive_message_chain(:config, :winrm).and_return(communicator_config)
550
+
551
+ allow(communicator_config).to receive_message_chain(:default, :port).and_return(GUEST_PORT_WINRM)
552
+
553
+ expect(cloudstack_compute).to receive(:create_port_forwarding_rule)
554
+ .with(create_port_forwarding_rule_parameters)
555
+ .and_return(create_port_forwarding_rule_respones)
556
+
557
+ expect(cloudstack_compute).to receive(:create_port_forwarding_rule)
558
+ .with(create_port_forwarding_rule_rdp_parameters).and_return(
559
+ 'createportforwardingruleresponse' =>
560
+ {
561
+ 'id' => PF_RDP_RULE_ID,
562
+ 'jobid' => PF_RDP_JOB_ID
563
+ }
564
+ )
565
+ allow(cloudstack_compute).to receive(:query_async_job_result).with(jobid: PF_RDP_JOB_ID)
566
+ .and_return(fake_job_result.merge(
567
+ 'queryasyncjobresultresponse' => {
568
+ 'jobresult' => {
569
+ 'portforwardingrule' => {
570
+ 'id' => PF_RDP_RULE_ID
571
+ }
572
+ }
573
+ }
574
+ ))
575
+ expect(file).to receive(:write).with(PF_RDP_RULE_ID + "\n")
576
+ expect(file).to receive(:write).with((PF_RANDOM_START + 1).to_s)
577
+ expect(cloudstack_compute).to receive(:request).with(create_network_acl_winrm_request)
578
+ .and_return(createNetworkACL_response)
579
+
580
+ expect(cloudstack_compute).to receive(:request).with(create_network_acl_rdp_request)
581
+ .and_return(
582
+ 'createnetworkaclresponse' => {
583
+ 'id' => '5dcb96b5-7785-463d-9a11-d8388c98e4ee',
584
+ 'jobid' => FW_RDP_JOB_ID
585
+ }
586
+ )
587
+ allow(cloudstack_compute).to receive(:query_async_job_result).with(jobid: FW_RDP_JOB_ID)
588
+ .and_return(
589
+ fake_job_result.merge(
590
+ 'queryasyncjobresultresponse' => {
591
+ 'jobstatus' => 1,
592
+ 'jobresult' => {
593
+ 'networkacl' => {
594
+ 'id' => FW_RDP_ACL_ID
595
+ }
596
+ }
597
+ }
598
+ )
599
+ )
600
+ expect(file).to receive(:write).with("#{FW_RDP_ACL_ID},networkacl\n")
601
+ end
602
+ it 'starts a vm' do
603
+ should eq true
604
+ end
605
+ end
606
+ end
607
+ end
608
+ end
609
+ end