foreman_google 3.0.7 → 3.0.9

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 (66) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +0 -15
  3. data/app/assets/javascripts/foreman_google/locale/cs_CZ/foreman_google.js +7 -1
  4. data/app/assets/javascripts/foreman_google/locale/de/foreman_google.js +7 -1
  5. data/app/assets/javascripts/foreman_google/locale/el/foreman_google.js +7 -1
  6. data/app/assets/javascripts/foreman_google/locale/en/foreman_google.js +7 -1
  7. data/app/assets/javascripts/foreman_google/locale/en_GB/foreman_google.js +7 -1
  8. data/app/assets/javascripts/foreman_google/locale/es/foreman_google.js +7 -1
  9. data/app/assets/javascripts/foreman_google/locale/fr/foreman_google.js +8 -2
  10. data/app/assets/javascripts/foreman_google/locale/it/foreman_google.js +7 -1
  11. data/app/assets/javascripts/foreman_google/locale/ja/foreman_google.js +8 -2
  12. data/app/assets/javascripts/foreman_google/locale/ka/foreman_google.js +7 -1
  13. data/app/assets/javascripts/foreman_google/locale/ko/foreman_google.js +8 -2
  14. data/app/assets/javascripts/foreman_google/locale/pl/foreman_google.js +7 -1
  15. data/app/assets/javascripts/foreman_google/locale/pt_BR/foreman_google.js +7 -1
  16. data/app/assets/javascripts/foreman_google/locale/ru/foreman_google.js +7 -1
  17. data/app/assets/javascripts/foreman_google/locale/sv_SE/foreman_google.js +7 -1
  18. data/app/assets/javascripts/foreman_google/locale/zh_CN/foreman_google.js +8 -2
  19. data/app/assets/javascripts/foreman_google/locale/zh_TW/foreman_google.js +7 -1
  20. data/app/lib/google_cloud_compute/compute_attributes.rb +3 -1
  21. data/app/models/foreman_google/google_compute.rb +2 -2
  22. data/lib/foreman_google/version.rb +1 -1
  23. data/locale/cs_CZ/LC_MESSAGES/foreman_google.mo +0 -0
  24. data/locale/cs_CZ/foreman_google.po +7 -1
  25. data/locale/de/LC_MESSAGES/foreman_google.mo +0 -0
  26. data/locale/de/foreman_google.po +7 -1
  27. data/locale/el/LC_MESSAGES/foreman_google.mo +0 -0
  28. data/locale/el/foreman_google.po +7 -1
  29. data/locale/en/LC_MESSAGES/foreman_google.mo +0 -0
  30. data/locale/en/foreman_google.po +7 -1
  31. data/locale/en_GB/LC_MESSAGES/foreman_google.mo +0 -0
  32. data/locale/en_GB/foreman_google.po +7 -1
  33. data/locale/es/LC_MESSAGES/foreman_google.mo +0 -0
  34. data/locale/es/foreman_google.po +7 -1
  35. data/locale/foreman_google.pot +12 -4
  36. data/locale/fr/LC_MESSAGES/foreman_google.mo +0 -0
  37. data/locale/fr/foreman_google.po +9 -3
  38. data/locale/it/LC_MESSAGES/foreman_google.mo +0 -0
  39. data/locale/it/foreman_google.po +7 -1
  40. data/locale/ja/LC_MESSAGES/foreman_google.mo +0 -0
  41. data/locale/ja/foreman_google.po +9 -3
  42. data/locale/ka/LC_MESSAGES/foreman_google.mo +0 -0
  43. data/locale/ka/foreman_google.po +7 -1
  44. data/locale/ko/LC_MESSAGES/foreman_google.mo +0 -0
  45. data/locale/ko/foreman_google.po +9 -3
  46. data/locale/pl/LC_MESSAGES/foreman_google.mo +0 -0
  47. data/locale/pl/foreman_google.po +7 -1
  48. data/locale/pt_BR/LC_MESSAGES/foreman_google.mo +0 -0
  49. data/locale/pt_BR/foreman_google.po +7 -1
  50. data/locale/ru/LC_MESSAGES/foreman_google.mo +0 -0
  51. data/locale/ru/foreman_google.po +7 -1
  52. data/locale/sv_SE/LC_MESSAGES/foreman_google.mo +0 -0
  53. data/locale/sv_SE/foreman_google.po +7 -1
  54. data/locale/zh_CN/LC_MESSAGES/foreman_google.mo +0 -0
  55. data/locale/zh_CN/foreman_google.po +9 -3
  56. data/locale/zh_TW/LC_MESSAGES/foreman_google.mo +0 -0
  57. data/locale/zh_TW/foreman_google.po +7 -1
  58. data/test/controllers/foreman_google/api/v2/compute_resources_extensions_test.rb +51 -0
  59. data/test/models/concerns/foreman_google/host_managed_extensions_test.rb +46 -0
  60. data/test/models/foreman_google/gce_test.rb +275 -3
  61. data/test/models/foreman_google/google_compute_test.rb +193 -4
  62. data/test/unit/foreman_google/google_compute_adapter_test.rb +59 -7
  63. data/test/unit/google_cloud_compute/compute_attributes_test.rb +235 -0
  64. data/test/unit/google_cloud_compute/compute_collection_test.rb +78 -0
  65. data/test/unit/google_extensions/attached_disk_test.rb +35 -0
  66. metadata +10 -30
@@ -194,20 +194,209 @@ module ForemanGoogle
194
194
 
195
195
  it '@network' do
196
196
  cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone)
197
- assert cr.network, 'default'
197
+ assert_equal 'default', cr.network
198
198
 
199
199
  cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone, args: { network: 'my-network' })
200
- assert cr.network, 'my-network'
200
+ assert_equal 'my-network', cr.network
201
201
  end
202
202
 
203
203
  it '@zone' do
204
204
  cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone)
205
- assert zone, cr.zone
205
+ assert_equal zone, cr.zone
206
206
  end
207
207
 
208
208
  it '@zone_name' do
209
209
  cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone, instance: instance)
210
- assert zone, cr.zone_name
210
+ assert_equal zone, cr.zone_name
211
+ end
212
+
213
+ describe '#status' do
214
+ it 'returns status when persisted' do
215
+ instance.status = 'RUNNING'
216
+ client.expects(:instance).with(zone, identity).returns(instance)
217
+ assert_equal 'RUNNING', subject.status
218
+ end
219
+
220
+ it 'returns false when not persisted' do
221
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone)
222
+ assert_not cr.status
223
+ end
224
+ end
225
+
226
+ describe '#state' do
227
+ it 'is an alias for status' do
228
+ instance.status = 'TERMINATED'
229
+ client.expects(:instance).with(zone, identity).returns(instance)
230
+ assert_equal subject.status, subject.state
231
+ end
232
+ end
233
+
234
+ describe '#start' do
235
+ it 'delegates to client.start when persisted' do
236
+ client.stubs(:instance).with(zone, identity).returns(instance)
237
+ client.expects(:start).with(zone, identity).returns(true)
238
+ subject.start
239
+ end
240
+
241
+ it 'raises when not persisted' do
242
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone)
243
+ assert_raises(Foreman::Exception) { cr.start }
244
+ end
245
+ end
246
+
247
+ describe '#stop' do
248
+ it 'delegates to client.stop when persisted' do
249
+ client.stubs(:instance).with(zone, identity).returns(instance)
250
+ client.expects(:stop).with(zone, identity).returns(true)
251
+ subject.stop
252
+ end
253
+
254
+ it 'raises when not persisted' do
255
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone)
256
+ assert_raises(Foreman::Exception) { cr.stop }
257
+ end
258
+ end
259
+
260
+ describe '#to_s' do
261
+ it 'returns the name' do
262
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone, args: { name: 'my-vm' })
263
+ assert_equal 'my-vm', cr.to_s
264
+ end
265
+ end
266
+
267
+ describe '#interfaces' do
268
+ it 'returns network_interfaces' do
269
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone)
270
+ assert_equal cr.network_interfaces, cr.interfaces
271
+ end
272
+ end
273
+
274
+ describe '#vm_description' do
275
+ it 'delegates to pretty_machine_type' do
276
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone, instance: instance)
277
+ assert_equal cr.pretty_machine_type, cr.vm_description
278
+ end
279
+ end
280
+
281
+ describe '#vm_ip_address - no network interfaces' do
282
+ it 'returns nil' do
283
+ empty_instance = OpenStruct.new(
284
+ name: 'instance', network_interfaces: [],
285
+ creation_timestamp: Time.zone.now, zone: zone,
286
+ machine_type: 'machineTypes/e2-micro'
287
+ )
288
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone, instance: empty_instance)
289
+ assert_nil cr.vm_ip_address
290
+ end
291
+ end
292
+
293
+ describe '#private_ip_address - no network interfaces' do
294
+ it 'returns nil' do
295
+ empty_instance = OpenStruct.new(
296
+ name: 'instance', network_interfaces: [],
297
+ creation_timestamp: Time.zone.now, zone: zone,
298
+ machine_type: 'machineTypes/e2-micro'
299
+ )
300
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone, instance: empty_instance)
301
+ assert_nil cr.private_ip_address
302
+ end
303
+ end
304
+
305
+ describe '#pretty_image_name - no disks' do
306
+ it 'returns nil' do
307
+ instance.disks = []
308
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone, instance: instance)
309
+ assert_nil cr.pretty_image_name
310
+ end
311
+ end
312
+
313
+ describe '#ip_addresses' do
314
+ it 'returns public and private IP' do
315
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone, instance: instance)
316
+ assert_equal ['1.2.3.4', '10.10.10.23'], cr.ip_addresses
317
+ end
318
+ end
319
+
320
+ describe '#serial_port_output' do
321
+ it 'delegates to client' do
322
+ client.stubs(:instance).with(zone, identity).returns(instance)
323
+ client.expects(:serial_port_output).with(zone, identity).returns(OpenStruct.new(contents: 'boot log'))
324
+ assert_equal 'boot log', subject.serial_port_output
325
+ end
326
+
327
+ it 'returns nil when client returns nil' do
328
+ client.stubs(:instance).with(zone, identity).returns(instance)
329
+ client.expects(:serial_port_output).with(zone, identity).returns(nil)
330
+ assert_nil subject.serial_port_output
331
+ end
332
+ end
333
+
334
+ describe '#volumes_attributes=' do
335
+ it 'is a no-op' do
336
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone)
337
+ cr.volumes_attributes = { '0' => { size_gb: 10 } }
338
+ assert cr.volumes.any?
339
+ end
340
+ end
341
+
342
+ describe '#reload - without identity' do
343
+ it 'returns nil' do
344
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone)
345
+ assert_nil cr.reload
346
+ end
347
+ end
348
+
349
+ describe '#create_volumes' do
350
+ it 'inserts disks and waits for READY' do
351
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone, args: { volumes: [{ size_gb: '20' }] })
352
+
353
+ client.expects(:insert_disk).with(zone, cr.volumes.first.insert_attrs)
354
+ client.expects(:disk).with(zone, cr.volumes.first.device_name).returns(OpenStruct.new(status: 'READY'))
355
+ client.expects(:wait_for).yields.returns({ duration: 1 })
356
+
357
+ cr.create_volumes
358
+ end
359
+ end
360
+
361
+ describe '#destroy_volumes' do
362
+ it 'deletes each volume disk' do
363
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone, args: { volumes: [{ size_gb: '20' }] })
364
+ client.expects(:delete_disk).with(zone, cr.volumes.first.device_name)
365
+ cr.destroy_volumes
366
+ end
367
+ end
368
+
369
+ describe '#create_instance' do
370
+ it 'calls insert_instance via ComputeAttributes' do
371
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone, args: { name: 'test-vm', machine_type: 'e2-micro' })
372
+ client.expects(:insert_instance).with(zone, has_key(:name))
373
+ cr.create_instance
374
+ end
375
+ end
376
+
377
+ describe '#set_disk_auto_delete' do
378
+ it 'delegates to client' do
379
+ args = { name: 'my-vm' }
380
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone, args: args)
381
+ client.expects(:set_disk_auto_delete).with(zone, 'my-vm')
382
+ cr.set_disk_auto_delete
383
+ end
384
+ end
385
+
386
+ describe '#wait_for' do
387
+ it 'delegates to client.wait_for' do
388
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone)
389
+ client.expects(:wait_for).yields.returns({ duration: 0 })
390
+ result = cr.wait_for { true }
391
+ assert_equal({ duration: 0 }, result)
392
+ end
393
+ end
394
+
395
+ describe '#public_ip_address' do
396
+ it 'is an alias for vm_ip_address' do
397
+ cr = ForemanGoogle::GoogleCompute.new(client: client, zone: zone, instance: instance)
398
+ assert_equal cr.vm_ip_address, cr.public_ip_address
399
+ end
211
400
  end
212
401
  end
213
402
  end
@@ -131,7 +131,7 @@ module ForemanGoogle
131
131
 
132
132
  result = subject.insert_instance('us-east1-b', args)
133
133
 
134
- assert 'insert', result.operation.operation_type
134
+ assert_equal 'insert', result.operation.operation_type
135
135
  assert_includes result.operation.target_link, 'foreman-test-google'
136
136
  end
137
137
 
@@ -156,14 +156,14 @@ module ForemanGoogle
156
156
  stub_request(:post, 'https://compute.googleapis.com/compute/v1/projects/coastal-haven-123456/zones/us-east1-b/instances/instance_name/start')
157
157
  .to_return(status: 200, body: File.read(File.join(__dir__, '..', '..', 'fixtures', 'instance_start.json')))
158
158
  result = subject.start('us-east1-b', 'instance_name')
159
- assert 'start', result.operation.operation_type
159
+ assert_equal 'start', result.operation.operation_type
160
160
  end
161
161
 
162
162
  it '#stop' do
163
163
  stub_request(:post, 'https://compute.googleapis.com/compute/v1/projects/coastal-haven-123456/zones/us-east1-b/instances/instance_name/stop')
164
164
  .to_return(status: 200, body: File.read(File.join(__dir__, '..', '..', 'fixtures', 'instance_stop.json')))
165
165
  result = subject.stop('us-east1-b', 'instance_name')
166
- assert 'stop', result.operation.operation_type
166
+ assert_equal 'stop', result.operation.operation_type
167
167
  end
168
168
 
169
169
  it '#set_disk_auto_delete' do
@@ -174,7 +174,7 @@ module ForemanGoogle
174
174
  .to_return(status: 200, body: File.read(File.join(__dir__, '..', '..', 'fixtures', 'instance_set_disk_auto_delete.json')))
175
175
  result = subject.set_disk_auto_delete('us-east1-b', 'instance_name')
176
176
 
177
- assert 'device-1', result[0].source
177
+ assert_equal 'instance-1', result[0].device_name
178
178
  assert result[0].auto_delete
179
179
  end
180
180
  end
@@ -186,14 +186,14 @@ module ForemanGoogle
186
186
 
187
187
  result = subject.insert_disk('us-east1-b', { name: 'foreman-disk1', size_gb: 23 })
188
188
  assert_includes result.operation.target_link, 'foreman-disk1'
189
- assert 'insert', result.operation.operation_type
189
+ assert_equal 'insert', result.operation.operation_type
190
190
  end
191
191
 
192
192
  it '#get' do
193
193
  stub_request(:get, 'https://compute.googleapis.com/compute/v1/projects/coastal-haven-123456/zones/us-east1-b/disks/foreman-disk1')
194
194
  .to_return(status: 200, body: File.read(File.join(__dir__, '..', '..', 'fixtures', 'disks_get.json')))
195
195
  result = subject.disk('us-east1-b', 'foreman-disk1')
196
- assert 'foreman-disk1', result.name
196
+ assert_equal 'foreman-disk1', result.name
197
197
  end
198
198
 
199
199
  it '#delete' do
@@ -202,7 +202,59 @@ module ForemanGoogle
202
202
  result = subject.delete_disk('us-east1-b', 'foreman-disk1')
203
203
 
204
204
  assert_includes result.operation.target_link, 'foreman-disk1'
205
- assert 'delete', result.operation.operation_type
205
+ assert_equal 'delete', result.operation.operation_type
206
+ end
207
+ end
208
+
209
+ describe '#delete_instance' do
210
+ it 'deletes an instance' do
211
+ stub_request(:delete, 'https://compute.googleapis.com/compute/v1/projects/coastal-haven-123456/zones/us-east1-b/instances/instance_name')
212
+ .to_return(status: 200, body: File.read(File.join(__dir__, '..', '..', 'fixtures', 'instance_stop.json')))
213
+ result = subject.delete_instance('us-east1-b', 'instance_name')
214
+ assert_equal 'stop', result.operation.operation_type
215
+ end
216
+ end
217
+
218
+ describe '#image' do
219
+ setup do
220
+ stub_request(:get, 'https://compute.googleapis.com/compute/v1/projects/coastal-haven-123456/global/images')
221
+ .to_return(body: File.read(File.join(__dir__, '..', '..', 'fixtures', 'images_coastal.json')))
222
+ end
223
+
224
+ it 'finds image by numeric id' do
225
+ subject.stub(:all_projects, []) do
226
+ result = subject.image(1)
227
+ assert_equal 'coastal-image', result.name
228
+ end
229
+ end
230
+
231
+ it 'returns nil when image not found' do
232
+ subject.stub(:all_projects, []) do
233
+ assert_nil subject.image(999)
234
+ end
235
+ end
236
+ end
237
+
238
+ describe '#serial_port_output' do
239
+ it 'returns serial port output' do
240
+ body = { contents: 'boot log output', next: 12_345, start: 0, selfLink: 'self-link' }.to_json
241
+ stub_request(:get, 'https://compute.googleapis.com/compute/v1/projects/coastal-haven-123456/zones/us-east1-b/instances/instance_name/serialPort')
242
+ .to_return(status: 200, body: body)
243
+ result = subject.serial_port_output('us-east1-b', 'instance_name')
244
+ assert_equal 'boot log output', result.contents
245
+ end
246
+ end
247
+
248
+ describe '#project_id' do
249
+ it 'returns the project_id from auth JSON' do
250
+ assert_equal 'coastal-haven-123456', subject.project_id
251
+ end
252
+ end
253
+
254
+ describe '#wait_for' do
255
+ it 'returns immediately when block yields true' do
256
+ result = subject.wait_for { true }
257
+ assert result[:duration] <= 1
206
258
  end
207
259
  end
208
260
  end
@@ -0,0 +1,235 @@
1
+ require 'test_google_helper'
2
+
3
+ module GoogleCloudCompute
4
+ class ComputeAttributesTest < GoogleTestCase
5
+ let(:client) { mock('GoogleAdapter') }
6
+ subject { GoogleCloudCompute::ComputeAttributes.new(client) }
7
+
8
+ setup do
9
+ client.stubs(:project_id).returns('my-project')
10
+ end
11
+
12
+ describe '#for_new' do
13
+ describe 'name handling' do
14
+ it 'generates a default name with foreman- prefix when name is nil' do
15
+ result = subject.for_new({})
16
+ assert_match(/\Aforeman-\d+\z/, result[:name])
17
+ assert_equal result[:name], result[:hostname]
18
+ end
19
+
20
+ it 'parameterizes the provided name' do
21
+ result = subject.for_new(name: 'My VM Name')
22
+ assert_equal 'my-vm-name', result[:name]
23
+ assert_equal 'my-vm-name', result[:hostname]
24
+ end
25
+ end
26
+
27
+ describe 'network handling' do
28
+ it 'defaults to default network' do
29
+ result = subject.for_new({})
30
+ assert_equal 'default', result[:network]
31
+ end
32
+
33
+ it 'uses custom network name' do
34
+ result = subject.for_new(network: 'custom-net')
35
+ assert_equal 'custom-net', result[:network]
36
+ end
37
+
38
+ it 'builds full URL without external IP' do
39
+ result = subject.for_new(network: 'default')
40
+ expected_url = 'https://compute.googleapis.com/compute/v1/projects/my-project/global/networks/default'
41
+ assert_equal expected_url, result[:network_interfaces][0][:network]
42
+ end
43
+
44
+ it 'adds NAT access config with external IP' do
45
+ result = subject.for_new(associate_external_ip: '1')
46
+ nic = result[:network_interfaces][0]
47
+ assert_equal 'global/networks/default', nic[:network]
48
+ assert_equal [{ name: 'External NAT', type: 'ONE_TO_ONE_NAT' }], nic[:access_configs]
49
+ end
50
+
51
+ it 'uses custom network interfaces with external IP' do
52
+ result = subject.for_new(
53
+ associate_external_ip: '1',
54
+ network_interfaces: [{ network: 'global/networks/my-net' }]
55
+ )
56
+ nic = result[:network_interfaces][0]
57
+ assert_equal 'global/networks/my-net', nic[:network]
58
+ assert_equal [{ name: 'External NAT', type: 'ONE_TO_ONE_NAT' }], nic[:access_configs]
59
+ end
60
+ end
61
+
62
+ describe 'associate_external_ip boolean casting' do
63
+ it 'casts string 1 to true' do
64
+ result = subject.for_new(associate_external_ip: '1')
65
+ assert result[:associate_external_ip]
66
+ end
67
+
68
+ it 'casts string 0 to false' do
69
+ result = subject.for_new(associate_external_ip: '0')
70
+ assert_not result[:associate_external_ip]
71
+ end
72
+
73
+ it 'defaults to false when absent' do
74
+ result = subject.for_new({})
75
+ assert_not result[:associate_external_ip]
76
+ end
77
+ end
78
+
79
+ describe 'volume construction' do
80
+ it 'creates a default 20 GB disk when no volumes' do
81
+ result = subject.for_new({})
82
+ assert_equal 1, result[:volumes].length
83
+ assert_equal 20, result[:volumes].first.disk_size_gb
84
+ end
85
+
86
+ it 'creates volumes with custom size' do
87
+ result = subject.for_new(volumes: [{ size_gb: '50' }])
88
+ assert_equal 50, result[:volumes].first.disk_size_gb
89
+ end
90
+
91
+ it 'sets source image on first volume when image_id is provided' do
92
+ image = OpenStruct.new(id: 1, self_link: 'projects/my-project/global/images/centos-7')
93
+ client.stubs(:image).with(1).returns(image)
94
+
95
+ result = subject.for_new(
96
+ volumes: [{ size_gb: '20' }, { size_gb: '30' }],
97
+ image_id: '1'
98
+ )
99
+
100
+ assert_equal 'projects/my-project/global/images/centos-7', result[:volumes][0].source
101
+ assert_empty result[:volumes][1].source
102
+ end
103
+
104
+ it 'names disks sequentially' do
105
+ result = subject.for_new(name: 'test-vm', volumes: [{ size_gb: '20' }, { size_gb: '30' }])
106
+ assert_equal 'test-vm-disk1', result[:volumes][0].device_name
107
+ assert_equal 'test-vm-disk2', result[:volumes][1].device_name
108
+ end
109
+
110
+ it 'accepts disk_size_gb as an alternative key' do
111
+ result = subject.for_new(volumes: [{ disk_size_gb: '40' }])
112
+ assert_equal 40, result[:volumes].first.disk_size_gb
113
+ end
114
+ end
115
+
116
+ describe 'metadata construction' do
117
+ it 'includes ssh-keys' do
118
+ result = subject.for_new(username: 'gce_user', public_key: 'ssh-rsa AAAA')
119
+ ssh_item = result[:metadata][:items].find { |i| i[:key] == 'ssh-keys' }
120
+ assert_equal 'gce_user:ssh-rsa AAAA', ssh_item[:value]
121
+ end
122
+
123
+ it 'includes user-data when present' do
124
+ result = subject.for_new(username: 'user', public_key: 'key', user_data: '#cloud-config')
125
+ ud_item = result[:metadata][:items].find { |i| i[:key] == 'user-data' }
126
+ assert_equal '#cloud-config', ud_item[:value]
127
+ end
128
+
129
+ it 'omits user-data when blank' do
130
+ result = subject.for_new(username: 'user', public_key: 'key')
131
+ keys = result[:metadata][:items].map { |i| i[:key] }
132
+ assert_not_includes keys, 'user-data'
133
+ end
134
+ end
135
+
136
+ it 'passes through machine_type and image_id' do
137
+ result = subject.for_new(machine_type: 'e2-micro', image_id: '42')
138
+ assert_equal 'e2-micro', result[:machine_type]
139
+ assert_equal '42', result[:image_id]
140
+ end
141
+ end
142
+
143
+ describe '#for_create' do
144
+ let(:instance) do
145
+ vol1 = Google::Cloud::Compute::V1::AttachedDisk.new(device_name: 'vm-disk1')
146
+ vol2 = Google::Cloud::Compute::V1::AttachedDisk.new(device_name: 'vm-disk2')
147
+ OpenStruct.new(
148
+ name: 'test-vm',
149
+ zone: 'us-east1-b',
150
+ machine_type: 'e2-micro',
151
+ volumes: [vol1, vol2],
152
+ network_interfaces: [{ network: 'global/networks/default' }],
153
+ metadata: { items: [{ key: 'ssh-keys', value: 'user:key' }] }
154
+ )
155
+ end
156
+
157
+ it 'builds machine_type URL from zone' do
158
+ result = subject.for_create(instance)
159
+ assert_equal 'zones/us-east1-b/machineTypes/e2-micro', result[:machine_type]
160
+ end
161
+
162
+ it 'builds disk source paths' do
163
+ result = subject.for_create(instance)
164
+ assert_equal 'zones/us-east1-b/disks/vm-disk1', result[:disks][0][:source]
165
+ assert_equal 'zones/us-east1-b/disks/vm-disk2', result[:disks][1][:source]
166
+ end
167
+
168
+ it 'marks first disk as boot' do
169
+ result = subject.for_create(instance)
170
+ assert result[:disks][0][:boot]
171
+ assert_not result[:disks][1][:boot]
172
+ end
173
+
174
+ it 'includes network_interfaces and metadata' do
175
+ result = subject.for_create(instance)
176
+ assert_equal instance.network_interfaces, result[:network_interfaces]
177
+ assert_equal instance.metadata, result[:metadata]
178
+ end
179
+
180
+ it 'includes name' do
181
+ result = subject.for_create(instance)
182
+ assert_equal 'test-vm', result[:name]
183
+ end
184
+ end
185
+
186
+ describe '#for_instance' do
187
+ let(:nics) do
188
+ [OpenStruct.new(network: 'projects/my-project/global/networks/custom', network_i_p: '10.0.0.1')]
189
+ end
190
+ let(:instance) do
191
+ OpenStruct.new(
192
+ name: 'existing-vm',
193
+ creation_timestamp: Time.zone.parse('2024-01-15 10:00:00'),
194
+ zone: 'projects/my-project/zones/us-west1-a',
195
+ machine_type: 'zones/us-west1-a/machineTypes/n1-standard-1',
196
+ network_interfaces: nics,
197
+ disks: [OpenStruct.new(device_name: 'disk1')],
198
+ metadata: { items: [] }
199
+ )
200
+ end
201
+
202
+ it 'extracts zone_name from full zone URL' do
203
+ result = subject.for_instance(instance)
204
+ assert_equal 'us-west1-a', result[:zone_name]
205
+ end
206
+
207
+ it 'extracts network name from full URL' do
208
+ result = subject.for_instance(instance)
209
+ assert_equal 'custom', result[:network]
210
+ end
211
+
212
+ it 'converts creation_timestamp to DateTime' do
213
+ result = subject.for_instance(instance)
214
+ assert_kind_of DateTime, result[:creation_timestamp]
215
+ end
216
+
217
+ it 'passes through name and hostname' do
218
+ result = subject.for_instance(instance)
219
+ assert_equal 'existing-vm', result[:name]
220
+ assert_equal 'existing-vm', result[:hostname]
221
+ end
222
+
223
+ it 'passes through disks as volumes and metadata' do
224
+ result = subject.for_instance(instance)
225
+ assert_equal instance.disks, result[:volumes]
226
+ assert_equal instance.metadata, result[:metadata]
227
+ end
228
+
229
+ it 'passes through machine_type' do
230
+ result = subject.for_instance(instance)
231
+ assert_equal instance.machine_type, result[:machine_type]
232
+ end
233
+ end
234
+ end
235
+ end
@@ -0,0 +1,78 @@
1
+ require 'test_google_helper'
2
+
3
+ module GoogleCloudCompute
4
+ class ComputeCollectionTest < GoogleTestCase
5
+ let(:client) { mock('GoogleAdapter') }
6
+ let(:zone) { 'us-east1-b' }
7
+
8
+ setup do
9
+ client.stubs(:project_id).returns('project_id')
10
+ end
11
+
12
+ describe 'with instances' do
13
+ let(:instances) do
14
+ nics = [OpenStruct.new(access_configs: [OpenStruct.new(nat_i_p: '1.2.3.4')],
15
+ network: 'projects/project_id/global/networks/default', network_i_p: '10.0.0.1')]
16
+ [
17
+ OpenStruct.new(id: 1, name: 'vm-1', network_interfaces: nics,
18
+ creation_timestamp: Time.zone.now, zone: zone, machine_type: 'machineTypes/e2-micro'),
19
+ OpenStruct.new(id: 2, name: 'vm-2', network_interfaces: nics,
20
+ creation_timestamp: Time.zone.now, zone: zone, machine_type: 'machineTypes/e2-small'),
21
+ ]
22
+ end
23
+
24
+ setup do
25
+ client.stubs(:instances).with(zone).returns(instances)
26
+ end
27
+
28
+ it 'wraps instances as GoogleCompute objects' do
29
+ collection = GoogleCloudCompute::ComputeCollection.new(client, zone)
30
+ collection.each do |vm|
31
+ assert_kind_of ForemanGoogle::GoogleCompute, vm
32
+ end
33
+ end
34
+
35
+ it 'iterates via each' do
36
+ collection = GoogleCloudCompute::ComputeCollection.new(client, zone)
37
+ names = collection.map(&:name)
38
+ assert_equal %w[vm-1 vm-2], names
39
+ end
40
+
41
+ it 'returns all VMs via all' do
42
+ collection = GoogleCloudCompute::ComputeCollection.new(client, zone)
43
+ assert_equal 2, collection.all.length
44
+ end
45
+
46
+ it 'is Enumerable' do
47
+ collection = GoogleCloudCompute::ComputeCollection.new(client, zone)
48
+ assert_kind_of Enumerable, collection
49
+ assert_equal 2, collection.count
50
+ end
51
+ end
52
+
53
+ describe 'with empty instance list' do
54
+ setup do
55
+ client.stubs(:instances).with(zone).returns([])
56
+ end
57
+
58
+ it 'returns empty collection' do
59
+ collection = GoogleCloudCompute::ComputeCollection.new(client, zone)
60
+ assert_empty collection.all
61
+ end
62
+
63
+ it 'iterates zero times' do
64
+ collection = GoogleCloudCompute::ComputeCollection.new(client, zone)
65
+ count = 0
66
+ collection.each { count += 1 }
67
+ assert_equal 0, count
68
+ end
69
+ end
70
+
71
+ describe 'with attrs' do
72
+ it 'passes attrs to client.instances' do
73
+ client.expects(:instances).with(zone, filter: 'name = "test"').returns([])
74
+ GoogleCloudCompute::ComputeCollection.new(client, zone, filter: 'name = "test"')
75
+ end
76
+ end
77
+ end
78
+ end
@@ -12,6 +12,41 @@ module GoogleExtensions
12
12
  disk = Google::Cloud::Compute::V1::AttachedDisk.new
13
13
  assert_empty disk.insert_attrs[:source_image]
14
14
  end
15
+
16
+ it 'includes device_name as name' do
17
+ disk = Google::Cloud::Compute::V1::AttachedDisk.new(device_name: 'boot-disk', disk_size_gb: 30)
18
+ attrs = disk.insert_attrs
19
+ assert_equal 'boot-disk', attrs[:name]
20
+ assert_equal 30, attrs[:size_gb]
21
+ end
22
+ end
23
+
24
+ describe '#size_gb' do
25
+ it 'returns disk_size_gb' do
26
+ disk = Google::Cloud::Compute::V1::AttachedDisk.new(disk_size_gb: 50)
27
+ assert_equal 50, disk.size_gb
28
+ end
29
+ end
30
+
31
+ describe '#persisted?' do
32
+ it 'returns nil' do
33
+ disk = Google::Cloud::Compute::V1::AttachedDisk.new
34
+ assert_nil disk.persisted?
35
+ end
36
+ end
37
+
38
+ describe '#id' do
39
+ it 'returns nil' do
40
+ disk = Google::Cloud::Compute::V1::AttachedDisk.new
41
+ assert_nil disk.id
42
+ end
43
+ end
44
+
45
+ describe '#_delete' do
46
+ it 'returns nil' do
47
+ disk = Google::Cloud::Compute::V1::AttachedDisk.new
48
+ assert_nil disk._delete
49
+ end
15
50
  end
16
51
  end
17
52
  end