beaker-google 0.3.0 → 0.4.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.
@@ -1,797 +1,488 @@
1
- require 'google/api_client'
1
+ # frozen_string_literal: true
2
+
3
+ require 'google/apis/compute_v1'
4
+ require 'google/apis/oslogin_v1'
5
+ require 'googleauth'
2
6
  require 'json'
3
7
  require 'time'
4
8
  require 'ostruct'
5
9
 
6
- module Beaker
7
- #Beaker helper module for doing API level Google Compute Engine interaction.
8
- class GoogleComputeHelper
10
+ # TODO: Figure out what to do about the timeout thing
11
+ # TODO: Implement Google::Apis::RequestOptions on all calls (In lib/google/apis/options.rb)
9
12
 
10
- class GoogleComputeError < StandardError
11
- end
13
+ # Beaker helper module for doing API level Google Compute Engine interaction.
14
+ class Beaker::GoogleComputeHelper
15
+ class GoogleComputeError < StandardError
16
+ end
12
17
 
13
- SLEEPWAIT = 5
14
-
15
- AUTH_URL = 'https://www.googleapis.com/auth/compute'
16
- API_VERSION = 'v1'
17
- BASE_URL = "https://www.googleapis.com/compute/#{API_VERSION}/projects/"
18
- CENTOS_PROJECT = 'centos-cloud'
19
- DEBIAN_PROJECT = 'debian-cloud'
20
- RHEL_PROJECT = 'rhel-cloud'
21
- SLES_PROJECT = 'sles-cloud'
22
- DEFAULT_ZONE_NAME = 'us-central1-a'
23
- DEFAULT_MACHINE_TYPE = 'n1-highmem-2'
24
- DEFAULT_DISK_SIZE = 25
25
-
26
- # Create a new instance of the Google Compute Engine helper object
27
- #
28
- # @param [Hash{Symbol=>String}] options The options hash containing
29
- # configuration values
30
- #
31
- # @option options [String] :gce_project The Google Compute Project name to
32
- # connect to
33
- #
34
- # @option options [String] :gce_keyfile The location of the Google Compute
35
- # service account keyfile
36
- #
37
- # @option options [String] :gce_password The password for the Google Compute
38
- # service account key
39
- #
40
- # @option options [String] :gce_email The email address for the Google
41
- # Compute service account
42
- #
43
- # @option options [String] :gce_machine_type A Google Compute machine type
44
- # used to create instances, defaults to n1-highmem-2
45
- #
46
- # @option options [Integer] :timeout The amount of time to attempt execution
47
- # before quiting and exiting with failure
48
- def initialize(options)
49
- @options = options
50
- @logger = options[:logger]
51
- try = 1
52
- attempts = @options[:timeout].to_i / SLEEPWAIT
53
- start = Time.now
54
-
55
- set_client(Beaker::Version::STRING)
56
- set_compute_api(API_VERSION, start, attempts)
57
-
58
- @options[:gce_project] = ENV['BEAKER_gce_project'] if ENV['BEAKER_gce_project']
59
- @options[:gce_keyfile] = ENV['BEAKER_gce_keyfile'] if ENV['BEAKER_gce_keyfile']
60
-
61
- unless (@options[:gce_keyfile] && File.exist?(@options[:gce_keyfile]))
62
- @options[:gce_keyfile] = File.join(ENV['HOME'], '.beaker', 'gce', %(#{@options[:gce_project]}.p12))
63
- end
64
-
65
- @options[:gce_password] = ENV['BEAKER_gce_password'] if ENV['BEAKER_gce_password']
66
- # This is the GCE default so there's usually not a reason to specify it
67
- @options[:gce_password] = 'notasecret' unless @options[:gce_password]
68
-
69
- @options[:gce_email] = ENV['BEAKER_gce_email'] if ENV['BEAKER_gce_email']
70
-
71
- raise 'You must specify a gce_project for Google Compute Engine instances!' unless @options[:gce_project]
72
-
73
- raise "Could not find gce_keyfile for Google Compute Engine at '#{@options[:gce_keyfile]}'!" unless File.exist?(@options[:gce_keyfile])
74
-
75
- raise 'You must specify a gce_email for Google Compute Engine instances!' unless @options[:gce_email]
76
-
77
- authenticate(@options[:gce_keyfile], @options[:gce_password], @options[:gce_email], start, attempts)
78
- end
18
+ SLEEPWAIT = 5
79
19
 
80
- # Determines the default Google Compute zone based upon options and
81
- # defaults
82
- #
83
- # @return The full URL to the default zone in which Google Compute requests
84
- # will be sent
85
- def default_zone
86
- BASE_URL + @options[:gce_project] + '/global/zones/' + DEFAULT_ZONE_NAME
87
- end
20
+ AUTH_URL = 'https://www.googleapis.com/auth/compute'
21
+ API_VERSION = 'v1'
22
+ BASE_URL = "https://www.googleapis.com/compute/#{API_VERSION}/projects/"
23
+ DEFAULT_ZONE_NAME = 'us-central1-a'
24
+ DEFAULT_MACHINE_TYPE = 'e2-standard-4'
25
+ DEFAULT_NETWORK_NAME = 'default'
88
26
 
89
- # Determines the default Google Compute network based upon defaults and
90
- # options
91
- #
92
- # @return The full URL to the default network in which Google Compute
93
- # instances will operate
94
- def default_network
95
- BASE_URL + @options[:gce_project] + '/global/networks/default'
96
- end
27
+ GCP_AUTH_SCOPE = [
28
+ Google::Apis::ComputeV1::AUTH_COMPUTE,
29
+ Google::Apis::OsloginV1::AUTH_CLOUD_PLATFORM_READ_ONLY,
30
+ ].freeze
97
31
 
98
- # Determines the Google Compute project which contains bases instances of
99
- # type name
100
- #
101
- # @param [String] name The platform type to search for
102
- #
103
- # @return The Google Compute project name
104
- #
105
- # @raise [Exception] If the provided platform type name is unsupported
106
- def get_platform_project(name)
107
- if name =~ /debian/
108
- return DEBIAN_PROJECT
109
- elsif name =~ /centos/
110
- return CENTOS_PROJECT
111
- elsif name =~ /rhel/
112
- return RHEL_PROJECT
113
- elsif name =~ /sles/
114
- return SLES_PROJECT
115
- else
116
- raise "Unsupported platform for Google Compute Engine: #{name}"
117
- end
118
- end
32
+ ##
33
+ # Create a new instance of the Google Compute Engine helper object
34
+ #
35
+ def initialize(options)
36
+ @options = options
37
+ @logger = options[:logger]
119
38
 
120
- # Create the Google APIClient object which will be used for accessing the
121
- # Google Compute API
122
- #
123
- # @param version The version number of Beaker currently running
124
- def set_client(version)
125
- @client = ::Google::APIClient.new({:application_name => "Beaker", :application_version => version})
126
- end
39
+ set_client(Beaker::Version::STRING)
127
40
 
128
- # Discover the currently active Google Compute API
129
- #
130
- # @param [String] version The version of the Google Compute API to discover
131
- #
132
- # @param [Integer] start The time when we started code execution, it is
133
- # compared to Time.now to determine how many further code execution
134
- # attempts remain
135
- #
136
- # @param [Integer] attempts The total amount of attempts to execute that we
137
- # are willing to allow
138
- #
139
- # @raise [Exception] Raised if we fail to discover the Google Compute API,
140
- # either through errors or running out of attempts
141
- def set_compute_api version, start, attempts
142
- try = (Time.now - start)/SLEEPWAIT
143
- while try <= attempts
144
- begin
145
- @compute = @client.discovered_api('compute', version)
146
- @logger.debug("Google Compute API discovered")
147
- return
148
- rescue => e
149
- @logger.debug("Failed to discover Google Compute API")
150
- if try >= attempts
151
- raise e
152
- end
153
- end
154
- try += 1
155
- end
156
- end
41
+ # ::Google::Apis.logger = ::Logger.new(::STDERR)
42
+ # ::Google::Apis.logger.level = ::Logger::DEBUG
43
+ # ::Google::Apis.logger.level = ::Logger::WARN
157
44
 
158
- # Creates an authenticated connection to the Google Compute Engine API
159
- #
160
- # @param [String] keyfile The location of the Google Compute Service
161
- # Account keyfile to use for authentication
162
- #
163
- # @param [String] password The password for the provided Google Compute
164
- # Service Account key
165
- #
166
- # @param [String] email The email address of the Google Compute Service
167
- # Account we are using to connect
168
- #
169
- # @param [Integer] start The time when we started code execution, it is
170
- # compared to Time.now to determine how many further code execution
171
- # attempts remain
172
- #
173
- # @param [Integer] attempts The total amount of attempts to execute that we
174
- # are willing to allow
175
- #
176
- # @raise [Exception] Raised if we fail to create an authenticated
177
- # connection to the Google Compute API, either through errors or running
178
- # out of attempts
179
- def authenticate(keyfile, password, email, start, attempts)
180
- # OAuth authentication, using the service account
181
- key = ::Google::APIClient::PKCS12.load_key(keyfile, password)
182
- service_account = ::Google::APIClient::JWTAsserter.new(
183
- email,
184
- AUTH_URL,
185
- key)
186
- try = (Time.now - start) / SLEEPWAIT
187
- while try <= attempts
188
- begin
189
- @client.authorization = service_account.authorize
190
- @logger.debug("Authorized to use Google Compute")
191
- return
192
- rescue => e
193
- @logger.debug("Failed to authorize to use Google Compute")
194
- if try >= attempts
195
- raise e
196
- end
197
- end
198
- try += 1
199
- end
200
- end
201
-
202
- # Executes a provided Google Compute request using a previously configured
203
- # and authenticated Google Compute client connection
204
- #
205
- # @param [Hash] req A correctly formatted Google Compute request object
206
- #
207
- # @param [Integer] start The time when we started code execution, it is
208
- # compared to Time.now to determine how many further code execution
209
- # attempts remain
210
- # @param [Integer] attempts The total amount of attempts to execute that we
211
- # are willing to allow
212
- #
213
- # @raise [Exception] Raised if we fail to execute the request, either
214
- # through errors or running out of attempts
215
- def execute req, start, attempts
216
- last_error = parsed = nil
217
- try = (Time.now - start) / SLEEPWAIT
218
- while try <= attempts
219
- begin
220
- result = @client.execute(req)
221
- parsed = JSON.parse(result.body)
222
- if not result.success?
223
- error_code = parsed["error"] ? parsed["error"]["code"] : 0
224
- if error_code == 404
225
- raise GoogleComputeError, "Resource Not Found: #{result.body}"
226
- elsif error_code == 400
227
- raise GoogleComputeError, "Bad Request: #{result.body}"
228
- else
229
- raise GoogleComputeError, "Error attempting Google Compute API execute: #{result.body}"
230
- end
231
- end
232
- return parsed
233
- # retry errors
234
- rescue Faraday::Error::ConnectionFailed => e
235
- @logger.debug "ConnectionFailed attempting Google Compute execute command"
236
- try += 1
237
- last_error = e
238
- end
239
- end
240
- # we only get down here if we've used up all our tries
241
- raise last_error
242
- end
243
-
244
- # Determines the latest image available for the provided platform name.
245
- #
246
- # Only images of the form (platform)-(version)-(version) are currently supported
247
- #
248
- # @param [String] platform The platform type to search for an instance of.
249
- #
250
- # @param [Integer] start The time when we started code execution, it is
251
- # compared to Time.now to determine how many further code execution
252
- # attempts remain
253
- #
254
- # @param [Integer] attempts The total amount of attempts to execute that we
255
- # are willing to allow
256
- #
257
- # @return [Hash] The image hash of the latest, non-deprecated image for the
258
- # provided platform
259
- #
260
- # @raise [Exception] Raised if we fail to execute the request, either
261
- # through errors or running out of attempts
262
- def get_latest_image(platform, start, attempts)
263
- #break up my platform for information
264
- platform_name, platform_version, platform_extra_info = platform.split('-', 3)
265
- #find latest image to use
266
- result = execute( image_list_req(get_platform_project(platform_name)), start, attempts )
267
- images = result["items"]
268
-
269
- #reject images of the wrong version of the given platform
270
- images.delete_if { |image| image['name'] !~ /^#{platform_name}-#{platform_version}/}
271
- #reject deprecated images
272
- images.delete_if { |image| image['deprecated']}
273
- #find a match based upon platform type
274
- if images.length != 1
275
- raise "Unable to find a single matching image for #{platform}, found #{images}"
276
- end
277
- images[0]
278
- end
279
-
280
- # Determines the Google Compute machineType object based upon the selected
281
- # gce_machine_type option
282
- #
283
- # @param [Integer] start The time when we started code execution, it is
284
- # compared to Time.now to determine how many further code execution
285
- # attempts remain
286
- #
287
- # @param [Integer] attempts The total amount of attempts to execute that we
288
- # are willing to allow
289
- #
290
- # @return [Hash] The machineType hash
291
- #
292
- # @raise [Exception] Raised if we fail get the machineType, either through
293
- # errors or running out of attempts
294
- def get_machineType(start, attempts)
295
- execute( machineType_get_req, start, attempts )
296
- end
45
+ @options[:gce_project] = ENV['BEAKER_gce_project'] if ENV['BEAKER_gce_project']
297
46
 
298
- # Determines the Google Compute network object in use for the current connection
299
- # @param [Integer] start The time when we started code execution, it is
300
- # compared to Time.now to determine how many further code execution
301
- # attempts remain
302
- #
303
- # @param [Integer] attempts The total amount of attempts to execute that we
304
- # are willing to allow
305
- #
306
- # @return [Hash] The network hash
307
- #
308
- # @raise [Exception] Raised if we fail get the network, either through
309
- # errors or running out of attempts
310
- def get_network(start, attempts)
311
- execute( network_get_req, start, attempts)
312
- end
47
+ @options[:gce_zone] = ENV.fetch('BEAKER_gce_zone', DEFAULT_ZONE_NAME)
48
+ @options[:gce_network] = ENV.fetch('BEAKER_gce_network', DEFAULT_NETWORK_NAME)
49
+ @options[:gce_subnetwork] = ENV.fetch('BEAKER_gce_subnetwork', nil)
313
50
 
314
- # Determines a list of existing Google Compute instances
315
- #
316
- # @param [Integer] start The time when we started code execution, it is
317
- # compared to Time.now to determine how many further code execution
318
- # attempts remain
319
- #
320
- # @param [Integer] attempts The total amount of attempts to execute that we
321
- # are willing to allow
322
- #
323
- # @return [Array[Hash]] The instances array of hashes
324
- #
325
- # @raise [Exception] Raised if we fail determine the list of existing
326
- # instances, either through errors or running out of attempts
327
- def list_instances(start, attempts)
328
- instances = execute( instance_list_req(), start, attempts )
329
- instances["items"]
330
- end
51
+ raise 'You must specify a gce_project for Google Compute Engine instances!' unless @options[:gce_project]
331
52
 
332
- # Determines a list of existing Google Compute disks
333
- #
334
- # @param [Integer] start The time when we started code execution, it is
335
- # compared to Time.now to determine how many further code execution
336
- # attempts remain
337
- #
338
- # @param [Integer] attempts The total amount of attempts to execute that we
339
- # are willing to allow
340
- #
341
- # @return [Array[Hash]] The disks array of hashes
342
- #
343
- # @raise [Exception] Raised if we fail determine the list of existing
344
- # disks, either through errors or running out of attempts
345
- def list_disks(start, attempts)
346
- disks = execute( disk_list_req(), start, attempts )
347
- disks["items"]
348
- end
53
+ authorizer = authenticate
54
+ @compute = ::Google::Apis::ComputeV1::ComputeService.new
55
+ @compute.authorization = authorizer
349
56
 
350
- # Determines a list of existing Google Compute firewalls
351
- #
352
- # @param [Integer] start The time when we started code execution, it is
353
- # compared to Time.now to determine how many further code execution
354
- # attempts remain
355
- #
356
- # @param [Integer] attempts The total amount of attempts to execute that we
357
- # are willing to allow
358
- #
359
- # @return [Array[Hash]] The firewalls array of hashes
360
- #
361
- # @raise [Exception] Raised if we fail determine the list of existing
362
- # firewalls, either through errors or running out of attempts
363
- def list_firewalls(start, attempts)
364
- result = execute( firewall_list_req(), start, attempts )
365
- firewalls = result["items"]
366
- firewalls.delete_if{|f| f['name'] =~ /default-allow-internal|default-ssh/}
367
- firewalls
368
- end
57
+ # Find the appropriate username to log into created instances
58
+ @cloudoslogin = Google::Apis::OsloginV1::CloudOSLoginService.new
59
+ @cloudoslogin.authorization = authorizer
60
+ end
369
61
 
370
- # Create a Google Compute firewall on the current connection
371
- #
372
- # @param [String] name The name of the firewall to create
373
- #
374
- # @param [Hash] network The Google Compute network hash in which to create
375
- # the firewall
376
- #
377
- # @param [Integer] start The time when we started code execution, it is
378
- # compared to Time.now to determine how many further code execution
379
- # attempts remain
380
- #
381
- # @param [Integer] attempts The total amount of attempts to execute that we
382
- # are willing to allow
383
- #
384
- # @raise [Exception] Raised if we fail create the firewall, either through
385
- # errors or running out of attempts
386
- def create_firewall(name, network, start, attempts)
387
- execute( firewall_insert_req( name, network['selfLink'] ), start, attempts )
388
- end
62
+ ##
63
+ # Determines the default Google Compute zone based upon options and
64
+ # defaults
65
+ #
66
+ # @return [String] The name of the zone
67
+ def default_zone
68
+ @options[:gce_zone]
69
+ end
389
70
 
390
- # Create a Google Compute disk on the current connection
391
- #
392
- # @param [String] name The name of the disk to create
393
- #
394
- # @param [Hash] img The Google Compute image to use for instance creation
395
- #
396
- # @param [Integer] start The time when we started code execution, it is
397
- # compared to Time.now to determine how many further code execution
398
- # attempts remain
399
- #
400
- # @param [Integer] attempts The total amount of attempts to execute that we
401
- # are willing to allow
402
- #
403
- # @raise [Exception] Raised if we fail create the disk, either through
404
- # errors or running out of attempts
405
- def create_disk(name, img, start, attempts)
406
- #create a new boot disk for this instance
407
- disk = execute( disk_insert_req( name, img['selfLink'] ), start, attempts )
408
-
409
- status = ''
410
- try = (Time.now - start) / SLEEPWAIT
411
- while status !~ /READY/ and try <= attempts
412
- begin
413
- disk = execute( disk_get_req( name ), start, attempts )
414
- status = disk['status']
415
- rescue GoogleComputeError => e
416
- @logger.debug("Waiting for #{name} disk creation")
417
- sleep(SLEEPWAIT)
418
- end
419
- try += 1
420
- end
421
- if status == ''
422
- raise "Unable to create disk #{name}"
423
- end
424
- disk
425
- end
71
+ ##
72
+ # Get the region name from the provided zone.
73
+ #
74
+ # Assume that the region is the name of the zone without
75
+ # the final - and zone letter
76
+ #
77
+ # @return [String] The name of the region
78
+ def default_region
79
+ @options[:gce_zone].split('-')[0..1].join('-')
80
+ end
426
81
 
427
- # Create a Google Compute instance on the current connection
428
- #
429
- # @param [String] name The name of the instance to create
430
- #
431
- # @param [Hash] img The Google Compute image to use for instance creation
432
- #
433
- # @param [Hash] machineType The Google Compute machineType
434
- #
435
- # @param [Hash] disk The Google Compute disk to attach to the newly created
436
- # instance
437
- #
438
- # @param [Integer] start The time when we started code execution, it is
439
- # compared to Time.now to determine how many further code execution
440
- # attempts remain
441
- #
442
- # @param [Integer] attempts The total amount of attempts to execute that we
443
- # are willing to allow
444
- #
445
- # @raise [Exception] Raised if we fail create the instance, either through
446
- # errors or running out of attempts
447
- def create_instance(name, img, machineType, disk, start, attempts)
448
- #add a new instance of the image
449
- instance = execute( instance_insert_req( name, img['selfLink'], machineType['selfLink'], disk['selfLink'] ), start, attempts)
450
- status = ''
451
- try = (Time.now - start) / SLEEPWAIT
452
- while status !~ /RUNNING/ and try <= attempts
453
- begin
454
- instance = execute( instance_get_req( name ), start, attempts )
455
- status = instance['status']
456
- rescue GoogleComputeError => e
457
- @logger.debug("Waiting for #{name} instance creation")
458
- sleep(SLEEPWAIT)
459
- end
460
- try += 1
461
- end
462
- if status == ''
463
- raise "Unable to create instance #{name}"
464
- end
465
- instance
466
- end
82
+ ##
83
+ # Determines the default Google Compute network based upon defaults and
84
+ # options
85
+ #
86
+ # @return [String] The short name of the VPC network
87
+ def default_network
88
+ @options[:gce_network]
89
+ end
467
90
 
468
- # Add key/value pairs to a Google Compute instance on the current
469
- # connection
470
- #
471
- # @param [String] name The name of the instance to add metadata to
472
- #
473
- # @param [String] fingerprint A hash of the metadata's contents of the
474
- # given instance
475
- #
476
- # @param [Array<Hash>] data An array of hashes. Each hash should have a
477
- # key and a value.
478
- #
479
- # @param [Integer] start The time when we started code execution, it is
480
- # compared to Time.now to determine how many further code execution
481
- # attempts remain
482
- #
483
- # @param [Integer] attempts The total amount of attempts to execute that we
484
- # are willing to allow
485
- #
486
- # @raise [Exception] Raised if we fail to add metadata, either through
487
- # errors or running out of attempts
488
- def setMetadata_on_instance(name, fingerprint, data, start, attempts)
489
- zone_operation = execute( instance_setMetadata_req( name, fingerprint, data), start, attempts )
490
- status = ''
491
- try = (Time.now - start) / SLEEPWAIT
492
- while status !~ /DONE/ and try <= attempts
493
- begin
494
- operation = execute( operation_get_req( zone_operation['name'] ), start, attempts )
495
- status = operation['status']
496
- rescue GoogleComputeError => e
497
- @logger.debug("Waiting for tags to be added to #{name}")
498
- sleep(SLEEPWAIT)
499
- end
500
- try += 1
501
- end
502
- if status == ''
503
- raise "Unable to set metaData (#{tags.to_s}) on #{name}"
504
- end
505
- zone_operation
506
- end
91
+ ##
92
+ # Find the username for ssh to use with this connection
93
+ #
94
+ # @return [String] The username for ssh
95
+ #
96
+ # @raise [Google::Auth::IDTokens::KeySourceError] if the key source failed to obtain public keys
97
+ # @raise [Google::Auth::IDTokens::VerificationError] if the token verification failed.
98
+ # Additional data may be available in the error subclass and message.
99
+ def ssh_username
100
+ authorizer = @compute.authorization
101
+ # This is a bit of a hack based on what I found in a user (default application credentials)
102
+ # and a service account. There might be a better way of doing this.
103
+ case authorizer.class.to_s
104
+ when 'Google::Auth::UserRefreshCredentials'
105
+ authorizer.refresh!
106
+ userid = ::Google::Auth::IDTokens.verify_oidc(authorizer.id_token)['email']
107
+ when 'Google::Auth::ServiceAccountCredentials'
108
+ userid = authorizer.issuer
109
+ else
110
+ raise 'Unknown type of credential'
111
+ end
112
+ userid = "users/#{userid}" unless userid.start_with? 'users/'
113
+ @cloudoslogin.get_user_login_profile(userid).posix_accounts[0].username
114
+ end
507
115
 
508
- # Delete a Google Compute instance on the current connection
509
- #
510
- # @param [String] name The name of the instance to delete
511
- #
512
- # @param [Integer] start The time when we started code execution, it is
513
- # compared to Time.now to determine how many further code execution
514
- # attempts remain
515
- #
516
- # @param [Integer] attempts The total amount of attempts to execute that we
517
- # are willing to allow
518
- #
519
- # @raise [Exception] Raised if we fail delete the instance, either through
520
- # errors or running out of attempts
521
- def delete_instance(name, start, attempts)
522
- result = execute( instance_delete_req( name ), start, attempts )
523
-
524
- # Ensure deletion of instance
525
- try = (Time.now - start) / SLEEPWAIT
526
- while try <= attempts
527
- begin
528
- result = execute( instance_get_req( name ), start, attempts )
529
- @logger.debug("Waiting for #{name} instance deletion")
530
- sleep(SLEEPWAIT)
531
- rescue GoogleComputeError => e
532
- @logger.debug("#{name} instance deleted!")
533
- return
534
- end
535
- try += 1
536
- end
537
- @logger.debug("#{name} instance was not removed before timeout, may still exist")
538
- end
116
+ ##
117
+ # Infer the network that a given subnetwork is attached to
118
+ #
119
+ # @param [String] subnetwork_name The name of the subnetwork
120
+ #
121
+ # @return [String] The short name of the network
122
+ #
123
+ # @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
124
+ # @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
125
+ # @raise [Google::Apis::AuthorizationError] Authorization is required
126
+ def default_network_from_subnet(subnetwork_name)
127
+ subnetwork = @compute.get_subnetwork(@options[:gce_project], default_region, subnetwork_name)
128
+ m = %r{.*/networks/(?<network_name>.*)\Z}.match subnetwork.network
129
+ nil if m.nil?
130
+ m['network_name']
131
+ end
539
132
 
540
- # Delete a Google Compute disk on the current connection
541
- #
542
- # @param [String] name The name of the disk to delete
543
- #
544
- # @param [Integer] start The time when we started code execution, it is
545
- # compared to Time.now to determine how many further code execution
546
- # attempts remain
547
- #
548
- # @param [Integer] attempts The total amount of attempts to execute that we
549
- # are willing to allow
550
- #
551
- # @raise [Exception] Raised if we fail delete the disk, either through
552
- # errors or running out of attempts
553
- def delete_disk(name, start, attempts)
554
- result = execute( disk_delete_req( name ), start, attempts )
555
-
556
- # Ensure deletion of disk
557
- try = (Time.now - start) / SLEEPWAIT
558
- while try <= attempts
559
- begin
560
- disk = execute( disk_get_req( name ), start, attempts )
561
- @logger.debug("Waiting for #{name} disk deletion")
562
- sleep(SLEEPWAIT)
563
- rescue GoogleComputeError => e
564
- @logger.debug("#{name} disk deleted!")
565
- return
566
- end
567
- try += 1
568
- end
569
- @logger.debug("#{name} disk was not removed before timeout, may still exist")
570
- end
133
+ ##
134
+ # Determine the subnetwork to use for instances
135
+ #
136
+ # If the network is the 'default' network, get the 'default' subnetwork for the region.
137
+ # If no subnet is provided by the user, pick the first one out of the user-provided network
138
+ #
139
+ # @return [String] The name of the subnetwork that should be attached to the instances
140
+ def default_subnetwork
141
+ network_name = @options[:gce_network]
142
+ if network_name == 'default'
143
+ @options[:gce_subnetwork] ||= @compute.get_subnetwork(@options[:gce_project], default_region, 'default').name
144
+ elsif @options[:gce_subnetwork].nil?
145
+ # No subnet set, get the first subnet in our current region for the network
146
+ subnetwork = @compute.get_network(@options[:gce_project], network_name).subnetworks[0]
147
+ m = %r{.*/subnetworks/(?<subnetwork_name>.*)\Z}.match subnetwork
148
+ raise "Unable to find a subnetwork in provided network #{network_name}" if m.nil?
149
+
150
+ @options[:gce_subnetwork] = m['subnetwork_name']
151
+ end
152
+ @options[:gce_subnetwork]
153
+ end
571
154
 
572
- # Delete a Google Compute firewall on the current connection
573
- #
574
- # @param [String] name The name of the firewall to delete
575
- #
576
- # @param [Integer] start The time when we started code execution, it is
577
- # compared to Time.now to determine how many further code execution
578
- # attempts remain
579
- #
580
- # @param [Integer] attempts The total amount of attempts to execute that we
581
- # are willing to allow
582
- #
583
- # @raise [Exception] Raised if we fail delete the firewall, either through
584
- # errors or running out of attempts
585
- def delete_firewall(name, start, attempts)
586
- result = execute( firewall_delete_req( name ), start, attempts )
587
- #ensure deletion of disk
588
- try = (Time.now - start) / SLEEPWAIT
589
- while try <= attempts
590
- begin
591
- firewall = execute( firewall_get_req( name ), start, attempts )
592
- @logger.debug("Waiting for #{name} firewall deletion")
593
- sleep(SLEEPWAIT)
594
- rescue GoogleComputeError => e
595
- @logger.debug("#{name} firewall deleted!")
596
- return
597
- end
598
- try += 1
599
- end
600
- @logger.debug("#{name} firewall was not removed before timeout, may still exist")
601
- end
155
+ ##
156
+ # Set the user-agent information for the application.
157
+ #
158
+ # @param version The version number of Beaker currently running
159
+ def set_client(version)
160
+ ::Google::Apis::ClientOptions.default.application_name = 'beaker-google'
161
+ ::Google::Apis::ClientOptions.default.application_version = version
162
+ end
602
163
 
603
- # Create a Google Compute list all images request
604
- #
605
- # @param [String] name The Google Compute project name to query
606
- #
607
- # @return [Hash] A correctly formatted Google Compute request hash
608
- def image_list_req(name)
609
- { :api_method => @compute.images.list,
610
- :parameters => { 'project' => name } }
164
+ ##
165
+ # Creates an authentication object to use in the various Google APIs
166
+ #
167
+ # This method currently supports using application credentials via the
168
+ # GOOGLE_APPLICATION_CREDENTIALS environment variable, and application default
169
+ # credentials.
170
+ #
171
+ # @return [Google::Auth::UserRefreshCredentials|Google::Auth::ServiceAccountCredentials]
172
+ # Authorization object to pass to Google APIs
173
+ def authenticate
174
+ if ENV['GOOGLE_APPLICATION_CREDENTIALS']
175
+ ::Google::Auth::ServiceAccountCredentials.from_env(scope: GCP_AUTH_SCOPE)
176
+ else
177
+ # Fall back to default application auth
178
+ ::Google::Auth.get_application_default(GCP_AUTH_SCOPE)
611
179
  end
180
+ end
612
181
 
613
- # Create a Google Compute list all disks request
614
- #
615
- # @return [Hash] A correctly formatted Google Compute request hash
616
- def disk_list_req
617
- { :api_method => @compute.disks.list,
618
- :parameters => { 'project' => @options[:gce_project], 'zone' => DEFAULT_ZONE_NAME } }
619
- end
182
+ ##
183
+ # Find the correct image object for a given project and name
184
+ #
185
+ # @param [String] image_project The project that owns the requested image
186
+ #
187
+ # @param [String] name The name of the image in the project. This must
188
+ # be the exact name of the image
189
+ #
190
+ # @return [Google::Apis::ComputeV1::Image]
191
+ #
192
+ # @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
193
+ # @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
194
+ # @raise [Google::Apis::AuthorizationError] Authorization is required
195
+ def get_image(project, name)
196
+ @compute.get_image(project, name)
197
+ end
620
198
 
621
- # Create a Google Compute get disk request
622
- #
623
- # @param [String] name The name of the disk to query for
624
- #
625
- # @return [Hash] A correctly formatted Google Compute request hash
626
- def disk_get_req(name)
627
- { :api_method => @compute.disks.get,
628
- :parameters => { 'project' => @options[:gce_project], 'zone' => DEFAULT_ZONE_NAME, 'disk' => name } }
629
- end
199
+ ##
200
+ # Find the latest non-deprecated image in the given project and family
201
+ #
202
+ # @param [String] image_project The project that owns the requested image
203
+ #
204
+ # @param [String] family The name of the image family
205
+ #
206
+ # @return [Google::Apis::ComputeV1::Image]
207
+ #
208
+ # @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
209
+ # @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
210
+ # @raise [Google::Apis::AuthorizationError] Authorization is required
211
+ def get_latest_image_from_family(image_project, family)
212
+ @compute.get_image_from_family(image_project, family)
213
+ end
630
214
 
631
- # Create a Google Compute disk delete request
632
- #
633
- # @param [String] name The name of the disk delete
634
- #
635
- # @return [Hash] A correctly formatted Google Compute request hash
636
- def disk_delete_req(name)
637
- { :api_method => @compute.disks.delete,
638
- :parameters => { 'project' => @options[:gce_project], 'zone' => DEFAULT_ZONE_NAME, 'disk' => name } }
639
- end
215
+ ##
216
+ # Determines the Google Compute machineType object based upon the selected
217
+ # gce_machine_type option
218
+ #
219
+ # @param [String] type_name The name of the type to get
220
+ #
221
+ # @return [Google::Apis::ComputeV1::MachineType]
222
+ #
223
+ # @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
224
+ # @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
225
+ # @raise [Google::Apis::AuthorizationError] Authorization is required
226
+ def get_machine_type(type_name = DEFAULT_MACHINE_TYPE)
227
+ @compute.get_machine_type(@options[:gce_project], default_zone, type_name)
228
+ end
640
229
 
641
- # Create a Google Compute disk create request
642
- #
643
- # @param [String] name The name of the disk to create
644
- #
645
- # @param [String] source The link to a Google Compute image to base the
646
- # disk creation on
647
- #
648
- # @return [Hash] A correctly formatted Google Compute request hash
649
- #
650
- def disk_insert_req(name, source)
651
- { :api_method => @compute.disks.insert,
652
- :parameters => { 'project' => @options[:gce_project], 'zone' => DEFAULT_ZONE_NAME, 'sourceImage' => source },
653
- :body_object => { 'name' => name, 'sizeGb' => DEFAULT_DISK_SIZE } }
654
- end
230
+ ##
231
+ # Determines the Google Compute network object in use for the current connection
232
+ #
233
+ # @return [Google::Apis::ComputeV1::Network]
234
+ #
235
+ # @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
236
+ # @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
237
+ # @raise [Google::Apis::AuthorizationError] Authorization is required
238
+ def get_network(network_name = default_network)
239
+ @compute.get_network(@options[:gce_project], network_name)
240
+ end
655
241
 
656
- # Create a Google Compute get firewall request
657
- #
658
- # @param [String] name The name of the firewall to query for
659
- #
660
- # @return [Hash] A correctly formatted Google Compute request hash
661
- def firewall_get_req(name)
662
- { :api_method => @compute.firewalls.get,
663
- :parameters => { 'project' => @options[:gce_project], 'zone' => DEFAULT_ZONE_NAME, 'firewall' => name } }
664
- end
242
+ ##
243
+ # Determines a list of existing Google Compute instances
244
+ #
245
+ # @return [Array[Google::Apis::ComputeV1::Instance]]
246
+ #
247
+ # @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
248
+ # @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
249
+ # @raise [Google::Apis::AuthorizationError] Authorization is required
250
+ def list_instances
251
+ @compute.list_instances(@options[:gce_project], default_zone).items
252
+ end
665
253
 
666
- # Create a Google Compute insert firewall request, open ports 443, 8140 and
667
- # 61613
668
- #
669
- # @param [String] name The name of the firewall to create
670
- #
671
- # @param [String] network The link to the Google Compute network to attach
672
- # this firewall to
673
- #
674
- # @return [Hash] A correctly formatted Google Compute request hash
675
- def firewall_insert_req(name, network)
676
- { :api_method => @compute.firewalls.insert,
677
- :parameters => { 'project' => @options[:gce_project], 'zone' => DEFAULT_ZONE_NAME },
678
- :body_object => { 'name' => name,
679
- 'allowed'=> [ { 'IPProtocol' => 'tcp', "ports" => [ '443', '8140', '61613', '8080', '8081' ]} ],
680
- 'network'=> network,
681
- 'sourceRanges' => [ "0.0.0.0/0" ] } }
682
- end
254
+ ##
255
+ # Determines a list of existing Google Compute disks
256
+ #
257
+ # @param [Integer] start The time when we started code execution, it is
258
+ # compared to Time.now to determine how many further code execution
259
+ # attempts remain
260
+ #
261
+ # @return [Array[Google::Apis::ComputeV1::Disk]]
262
+ #
263
+ # @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
264
+ # @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
265
+ # @raise [Google::Apis::AuthorizationError] Authorization is required
266
+ def list_disks
267
+ @compute.list_disks(@options[:gce_project], default_zone).items
268
+ end
683
269
 
684
- # Create a Google Compute delete firewall request
685
- #
686
- # @param [String] name The name of the firewall to delete
687
- #
688
- # @return [Hash] A correctly formatted Google Compute request hash
689
- def firewall_delete_req(name)
690
- { :api_method => @compute.firewalls.delete,
691
- :parameters => { 'project' => @options[:gce_project], 'zone' => DEFAULT_ZONE_NAME, 'firewall' => name } }
692
- end
270
+ ##
271
+ # Determines a list of existing Google Compute firewalls
272
+ #
273
+ # @return [Array[Google::Apis::ComputeV1::Firewall]]
274
+ #
275
+ # @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
276
+ # @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
277
+ # @raise [Google::Apis::AuthorizationError] Authorization is required
278
+ def list_firewalls
279
+ @compute.list_firewalls(@options[:gce_project],
280
+ filter: 'name != default-allow-internal AND name != default-ssh').items
281
+ end
693
282
 
694
- # Create a Google Compute list firewall request
695
- #
696
- # @return [Hash] A correctly formatted Google Compute request hash
697
- def firewall_list_req()
698
- { :api_method => @compute.firewalls.list,
699
- :parameters => { 'project' => @options[:gce_project], 'zone' => DEFAULT_ZONE_NAME } }
700
- end
283
+ ##
284
+ # Create a Google Compute firewall
285
+ #
286
+ # @param [String] name The name of the firewall to create
287
+ #
288
+ # @param [::Google::Apis::ComputeV1::Network] network The Google Compute networkin which to create
289
+ # the firewall
290
+ #
291
+ # @return [Google::Apis::ComputeV1::Operation]
292
+ #
293
+ # @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
294
+ # @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
295
+ # @raise [Google::Apis::AuthorizationError] Authorization is required
296
+ def create_firewall(name, network)
297
+ firewall_object = ::Google::Apis::ComputeV1::Firewall.new(
298
+ name: name,
299
+ allowed: [
300
+ ::Google::Apis::ComputeV1::Firewall::Allowed.new(ip_protocol: 'tcp',
301
+ ports: ['443', '8140', '61613', '8080', '8081', '22']),
302
+ ],
303
+ network: network.self_link,
304
+ # TODO: Is there a better way to do this?
305
+ sourceRanges: ['0.0.0.0/0'], # Allow from anywhere
306
+ )
307
+ operation = @compute.insert_firewall(@options[:gce_project], firewall_object)
308
+ @compute.wait_global_operation(@options[:gce_project], operation.name)
309
+ end
701
310
 
702
- # Create a Google Compute get network request
703
- #
704
- # @param [String] name (default) The name of the network to access
705
- # information about
706
- #
707
- # @return [Hash] A correctly formatted Google Compute request hash
708
- def network_get_req(name = 'default')
709
- { :api_method => @compute.networks.get,
710
- :parameters => { 'project' => @options[:gce_project], 'zone' => DEFAULT_ZONE_NAME, 'network' => name } }
711
- end
311
+ ##
312
+ # Add a taget_tag to an existing firewall
313
+ #
314
+ # @param [String] the name of the firewall to update
315
+ #
316
+ # @ param [String] tag The tag to add to the firewall
317
+ #
318
+ # @return [Google::Apis::ComputeV1::Operation]
319
+ #
320
+ # @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
321
+ # @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
322
+ # @raise [Google::Apis::AuthorizationError] Authorization is required
323
+ def add_firewall_tag(name, tag)
324
+ firewall = @compute.get_firewall(@options[:gce_project], name)
325
+ firewall.target_tags = [] if firewall.target_tags.nil?
326
+ firewall.target_tags << tag
327
+ operation = @compute.patch_firewall(@options[:gce_project], name, firewall)
328
+ @compute.wait_global_operation(@options[:gce_project], operation.name)
329
+ end
712
330
 
713
- # Create a Google Compute zone operation request
714
- #
715
- # @return [Hash] A correctly formatted Google Compute request hash
716
- def operation_get_req(name)
717
- { :api_method => @compute.zone_operations.get,
718
- :parameters => { 'project' => @options[:gce_project], 'zone' => DEFAULT_ZONE_NAME, 'operation' => name } }
719
- end
331
+ ##
332
+ # Create a Google Compute disk
333
+ #
334
+ # @param [String] name The name of the disk to create
335
+ #
336
+ # @param [String] img The existing disk image to clone for this image
337
+ # or nil to create a blank disk
338
+ #
339
+ # @return [Google::Apis::ComputeV1::Operation]
340
+ #
341
+ # @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
342
+ # @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
343
+ # @raise [Google::Apis::AuthorizationError] Authorization is required
344
+ def create_disk(name, size, img = nil)
345
+ new_disk = ::Google::Apis::ComputeV1::Disk.new(
346
+ name: name,
347
+ size_gb: size,
348
+ source_image: img,
349
+ )
350
+ operation = @compute.insert_disk(@options[:gce_project], @options[:gce_zone], new_disk)
351
+ @compute.wait_zone_operation(@options[:gce_project], @options[:gce_zone], operation.name)
352
+ end
720
353
 
721
- # Set tags on a Google Compute instance
722
- #
723
- # @param [Array<String>] data An array of tags to be added to an instance
724
- #
725
- # @return [Hash] A correctly formatted Google Compute request hash
726
- def instance_setMetadata_req(name, fingerprint, data)
727
- { :api_method => @compute.instances.set_metadata,
728
- :parameters => { 'project' => @options[:gce_project], 'zone' => DEFAULT_ZONE_NAME, 'instance' => name },
729
- :body_object => { 'kind' => 'compute#metadata',
730
- 'fingerprint' => fingerprint,
731
- 'items' => data }
732
- }
733
- end
354
+ ##
355
+ # Create a Google Compute instance
356
+ #
357
+ # @param [String] name The name of the instance to create
358
+ #
359
+ # @param [Google::Apis::ComputeV1::Image] img The Google Compute image to use for instance creation
360
+ #
361
+ # @param [Google::Apis::ComputeV1::MachineType] machine_type The Google Compute Machine Type
362
+ #
363
+ # @param [Integer] disk_size The size of the boot disk for the new instance. Must be equal to or
364
+ # greater than the image disk's size
365
+ #
366
+ # @return [Google::Apis::ComputeV1::Operation]
367
+ #
368
+ # @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
369
+ # @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
370
+ # @raise [Google::Apis::AuthorizationError] Authorization is required
371
+ def create_instance(name, img, machine_type, disk_size)
372
+ initialize_params = ::Google::Apis::ComputeV1::AttachedDiskInitializeParams.new(
373
+ disk_size_gb: disk_size,
374
+ source_image: img.self_link,
375
+ )
376
+ disk_params = ::Google::Apis::ComputeV1::AttachedDisk.new(
377
+ boot: true,
378
+ auto_delete: true,
379
+ initialize_params: initialize_params,
380
+ )
381
+ # attached_network = ::Google::Apis::ComputeV1::networkInterfaces.new()
382
+ tags = ::Google::Apis::ComputeV1::Tags.new(
383
+ items: [name],
384
+ )
385
+ network_interface = ::Google::Apis::ComputeV1::NetworkInterface.new(
386
+ network: get_network(default_network).self_link,
387
+ subnetwork: @compute.get_subnetwork(@options[:gce_project], default_region, default_subnetwork).self_link,
388
+ # Create an AccessConfig to add a NAT IP to the host.
389
+ # TODO: Make this configurable
390
+ access_configs: [
391
+ ::Google::Apis::ComputeV1::AccessConfig.new(
392
+ network_tier: 'STANDARD',
393
+ ),
394
+ ],
395
+ )
396
+ new_instance = ::Google::Apis::ComputeV1::Instance.new(
397
+ machine_type: machine_type.self_link,
398
+ name: name,
399
+ disks: [disk_params],
400
+ network_interfaces: [network_interface],
401
+ tags: tags,
402
+ )
403
+ operation = @compute.insert_instance(@options[:gce_project], @options[:gce_zone], new_instance)
404
+ @compute.wait_zone_operation(@options[:gce_project], @options[:gce_zone], operation.name)
405
+ end
734
406
 
735
- # Create a Google Compute list instance request
736
- #
737
- # @return [Hash] A correctly formatted Google Compute request hash
738
- def instance_list_req
739
- { :api_method => @compute.instances.list,
740
- :parameters => { 'project' => @options[:gce_project], 'zone' => DEFAULT_ZONE_NAME } }
741
- end
407
+ ##
408
+ # Get the named instace from Google Compute Image
409
+ #
410
+ # @param [String] name The name of the instance
411
+ #
412
+ # @return [Google::Apis::ComputeV1::Instance]
413
+ #
414
+ # @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
415
+ # @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
416
+ # @raise [Google::Apis::AuthorizationError] Authorization is required
417
+ def get_instance(name)
418
+ @compute.get_instance(@options[:gce_project], @options[:gce_zone], name)
419
+ end
742
420
 
743
- # Create a Google Compute get instance request
744
- #
745
- # @param [String] name The name of the instance to query for
746
- #
747
- # @return [Hash] A correctly formatted Google Compute request hash
748
- def instance_get_req(name)
749
- { :api_method => @compute.instances.get,
750
- :parameters => { 'project' => @options[:gce_project], 'zone' => DEFAULT_ZONE_NAME, 'instance' => name } }
751
- end
421
+ ##
422
+ # Set key/value metadata pairs to a Google Compute instance
423
+ #
424
+ # This function replaces any existing items in the metadata hash!
425
+ #
426
+ # @param [String] name The name of the instance to set metadata
427
+ #
428
+ # @param [String] data An array of hashes to set ass metadata. Each array
429
+ # item should have a 'key' and 'value' key.
430
+ #
431
+ # @return [Google::Apis::ComputeV1::Operation]
432
+ #
433
+ # @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
434
+ # @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
435
+ # @raise [Google::Apis::AuthorizationError] Authorization is required
436
+ def set_metadata_on_instance(name, data)
437
+ instance = @compute.get_instance(@options[:gce_project], @options[:gce_zone], name)
438
+ mdata = instance.metadata.dup
439
+ mdata.items = data
440
+ operation = @compute.set_instance_metadata(@options[:gce_project], @options[:gce_zone], name, mdata)
441
+ @compute.wait_zone_operation(@options[:gce_project], @options[:gce_zone], operation.name)
442
+ end
752
443
 
753
- # Create a Google Compute instance delete request
754
- #
755
- # @param [String] name The name of the instance to delete
756
- #
757
- # @return [Hash] A correctly formatted Google Compute request hash
758
- def instance_delete_req(name)
759
- { :api_method => @compute.instances.delete,
760
- :parameters => { 'project' => @options[:gce_project], 'zone' => DEFAULT_ZONE_NAME, 'instance' => name } }
761
- end
444
+ ##
445
+ # Delete a Google Compute instance
446
+ #
447
+ # @param [String] name The name of the instance to delete
448
+ #
449
+ # @return [Google::Apis::ComputeV1::Operation]
450
+ #
451
+ # @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
452
+ # @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
453
+ # @raise [Google::Apis::AuthorizationError] Authorization is required
454
+ def delete_instance(name)
455
+ operation = @compute.delete_instance(@options[:gce_project], default_zone, name)
456
+ @compute.wait_zone_operation(@options[:gce_project], @options[:gce_zone], operation.name)
457
+ end
762
458
 
763
- # Create a Google Compute instance create request
764
- #
765
- # @param [String] name The name of the instance to create
766
- #
767
- # @param [String] image The link to the image to use for instance create
768
- #
769
- # @param [String] machineType The link to the type of Google Compute
770
- # instance to create (indicates cpus and memory size)
771
- #
772
- # @param [String] disk The link to the disk to be used by the newly created
773
- # instance
774
- #
775
- # @return [Hash] A correctly formatted Google Compute request hash
776
- def instance_insert_req(name, image, machineType, disk)
777
- { :api_method => @compute.instances.insert,
778
- :parameters => { 'project' => @options[:gce_project], 'zone' => DEFAULT_ZONE_NAME },
779
- :body_object => { 'name' => name,
780
- 'image' => image,
781
- 'zone' => default_zone,
782
- 'machineType' => machineType,
783
- 'disks' => [ { 'source' => disk,
784
- 'type' => 'PERSISTENT', 'boot' => 'true'} ],
785
- 'networkInterfaces' => [ { 'accessConfigs' => [{ 'type' => 'ONE_TO_ONE_NAT', 'name' => 'External NAT' }],
786
- 'network' => default_network } ] } }
787
- end
459
+ ##
460
+ # Delete a Google Compute disk
461
+ #
462
+ # @param [String] name The name of the disk to delete
463
+ #
464
+ # @return [Google::Apis::ComputeV1::Operation]
465
+ #
466
+ # @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
467
+ # @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
468
+ # @raise [Google::Apis::AuthorizationError] Authorization is required
469
+ def delete_disk(name)
470
+ operation = @compute.delete_disk(@options[:gce_project], default_zone, name)
471
+ @compute.wait_zone_operation(@options[:gce_project], @options[:gce_zone], operation.name)
472
+ end
788
473
 
789
- # Create a Google Compute machineType get request
790
- #
791
- # @return [Hash] A correctly formatted Google Compute request hash
792
- def machineType_get_req()
793
- { :api_method => @compute.machine_types.get,
794
- :parameters => { 'project' => @options[:gce_project], 'zone' => DEFAULT_ZONE_NAME, 'machineType' => @options[:gce_machine_type] || DEFAULT_MACHINE_TYPE } }
795
- end
474
+ ##
475
+ # Delete a Google Compute firewall
476
+ #
477
+ # @param [String] name The name of the firewall to delete
478
+ #
479
+ # @return [Google::Apis::ComputeV1::Operation]
480
+ #
481
+ # @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
482
+ # @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
483
+ # @raise [Google::Apis::AuthorizationError] Authorization is required
484
+ def delete_firewall(name)
485
+ operation = @compute.delete_firewall(@options[:gce_project], name)
486
+ @compute.wait_global_operation(@options[:gce_project], operation.name)
796
487
  end
797
488
  end