beaker-google 0.3.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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