beaker-google 1.0.0 → 1.2.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.
- checksums.yaml +4 -4
- data/.github/dependabot.yml +9 -0
- data/.github/workflows/ci.yml +24 -14
- data/.github/workflows/codeql-analysis.yml +4 -4
- data/.github/workflows/release.yml +2 -2
- data/.gitignore +1 -0
- data/.rubocop.yml +2 -518
- data/.simplecov +2 -0
- data/CHANGELOG.md +42 -2
- data/Gemfile +5 -2
- data/README.md +14 -3
- data/Rakefile +16 -6
- data/beaker-google.gemspec +21 -20
- data/bin/beaker-google +1 -0
- data/lib/beaker/hypervisor/google.rb +5 -1
- data/lib/beaker/hypervisor/google_compute.rb +67 -33
- data/lib/beaker/hypervisor/google_compute_helper.rb +601 -436
- data/lib/beaker-google/version.rb +3 -1
- metadata +54 -34
@@ -10,479 +10,644 @@ require 'ostruct'
|
|
10
10
|
# TODO: Figure out what to do about the timeout thing
|
11
11
|
# TODO: Implement Google::Apis::RequestOptions on all calls (In lib/google/apis/options.rb)
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
class
|
16
|
-
|
13
|
+
module Beaker
|
14
|
+
# Beaker helper module for doing API level Google Compute Engine interaction.
|
15
|
+
class GoogleComputeHelper
|
16
|
+
class GoogleComputeError < StandardError
|
17
|
+
end
|
17
18
|
|
18
|
-
|
19
|
+
SLEEPWAIT = 5
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
21
|
+
AUTH_URL = 'https://www.googleapis.com/auth/compute'
|
22
|
+
API_VERSION = 'v1'
|
23
|
+
BASE_URL = "https://www.googleapis.com/compute/#{API_VERSION}/projects/"
|
24
|
+
DEFAULT_ZONE_NAME = 'us-central1-a'
|
25
|
+
DEFAULT_MACHINE_TYPE = 'e2-standard-4'
|
26
|
+
DEFAULT_NETWORK_NAME = 'default'
|
26
27
|
|
27
|
-
|
28
|
-
Google::Apis::ComputeV1::AUTH_COMPUTE,
|
29
|
-
Google::Apis::OsloginV1::AUTH_CLOUD_PLATFORM_READ_ONLY,
|
30
|
-
].freeze
|
28
|
+
VALID_PROTOS = %w[tcp udp icmp esp ah ipip sctp].freeze
|
31
29
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
@options = options
|
37
|
-
@logger = options[:logger]
|
30
|
+
GCP_AUTH_SCOPE = [
|
31
|
+
::Google::Apis::ComputeV1::AUTH_COMPUTE,
|
32
|
+
::Google::Apis::OsloginV1::AUTH_CLOUD_PLATFORM_READ_ONLY,
|
33
|
+
].freeze
|
38
34
|
|
39
|
-
|
35
|
+
##
|
36
|
+
# Create a new instance of the Google Compute Engine helper object
|
37
|
+
#
|
38
|
+
def initialize(options)
|
39
|
+
@options = options
|
40
|
+
@logger = options[:logger]
|
40
41
|
|
41
|
-
|
42
|
-
# ::Google::Apis.logger.level = ::Logger::DEBUG
|
43
|
-
# ::Google::Apis.logger.level = ::Logger::WARN
|
42
|
+
client(Beaker::Version::STRING)
|
44
43
|
|
45
|
-
|
44
|
+
# ::Google::Apis.logger = ::Logger.new(::STDERR)
|
45
|
+
# ::Google::Apis.logger.level = ::Logger::DEBUG
|
46
|
+
# ::Google::Apis.logger.level = ::Logger::WARN
|
46
47
|
|
47
|
-
|
48
|
-
@options[:gce_network] = ENV.fetch('BEAKER_gce_network', DEFAULT_NETWORK_NAME)
|
49
|
-
@options[:gce_subnetwork] = ENV.fetch('BEAKER_gce_subnetwork', nil)
|
48
|
+
@options[:gce_project] = ENV['BEAKER_gce_project'] if ENV['BEAKER_gce_project']
|
50
49
|
|
51
|
-
|
50
|
+
@options[:gce_zone] = ENV.fetch('BEAKER_gce_zone', DEFAULT_ZONE_NAME)
|
51
|
+
@options[:gce_network] = ENV.fetch('BEAKER_gce_network', DEFAULT_NETWORK_NAME)
|
52
|
+
@options[:gce_subnetwork] = ENV.fetch('BEAKER_gce_subnetwork', nil)
|
52
53
|
|
53
|
-
|
54
|
-
|
55
|
-
|
54
|
+
@configure_ports = ENV.fetch('BEAKER_gce_ports', '').strip
|
55
|
+
# Split the ports based on commas, removing any empty values
|
56
|
+
@options[:gce_ports] = @configure_ports.split(/\s*?,\s*/).reject(&:empty?)
|
56
57
|
|
57
|
-
|
58
|
-
@cloudoslogin = Google::Apis::OsloginV1::CloudOSLoginService.new
|
59
|
-
@cloudoslogin.authorization = authorizer
|
60
|
-
end
|
58
|
+
raise 'You must specify a gce_project for Google Compute Engine instances!' unless @options[:gce_project]
|
61
59
|
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
#
|
66
|
-
# @return [String] The name of the zone
|
67
|
-
def default_zone
|
68
|
-
@options[:gce_zone]
|
69
|
-
end
|
60
|
+
@options[:gce_ports].each do |port|
|
61
|
+
parts = port.split('/', 2)
|
62
|
+
raise "Invalid format for port #{port}. Should be 'port/proto'" unless parts.length == 2
|
70
63
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
@options[:gce_zone].split('-')[0..1].join('-')
|
80
|
-
end
|
64
|
+
proto = parts[1]
|
65
|
+
unless VALID_PROTOS.include? proto
|
66
|
+
raise "Invalid value '#{proto}' for protocol in '#{port}'. Must be one of '#{VALID_PROTOS.join("', '")}'"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
authorizer = authenticate
|
70
|
+
@compute = ::Google::Apis::ComputeV1::ComputeService.new
|
71
|
+
@compute.authorization = authorizer
|
81
72
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
# @return [String] The short name of the VPC network
|
87
|
-
def default_network
|
88
|
-
@options[:gce_network]
|
89
|
-
end
|
73
|
+
# Find the appropriate username to log into created instances
|
74
|
+
@cloudoslogin = ::Google::Apis::OsloginV1::CloudOSLoginService.new
|
75
|
+
@cloudoslogin.authorization = authorizer
|
76
|
+
end
|
90
77
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
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'
|
78
|
+
##
|
79
|
+
# Determines the default Google Compute zone based upon options and
|
80
|
+
# defaults
|
81
|
+
#
|
82
|
+
# @return [String] The name of the zone
|
83
|
+
def default_zone
|
84
|
+
@options[:gce_zone]
|
111
85
|
end
|
112
|
-
userid = "users/#{userid}" unless userid.start_with? 'users/'
|
113
|
-
@cloudoslogin.get_user_login_profile(userid).posix_accounts[0].username
|
114
|
-
end
|
115
86
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
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
|
87
|
+
##
|
88
|
+
# Get the region name from the provided zone.
|
89
|
+
#
|
90
|
+
# Assume that the region is the name of the zone without
|
91
|
+
# the final - and zone letter
|
92
|
+
#
|
93
|
+
# @return [String] The name of the region
|
94
|
+
def default_region
|
95
|
+
@options[:gce_zone].split('-')[0..1].join('-')
|
96
|
+
end
|
132
97
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
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']
|
98
|
+
##
|
99
|
+
# Determines the default Google Compute network based upon defaults and
|
100
|
+
# options
|
101
|
+
#
|
102
|
+
# @return [String] The short name of the VPC network
|
103
|
+
def default_network
|
104
|
+
@options[:gce_network]
|
151
105
|
end
|
152
|
-
@options[:gce_subnetwork]
|
153
|
-
end
|
154
106
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
107
|
+
##
|
108
|
+
# Find the username for ssh to use with this connection
|
109
|
+
#
|
110
|
+
# @return [String] The username for ssh
|
111
|
+
#
|
112
|
+
# @raise [Google::Auth::IDTokens::KeySourceError] if the key source failed to obtain public keys
|
113
|
+
# @raise [Google::Auth::IDTokens::VerificationError] if the token verification failed.
|
114
|
+
# Additional data may be available in the error subclass and message.
|
115
|
+
def ssh_username
|
116
|
+
authorizer = @compute.authorization
|
117
|
+
# This is a bit of a hack based on what I found in a user (default application credentials)
|
118
|
+
# and a service account. There might be a better way of doing this.
|
119
|
+
case authorizer.class.to_s
|
120
|
+
when 'Google::Auth::UserRefreshCredentials'
|
121
|
+
authorizer.refresh!
|
122
|
+
userid = ::Google::Auth::IDTokens.verify_oidc(authorizer.id_token)['email']
|
123
|
+
when 'Google::Auth::ServiceAccountCredentials'
|
124
|
+
userid = authorizer.issuer
|
125
|
+
else
|
126
|
+
raise 'Unknown type of credential'
|
127
|
+
end
|
128
|
+
userid = "users/#{userid}" unless userid.start_with? 'users/'
|
129
|
+
@cloudoslogin.get_user_login_profile(userid).posix_accounts[0].username
|
130
|
+
end
|
163
131
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
132
|
+
##
|
133
|
+
# Infer the network that a given subnetwork is attached to
|
134
|
+
#
|
135
|
+
# @param [String] subnetwork_name The name of the subnetwork
|
136
|
+
#
|
137
|
+
# @return [String] The short name of the network
|
138
|
+
#
|
139
|
+
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
140
|
+
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
141
|
+
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
142
|
+
def default_network_from_subnet(subnetwork_name)
|
143
|
+
subnetwork = @compute.get_subnetwork(@options[:gce_project], default_region, subnetwork_name)
|
144
|
+
m = %r{.*/networks/(?<network_name>.*)\Z}.match subnetwork.network
|
145
|
+
nil if m.nil?
|
146
|
+
m['network_name']
|
179
147
|
end
|
180
|
-
end
|
181
148
|
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
149
|
+
##
|
150
|
+
# Determine the subnetwork to use for instances
|
151
|
+
#
|
152
|
+
# If the network is the 'default' network, get the 'default' subnetwork for the region.
|
153
|
+
# If no subnet is provided by the user, pick the first one out of the user-provided network
|
154
|
+
#
|
155
|
+
# @return [String] The name of the subnetwork that should be attached to the instances
|
156
|
+
def default_subnetwork
|
157
|
+
network_name = @options[:gce_network]
|
158
|
+
if network_name == 'default'
|
159
|
+
@options[:gce_subnetwork] ||= @compute.get_subnetwork(@options[:gce_project], default_region, 'default').name
|
160
|
+
elsif @options[:gce_subnetwork].nil?
|
161
|
+
# No subnet set, get the first subnet in our current region for the network
|
162
|
+
subnetwork = @compute.get_network(@options[:gce_project], network_name).subnetworks[0]
|
163
|
+
m = %r{.*/subnetworks/(?<subnetwork_name>.*)\Z}.match subnetwork
|
164
|
+
raise "Unable to find a subnetwork in provided network #{network_name}" if m.nil?
|
165
|
+
|
166
|
+
@options[:gce_subnetwork] = m['subnetwork_name']
|
167
|
+
end
|
168
|
+
@options[:gce_subnetwork]
|
169
|
+
end
|
198
170
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
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
|
171
|
+
##
|
172
|
+
# Set the user-agent information for the application.
|
173
|
+
#
|
174
|
+
# @param version The version number of Beaker currently running
|
175
|
+
def client(version)
|
176
|
+
::Google::Apis::ClientOptions.default.application_name = 'beaker-google'
|
177
|
+
::Google::Apis::ClientOptions.default.application_version = version
|
178
|
+
end
|
214
179
|
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
180
|
+
##
|
181
|
+
# Creates an authentication object to use in the various Google APIs
|
182
|
+
#
|
183
|
+
# This method currently supports using application credentials via the
|
184
|
+
# GOOGLE_APPLICATION_CREDENTIALS environment variable, and application default
|
185
|
+
# credentials.
|
186
|
+
#
|
187
|
+
# @return [Google::Auth::UserRefreshCredentials|Google::Auth::ServiceAccountCredentials]
|
188
|
+
# Authorization object to pass to Google APIs
|
189
|
+
def authenticate
|
190
|
+
if ENV['GOOGLE_APPLICATION_CREDENTIALS']
|
191
|
+
::Google::Auth::ServiceAccountCredentials.from_env(scope: GCP_AUTH_SCOPE)
|
192
|
+
else
|
193
|
+
# Fall back to default application auth
|
194
|
+
::Google::Auth.get_application_default(GCP_AUTH_SCOPE)
|
195
|
+
end
|
196
|
+
end
|
229
197
|
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
198
|
+
##
|
199
|
+
# Find the correct image object for a given project and name
|
200
|
+
#
|
201
|
+
# @param [String] image_project The project that owns the requested image
|
202
|
+
#
|
203
|
+
# @param [String] name The name of the image in the project. This must
|
204
|
+
# be the exact name of the image
|
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_image(project, name)
|
212
|
+
@compute.get_image(project, name)
|
213
|
+
end
|
241
214
|
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
@
|
252
|
-
|
215
|
+
##
|
216
|
+
# Find the latest non-deprecated image in the given project and family
|
217
|
+
#
|
218
|
+
# @param [String] image_project The project that owns the requested image
|
219
|
+
#
|
220
|
+
# @param [String] family The name of the image family
|
221
|
+
#
|
222
|
+
# @return [Google::Apis::ComputeV1::Image]
|
223
|
+
#
|
224
|
+
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
225
|
+
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
226
|
+
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
227
|
+
def get_latest_image_from_family(image_project, family)
|
228
|
+
@compute.get_image_from_family(image_project, family)
|
229
|
+
end
|
253
230
|
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
end
|
231
|
+
##
|
232
|
+
# Determines the Google Compute machineType object based upon the selected
|
233
|
+
# gce_machine_type option
|
234
|
+
#
|
235
|
+
# @param [String] type_name The name of the type to get
|
236
|
+
#
|
237
|
+
# @return [Google::Apis::ComputeV1::MachineType]
|
238
|
+
#
|
239
|
+
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
240
|
+
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
241
|
+
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
242
|
+
def get_machine_type(type_name = DEFAULT_MACHINE_TYPE)
|
243
|
+
@compute.get_machine_type(@options[:gce_project], default_zone, type_name)
|
244
|
+
end
|
269
245
|
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
end
|
246
|
+
##
|
247
|
+
# Determines the Google Compute network object in use for the current connection
|
248
|
+
#
|
249
|
+
# @return [Google::Apis::ComputeV1::Network]
|
250
|
+
#
|
251
|
+
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
252
|
+
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
253
|
+
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
254
|
+
def get_network(network_name = default_network)
|
255
|
+
@compute.get_network(@options[:gce_project], network_name)
|
256
|
+
end
|
282
257
|
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
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
|
258
|
+
##
|
259
|
+
# Determines a list of existing Google Compute instances
|
260
|
+
#
|
261
|
+
# @return [Array[Google::Apis::ComputeV1::Instance]]
|
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_instances
|
267
|
+
@compute.list_instances(@options[:gce_project], default_zone).items
|
268
|
+
end
|
310
269
|
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
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
|
270
|
+
##
|
271
|
+
# Determines a list of existing Google Compute disks
|
272
|
+
#
|
273
|
+
# @param [Integer] start The time when we started code execution, it is
|
274
|
+
# compared to Time.now to determine how many further code execution
|
275
|
+
# attempts remain
|
276
|
+
#
|
277
|
+
# @return [Array[Google::Apis::ComputeV1::Disk]]
|
278
|
+
#
|
279
|
+
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
280
|
+
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
281
|
+
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
282
|
+
def list_disks
|
283
|
+
@compute.list_disks(@options[:gce_project], default_zone).items
|
284
|
+
end
|
330
285
|
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
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
|
286
|
+
##
|
287
|
+
# Determines a list of existing Google Compute firewalls
|
288
|
+
#
|
289
|
+
# @return [Array[Google::Apis::ComputeV1::Firewall]]
|
290
|
+
#
|
291
|
+
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
292
|
+
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
293
|
+
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
294
|
+
def list_firewalls
|
295
|
+
@compute.list_firewalls(@options[:gce_project],
|
296
|
+
filter: 'name != default-allow-internal AND name != default-ssh').items
|
297
|
+
end
|
353
298
|
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
#
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
405
|
-
|
299
|
+
##
|
300
|
+
# Create a Google Compute firewall
|
301
|
+
#
|
302
|
+
# @param [String] name The name of the firewall to create
|
303
|
+
#
|
304
|
+
# @param [::Google::Apis::ComputeV1::Network] network The Google Compute networkin which to create
|
305
|
+
# the firewall
|
306
|
+
#
|
307
|
+
# @param [Array<String>] allow List of ports to allow through the firewall. One of 'allow' or 'deny' must be
|
308
|
+
# specified, but not both.
|
309
|
+
#
|
310
|
+
# @param [Array<String>] deny List of ports to deny through the firewall. One of 'allow' or 'deny' must be
|
311
|
+
# specified, but not both.
|
312
|
+
#
|
313
|
+
# @param [Array<String>] source_ranges List of ranges in CIDR format to accept through the firewall. If neither
|
314
|
+
# 'source_ranges' or 'source_tags' is specified, GCP adds a default 'source_range' of '0.0.0.0/0' (allow all)
|
315
|
+
#
|
316
|
+
# @param [Array<String>] source_tags List of network tags to accept through the firewall. If neither 'source_ranges'
|
317
|
+
# or 'source_tags' is specified, GCP adds a default 'source_range' of '0.0.0.0/0' (allow all)
|
318
|
+
#
|
319
|
+
# @param [Array<String>] target_ranges List of ranges in CIDR format to apply this firewall. If neither
|
320
|
+
# 'target_ranges' or 'target_tags' is specified, the firewall applies to all hosts in the VPC
|
321
|
+
#
|
322
|
+
# @param [Array<String>] target_tags List of network tags to apply this firewall. If neither 'target_ranges' or
|
323
|
+
# 'target_tags' is specified, the firewall applies to all hosts in the VPC
|
324
|
+
#
|
325
|
+
# @return [Google::Apis::ComputeV1::Operation]
|
326
|
+
#
|
327
|
+
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
328
|
+
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
329
|
+
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
330
|
+
def create_firewall(name, network, allow: [], deny: [], source_ranges: [], source_tags: [], target_ranges: [],
|
331
|
+
target_tags: [])
|
332
|
+
allowed = []
|
333
|
+
allow.each do |port|
|
334
|
+
parts = port.split('/', 2)
|
335
|
+
allowed << if parts[1] == 'tcp' || parts[1] == 'udp' || parts[1] == 'sctp'
|
336
|
+
::Google::Apis::ComputeV1::Firewall::Allowed.new(ip_protocol: parts[1], ports: [parts[0]])
|
337
|
+
else
|
338
|
+
::Google::Apis::ComputeV1::Firewall::Allowed.new(ip_protocol: parts[1])
|
339
|
+
end
|
340
|
+
end
|
341
|
+
denied = []
|
342
|
+
deny.each do |port|
|
343
|
+
parts = port.split('/', 2)
|
344
|
+
denied << if parts[1] == 'tcp' || parts[1] == 'udp' || parts[1] == 'sctp'
|
345
|
+
::Google::Apis::ComputeV1::Firewall::Denied.new(ip_protocol: parts[1], ports: [parts[0]])
|
346
|
+
else
|
347
|
+
::Google::Apis::ComputeV1::Firewall::Denied.new(ip_protocol: parts[1])
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
firewall_object = ::Google::Apis::ComputeV1::Firewall.new(
|
352
|
+
name: name,
|
353
|
+
direction: 'INGRESS',
|
354
|
+
network: network.self_link,
|
355
|
+
allowed: allowed,
|
356
|
+
denied: denied,
|
357
|
+
source_ranges: source_ranges,
|
358
|
+
source_tags: source_tags,
|
359
|
+
target_ranges: target_ranges,
|
360
|
+
target_tags: target_tags,
|
361
|
+
)
|
362
|
+
operation = @compute.insert_firewall(@options[:gce_project], firewall_object)
|
363
|
+
@compute.wait_global_operation(@options[:gce_project], operation.name)
|
364
|
+
end
|
406
365
|
|
407
|
-
|
408
|
-
|
409
|
-
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
366
|
+
##
|
367
|
+
# Get the named firewall
|
368
|
+
#
|
369
|
+
# @param [String] name The name of the firewall
|
370
|
+
#
|
371
|
+
# @return [Google::Apis::ComputeV1::Firewall]
|
372
|
+
#
|
373
|
+
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
374
|
+
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
375
|
+
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
376
|
+
def get_firewall(name)
|
377
|
+
@compute.get_firewall(@options[:gce_project], name)
|
378
|
+
end
|
420
379
|
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
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
|
380
|
+
##
|
381
|
+
# Add a source range to the firewall.
|
382
|
+
#
|
383
|
+
# @param [String] name The name of the firewall
|
384
|
+
#
|
385
|
+
# @param [String] range The IP range in CIDR format to add to the firewall
|
386
|
+
#
|
387
|
+
# @return [Google::Apis::ComputeV1::Operation]
|
388
|
+
#
|
389
|
+
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
390
|
+
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
391
|
+
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
392
|
+
def add_firewall_source_range(name, range)
|
393
|
+
firewall = get_firewall(name)
|
394
|
+
firewall.source_ranges = [] if firewall.source_ranges.nil?
|
395
|
+
firewall.source_ranges << range
|
396
|
+
operation = @compute.patch_firewall(@options[:gce_project], name, firewall)
|
397
|
+
@compute.wait_global_operation(@options[:gce_project], operation.name)
|
398
|
+
end
|
443
399
|
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
450
|
-
|
451
|
-
|
452
|
-
|
453
|
-
|
454
|
-
|
455
|
-
|
456
|
-
@
|
457
|
-
|
400
|
+
##
|
401
|
+
# Add an allowed port to the firewall
|
402
|
+
#
|
403
|
+
# @param [String] name The name of the firewall
|
404
|
+
#
|
405
|
+
# @param [String] port The port number to open on the firewall
|
406
|
+
#
|
407
|
+
# @param [String] proto The protocol of the port. This should be 'tcp' or 'udp'
|
408
|
+
#
|
409
|
+
# @return [Google::Apis::ComputeV1::Operation]
|
410
|
+
#
|
411
|
+
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
412
|
+
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
413
|
+
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
414
|
+
def add_firewall_port(name, port, proto)
|
415
|
+
firewall = get_firewall(name)
|
416
|
+
firewall.allowed = [] if firewall.allowed.nil?
|
417
|
+
firewall.allowed << ::Google::Apis::ComputeV1::Firewall::Allowed.new(ip_protocol: proto, ports: [port])
|
418
|
+
operation = @compute.patch_firewall(@options[:gce_project], name, firewall)
|
419
|
+
@compute.wait_global_operation(@options[:gce_project], operation.name)
|
420
|
+
end
|
458
421
|
|
459
|
-
|
460
|
-
|
461
|
-
|
462
|
-
|
463
|
-
|
464
|
-
|
465
|
-
|
466
|
-
|
467
|
-
|
468
|
-
|
469
|
-
|
470
|
-
|
471
|
-
|
472
|
-
|
422
|
+
##
|
423
|
+
# Add a taget_tag to an existing firewall
|
424
|
+
#
|
425
|
+
# @param [String] the name of the firewall to update
|
426
|
+
#
|
427
|
+
# @param [String] tag The target tag to add to the firewall
|
428
|
+
#
|
429
|
+
# @return [Google::Apis::ComputeV1::Operation]
|
430
|
+
#
|
431
|
+
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
432
|
+
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
433
|
+
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
434
|
+
def add_firewall_target_tag(name, tag)
|
435
|
+
firewall = @compute.get_firewall(@options[:gce_project], name)
|
436
|
+
firewall.target_tags = [] if firewall.target_tags.nil?
|
437
|
+
firewall.target_tags << tag
|
438
|
+
operation = @compute.patch_firewall(@options[:gce_project], name, firewall)
|
439
|
+
@compute.wait_global_operation(@options[:gce_project], operation.name)
|
440
|
+
end
|
441
|
+
|
442
|
+
##
|
443
|
+
# Add a source_tag to an existing firewall
|
444
|
+
#
|
445
|
+
# @param [String] the name of the firewall to update
|
446
|
+
#
|
447
|
+
# @param [String] tag The source tag to add to the firewall
|
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 add_firewall_source_tag(name, tag)
|
455
|
+
firewall = @compute.get_firewall(@options[:gce_project], name)
|
456
|
+
firewall.source_tags = [] if firewall.source_tags.nil?
|
457
|
+
firewall.source_tags << tag
|
458
|
+
operation = @compute.patch_firewall(@options[:gce_project], name, firewall)
|
459
|
+
@compute.wait_global_operation(@options[:gce_project], operation.name)
|
460
|
+
end
|
473
461
|
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
479
|
-
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
@
|
462
|
+
##
|
463
|
+
# Create a Google Compute disk
|
464
|
+
#
|
465
|
+
# @param [String] name The name of the disk to create
|
466
|
+
#
|
467
|
+
# @param [String] img The existing disk image to clone for this image
|
468
|
+
# or nil to create a blank disk
|
469
|
+
#
|
470
|
+
# @return [Google::Apis::ComputeV1::Operation]
|
471
|
+
#
|
472
|
+
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
473
|
+
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
474
|
+
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
475
|
+
def create_disk(name, size, img = nil)
|
476
|
+
new_disk = ::Google::Apis::ComputeV1::Disk.new(
|
477
|
+
name: name,
|
478
|
+
size_gb: size,
|
479
|
+
source_image: img,
|
480
|
+
)
|
481
|
+
operation = @compute.insert_disk(@options[:gce_project], @options[:gce_zone], new_disk)
|
482
|
+
@compute.wait_zone_operation(@options[:gce_project], @options[:gce_zone], operation.name)
|
483
|
+
end
|
484
|
+
|
485
|
+
##
|
486
|
+
# Create a Google Compute instance
|
487
|
+
#
|
488
|
+
# @param [String] name The name of the instance to create
|
489
|
+
#
|
490
|
+
# @param [Google::Apis::ComputeV1::Image] img The Google Compute image to use for instance creation
|
491
|
+
#
|
492
|
+
# @param [Google::Apis::ComputeV1::MachineType] machine_type The Google Compute Machine Type
|
493
|
+
#
|
494
|
+
# @param [Integer] disk_size The size of the boot disk for the new instance. Must be equal to or
|
495
|
+
# greater than the image disk's size
|
496
|
+
#
|
497
|
+
# @param [String] hostname The custom hostname to set in the OS of the instance
|
498
|
+
#
|
499
|
+
# @return [Google::Apis::ComputeV1::Operation]
|
500
|
+
#
|
501
|
+
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
502
|
+
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
503
|
+
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
504
|
+
def create_instance(name, img, machine_type, disk_size, hostname)
|
505
|
+
initialize_params = ::Google::Apis::ComputeV1::AttachedDiskInitializeParams.new(
|
506
|
+
disk_size_gb: disk_size,
|
507
|
+
source_image: img.self_link,
|
508
|
+
)
|
509
|
+
disk_params = ::Google::Apis::ComputeV1::AttachedDisk.new(
|
510
|
+
boot: true,
|
511
|
+
auto_delete: true,
|
512
|
+
initialize_params: initialize_params,
|
513
|
+
)
|
514
|
+
# attached_network = ::Google::Apis::ComputeV1::networkInterfaces.new()
|
515
|
+
tags = ::Google::Apis::ComputeV1::Tags.new(
|
516
|
+
items: [name],
|
517
|
+
)
|
518
|
+
network_interface = ::Google::Apis::ComputeV1::NetworkInterface.new(
|
519
|
+
network: get_network(default_network).self_link,
|
520
|
+
subnetwork: @compute.get_subnetwork(@options[:gce_project], default_region, default_subnetwork).self_link,
|
521
|
+
# Create an AccessConfig to add a NAT IP to the host.
|
522
|
+
# TODO: Make this configurable
|
523
|
+
access_configs: [
|
524
|
+
::Google::Apis::ComputeV1::AccessConfig.new(
|
525
|
+
network_tier: 'STANDARD',
|
526
|
+
),
|
527
|
+
],
|
528
|
+
)
|
529
|
+
|
530
|
+
instance_opts = {
|
531
|
+
machine_type: machine_type.self_link,
|
532
|
+
name: name,
|
533
|
+
disks: [disk_params],
|
534
|
+
network_interfaces: [network_interface],
|
535
|
+
tags: tags,
|
536
|
+
}
|
537
|
+
|
538
|
+
# use custom hostname if specified
|
539
|
+
if hostname && ENV.fetch('BEAKER_set_gce_hostname', false)
|
540
|
+
# The google api requires an FQDN for the custom hostname
|
541
|
+
valid_hostname = hostname.include?('.') ? hostname : "#{hostname}.beaker.test"
|
542
|
+
instance_opts[:hostname] = valid_hostname
|
543
|
+
end
|
544
|
+
|
545
|
+
new_instance = ::Google::Apis::ComputeV1::Instance.new(**instance_opts)
|
546
|
+
|
547
|
+
operation = @compute.insert_instance(@options[:gce_project], @options[:gce_zone], new_instance)
|
548
|
+
@compute.wait_zone_operation(@options[:gce_project], @options[:gce_zone], operation.name)
|
549
|
+
end
|
550
|
+
|
551
|
+
##
|
552
|
+
# Get the named instace from Google Compute Image
|
553
|
+
#
|
554
|
+
# @param [String] name The name of the instance
|
555
|
+
#
|
556
|
+
# @return [Google::Apis::ComputeV1::Instance]
|
557
|
+
#
|
558
|
+
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
559
|
+
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
560
|
+
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
561
|
+
def get_instance(name)
|
562
|
+
@compute.get_instance(@options[:gce_project], @options[:gce_zone], name)
|
563
|
+
end
|
564
|
+
|
565
|
+
##
|
566
|
+
# Add a tag to a Google Compute Instance
|
567
|
+
#
|
568
|
+
# @param [String] name The name of the instance
|
569
|
+
#
|
570
|
+
# @param [String] tag The tag to add to the instance
|
571
|
+
#
|
572
|
+
# @return [Google::Apis::ComputeV1::Operation]
|
573
|
+
#
|
574
|
+
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
575
|
+
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
576
|
+
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
577
|
+
def add_instance_tag(name, tag)
|
578
|
+
instance = get_instance(name)
|
579
|
+
tags = instance.tags
|
580
|
+
tags.items << tag
|
581
|
+
operation = @compute.set_instance_tags(@options[:gce_project], @options[:gce_zone], name, tags)
|
582
|
+
@compute.wait_zone_operation(@options[:gce_project], @options[:gce_zone], operation.name)
|
583
|
+
end
|
584
|
+
|
585
|
+
##
|
586
|
+
# Set key/value metadata pairs to a Google Compute instance
|
587
|
+
#
|
588
|
+
# This function replaces any existing items in the metadata hash!
|
589
|
+
#
|
590
|
+
# @param [String] name The name of the instance to set metadata
|
591
|
+
#
|
592
|
+
# @param [String] data An array of hashes to set ass metadata. Each array
|
593
|
+
# item should have a 'key' and 'value' key.
|
594
|
+
#
|
595
|
+
# @return [Google::Apis::ComputeV1::Operation]
|
596
|
+
#
|
597
|
+
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
598
|
+
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
599
|
+
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
600
|
+
def set_metadata_on_instance(name, data)
|
601
|
+
instance = @compute.get_instance(@options[:gce_project], @options[:gce_zone], name)
|
602
|
+
mdata = instance.metadata.dup
|
603
|
+
mdata.items = data
|
604
|
+
operation = @compute.set_instance_metadata(@options[:gce_project], @options[:gce_zone], name, mdata)
|
605
|
+
@compute.wait_zone_operation(@options[:gce_project], @options[:gce_zone], operation.name)
|
606
|
+
end
|
607
|
+
|
608
|
+
##
|
609
|
+
# Delete a Google Compute instance
|
610
|
+
#
|
611
|
+
# @param [String] name The name of the instance to delete
|
612
|
+
#
|
613
|
+
# @return [Google::Apis::ComputeV1::Operation]
|
614
|
+
#
|
615
|
+
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
616
|
+
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
617
|
+
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
618
|
+
def delete_instance(name)
|
619
|
+
operation = @compute.delete_instance(@options[:gce_project], default_zone, name)
|
620
|
+
@compute.wait_zone_operation(@options[:gce_project], @options[:gce_zone], operation.name)
|
621
|
+
end
|
622
|
+
|
623
|
+
##
|
624
|
+
# Delete a Google Compute disk
|
625
|
+
#
|
626
|
+
# @param [String] name The name of the disk to delete
|
627
|
+
#
|
628
|
+
# @return [Google::Apis::ComputeV1::Operation]
|
629
|
+
#
|
630
|
+
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
631
|
+
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
632
|
+
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
633
|
+
def delete_disk(name)
|
634
|
+
operation = @compute.delete_disk(@options[:gce_project], default_zone, name)
|
635
|
+
@compute.wait_zone_operation(@options[:gce_project], @options[:gce_zone], operation.name)
|
636
|
+
end
|
637
|
+
|
638
|
+
##
|
639
|
+
# Delete a Google Compute firewall
|
640
|
+
#
|
641
|
+
# @param [String] name The name of the firewall to delete
|
642
|
+
#
|
643
|
+
# @return [Google::Apis::ComputeV1::Operation]
|
644
|
+
#
|
645
|
+
# @raise [Google::Apis::ServerError] An error occurred on the server and the request can be retried
|
646
|
+
# @raise [Google::Apis::ClientError] The request is invalid and should not be retried without modification
|
647
|
+
# @raise [Google::Apis::AuthorizationError] Authorization is required
|
648
|
+
def delete_firewall(name)
|
649
|
+
operation = @compute.delete_firewall(@options[:gce_project], name)
|
650
|
+
@compute.wait_global_operation(@options[:gce_project], operation.name)
|
651
|
+
end
|
487
652
|
end
|
488
653
|
end
|