vagrant-google 2.5.0 → 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,72 @@
1
+ # Copyright 2015 Google Inc. All Rights Reserved.
2
+ #
3
+ # Licensed under the Apache License, Version 2.0 (the "License");
4
+ # you may not use this file except in compliance with the License.
5
+ # You may obtain a copy of the License at
6
+ #
7
+ # http://www.apache.org/licenses/LICENSE-2.0
8
+ #
9
+ # Unless required by applicable law or agreed to in writing, software
10
+ # distributed under the License is distributed on an "AS IS" BASIS,
11
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ # See the License for the specific language governing permissions and
13
+ # limitations under the License.
14
+ #
15
+ # Changes:
16
+ # April 2019: Modified example found here:
17
+ # https://github.com/GoogleCloudPlatform/compute-image-windows/blob/master/examples/windows_auth_python_sample.py
18
+ # to enable WinRM with vagrant.
19
+
20
+ module VagrantPlugins
21
+ module Google
22
+ module Action
23
+ # Sets up a temporary WinRM password using Google's method for
24
+ # establishing a new password over encrypted channels.
25
+ class SetupWinrmPassword
26
+ def initialize(app, env)
27
+ @app = app
28
+ @logger = Log4r::Logger.new("vagrant_google::action::setup_winrm_password")
29
+ end
30
+
31
+ def setup_password(env, instance, zone, user)
32
+ # Setup
33
+ compute = env[:google_compute]
34
+ server = compute.servers.get(instance, zone)
35
+ password = server.reset_windows_password(user)
36
+
37
+ env[:ui].info("Temp Password: #{password}")
38
+
39
+ password
40
+ end
41
+
42
+ def call(env)
43
+ # Get the configs
44
+ zone = env[:machine].provider_config.zone
45
+ zone_config = env[:machine].provider_config.get_zone_config(zone)
46
+
47
+ instance = zone_config.name
48
+ user = env[:machine].config.winrm.username
49
+ pass = env[:machine].config.winrm.password
50
+
51
+ # Get Temporary Password, set WinRM password
52
+ temp_pass = setup_password(env, instance, zone, user)
53
+ env[:machine].config.winrm.password = temp_pass
54
+
55
+ # Wait for WinRM To be Ready
56
+ env[:ui].info("Waiting for WinRM To be ready")
57
+ env[:machine].communicate.wait_for_ready(60)
58
+
59
+ # Use WinRM to Change Password to one in Vagrantfile
60
+ env[:ui].info("Changing password from temporary to winrm password")
61
+ winrmcomm = VagrantPlugins::CommunicatorWinRM::Communicator.new(env[:machine])
62
+ cmd = "net user #{user} #{pass}"
63
+ opts = { elevated: true }
64
+ winrmcomm.test(cmd, opts)
65
+
66
+ # Update WinRM password to reflect updated one
67
+ env[:machine].config.winrm.password = pass
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -65,9 +65,9 @@ module VagrantPlugins
65
65
  @logger.info("Time to instance ready: #{env[:metrics]["instance_ready_time"]}")
66
66
 
67
67
  unless env[:interrupted]
68
- env[:metrics]["instance_ssh_time"] = Util::Timer.time do
69
- # Wait for SSH to be ready.
70
- env[:ui].info(I18n.t("vagrant_google.waiting_for_ssh"))
68
+ env[:metrics]["instance_comm_time"] = Util::Timer.time do
69
+ # Wait for Comms to be ready.
70
+ env[:ui].info(I18n.t("vagrant_google.waiting_for_comm"))
71
71
  while true
72
72
  # If we're interrupted then just back out
73
73
  break if env[:interrupted]
@@ -76,7 +76,7 @@ module VagrantPlugins
76
76
  end
77
77
  end
78
78
 
79
- @logger.info("Time for SSH ready: #{env[:metrics]["instance_ssh_time"]}")
79
+ @logger.info("Time for Comms ready: #{env[:metrics]["instance_comm_time"]}")
80
80
 
81
81
  # Ready and booted!
82
82
  env[:ui].info(I18n.t("vagrant_google.ready"))
@@ -178,38 +178,68 @@ module VagrantPlugins
178
178
  # @return [Array<Hash>]
179
179
  attr_accessor :additional_disks
180
180
 
181
+ # (Optional - Override default WinRM setup before for Public Windows images)
182
+ #
183
+ # @return [Boolean]
184
+ attr_accessor :setup_winrm_password
185
+
186
+ # Accelerators
187
+ #
188
+ # @return [Array<Hash>]
189
+ attr_accessor :accelerators
190
+
191
+ # whether the instance has Secure Boot enabled
192
+ #
193
+ # @return Boolean
194
+ attr_accessor :enable_secure_boot
195
+
196
+ # whether the instance has the vTPM enabled
197
+ #
198
+ # @return Boolean
199
+ attr_accessor :enable_vtpm
200
+
201
+ # whether the instance has integrity monitoring enabled
202
+ #
203
+ # @return Boolean
204
+ attr_accessor :enable_integrity_monitoring
205
+
181
206
  def initialize(zone_specific=false)
182
- @google_json_key_location = UNSET_VALUE
183
- @google_project_id = UNSET_VALUE
184
- @image = UNSET_VALUE
185
- @image_family = UNSET_VALUE
186
- @image_project_id = UNSET_VALUE
187
- @instance_group = UNSET_VALUE
188
- @machine_type = UNSET_VALUE
189
- @disk_size = UNSET_VALUE
190
- @disk_name = UNSET_VALUE
191
- @disk_type = UNSET_VALUE
192
- @metadata = {}
193
- @name = UNSET_VALUE
194
- @network = UNSET_VALUE
195
- @network_project_id = UNSET_VALUE
196
- @subnetwork = UNSET_VALUE
197
- @tags = []
198
- @labels = {}
199
- @can_ip_forward = UNSET_VALUE
200
- @external_ip = UNSET_VALUE
201
- @network_ip = UNSET_VALUE
202
- @use_private_ip = UNSET_VALUE
203
- @autodelete_disk = UNSET_VALUE
204
- @preemptible = UNSET_VALUE
205
- @auto_restart = UNSET_VALUE
206
- @on_host_maintenance = UNSET_VALUE
207
- @instance_ready_timeout = UNSET_VALUE
208
- @zone = UNSET_VALUE
209
- @scopes = UNSET_VALUE
210
- @service_accounts = UNSET_VALUE
211
- @service_account = UNSET_VALUE
212
- @additional_disks = []
207
+ @google_json_key_location = UNSET_VALUE
208
+ @google_project_id = UNSET_VALUE
209
+ @image = UNSET_VALUE
210
+ @image_family = UNSET_VALUE
211
+ @image_project_id = UNSET_VALUE
212
+ @instance_group = UNSET_VALUE
213
+ @machine_type = UNSET_VALUE
214
+ @disk_size = UNSET_VALUE
215
+ @disk_name = UNSET_VALUE
216
+ @disk_type = UNSET_VALUE
217
+ @metadata = {}
218
+ @name = UNSET_VALUE
219
+ @network = UNSET_VALUE
220
+ @network_project_id = UNSET_VALUE
221
+ @subnetwork = UNSET_VALUE
222
+ @tags = []
223
+ @labels = {}
224
+ @can_ip_forward = UNSET_VALUE
225
+ @external_ip = UNSET_VALUE
226
+ @network_ip = UNSET_VALUE
227
+ @use_private_ip = UNSET_VALUE
228
+ @autodelete_disk = UNSET_VALUE
229
+ @preemptible = UNSET_VALUE
230
+ @auto_restart = UNSET_VALUE
231
+ @on_host_maintenance = UNSET_VALUE
232
+ @instance_ready_timeout = UNSET_VALUE
233
+ @zone = UNSET_VALUE
234
+ @scopes = UNSET_VALUE
235
+ @service_accounts = UNSET_VALUE
236
+ @service_account = UNSET_VALUE
237
+ @additional_disks = []
238
+ @setup_winrm_password = UNSET_VALUE
239
+ @accelerators = []
240
+ @enable_secure_boot = UNSET_VALUE
241
+ @enable_vtpm = UNSET_VALUE
242
+ @enable_integrity_monitoring = UNSET_VALUE
213
243
 
214
244
  # Internal state (prefix with __ so they aren't automatically
215
245
  # merged)
@@ -275,12 +305,10 @@ module VagrantPlugins
275
305
  result.instance_variable_set(:@__zone_config, new_zone_config)
276
306
 
277
307
  # Merge in the metadata
278
- result.metadata.merge!(self.metadata)
279
- result.metadata.merge!(other.metadata)
308
+ result.metadata = self.metadata.merge(other.metadata)
280
309
 
281
310
  # Merge in the labels
282
- result.labels.merge!(self.labels)
283
- result.labels.merge!(other.labels)
311
+ result.labels = self.labels.merge(other.labels)
284
312
 
285
313
  # Merge in the tags
286
314
  result.tags |= self.tags
@@ -382,11 +410,23 @@ module VagrantPlugins
382
410
  # Default IAM service account
383
411
  @service_account = nil if @service_account == UNSET_VALUE
384
412
 
413
+ # Default Setup WinRM Password
414
+ @setup_winrm_password = nil if @setup_winrm_password == UNSET_VALUE
415
+
385
416
  # Config option service_accounts is deprecated
386
417
  if @service_accounts
387
418
  @scopes = @service_accounts
388
419
  end
389
420
 
421
+ # enable_secure_boot defaults to nil
422
+ @enable_secure_boot = false if @enable_secure_boot == UNSET_VALUE
423
+
424
+ # enable_vtpm defaults to nil
425
+ @enable_vtpm = false if @enable_vtpm == UNSET_VALUE
426
+
427
+ # enable_integrity_monitoring defaults to nil
428
+ @enable_integrity_monitoring = false if @enable_integrity_monitoring == UNSET_VALUE
429
+
390
430
  # Compile our zone specific configurations only within
391
431
  # NON-zone-SPECIFIC configurations.
392
432
  unless @__zone_specific
@@ -444,6 +484,11 @@ module VagrantPlugins
444
484
 
445
485
  errors << I18n.t("vagrant_google.config.image_required") if config.image.nil? && config.image_family.nil?
446
486
  errors << I18n.t("vagrant_google.config.name_required") if @name.nil?
487
+
488
+ if !config.accelerators.empty?
489
+ errors << I18n.t("vagrant_google.config.on_host_maintenance_invalid_with_accelerators") unless \
490
+ config.on_host_maintenance == "TERMINATE"
491
+ end
447
492
  end
448
493
 
449
494
  if @service_accounts
@@ -13,6 +13,6 @@
13
13
  # limitations under the License.
14
14
  module VagrantPlugins
15
15
  module Google
16
- VERSION = "2.5.0".freeze
16
+ VERSION = "2.6.0".freeze
17
17
  end
18
18
  end
@@ -14,8 +14,8 @@ en:
14
14
  Instance is not created. Please run `vagrant up` first.
15
15
  ready: |-
16
16
  Machine is booted and ready for use!
17
- ready_ssh: |-
18
- Machine is ready for SSH access!
17
+ ready_comm: |-
18
+ Machine is ready for Communicator access!
19
19
  rsync_not_found_warning: |-
20
20
  Warning! Folder sync disabled because the rsync binary is missing.
21
21
  Make sure rsync is installed and the binary can be found in the PATH.
@@ -31,8 +31,8 @@ en:
31
31
  Waiting for GCP operation '%{name}' to finish...
32
32
  waiting_for_ready: |-
33
33
  Waiting for instance to become "ready"...
34
- waiting_for_ssh: |-
35
- Waiting for SSH to become available...
34
+ waiting_for_comm: |-
35
+ Waiting for Communicator to become available...
36
36
  warn_networks: |-
37
37
  Warning! The Google provider doesn't support any of the Vagrant
38
38
  high-level network configurations (`config.vm.network`). They
@@ -71,6 +71,9 @@ en:
71
71
  "image" must be unset when setting "image_family"
72
72
  service_accounts_deprecaated: |-
73
73
  "service_accounts is deprecated. Please use scopes instead"
74
+ on_host_maintenance_invalid_with_accelerators: |-
75
+ "on_host_maintenance" option must be set to "TERMINATE" for instances
76
+ with accelerators
74
77
  #-------------------------------------------------------------------------------
75
78
  # Translations for exception classes
76
79
  #-------------------------------------------------------------------------------
@@ -0,0 +1,40 @@
1
+ require "fileutils"
2
+
3
+ # Helper method to insert text after a line that matches the regex
4
+ def insert_after_line(file, insert, regex = /^## Next/)
5
+ tempfile = File.open("#{file}.tmp", "w")
6
+ f = File.new(file)
7
+ f.each do |line|
8
+ tempfile << line
9
+ next unless line =~ regex
10
+
11
+ tempfile << "\n"
12
+ tempfile << insert
13
+ tempfile << "\n"
14
+ end
15
+ f.close
16
+ tempfile.close
17
+
18
+ FileUtils.mv("#{file}.tmp", file)
19
+ end
20
+
21
+ # Extracts all changes that have been made after the latest pushed tag
22
+ def changes_since_last_tag
23
+ `git --no-pager log $(git describe --tags --abbrev=0)..HEAD --grep="Merge" --pretty=format:"%t - %s%n%b%n"`
24
+ end
25
+
26
+ # Extracts all github users contributed since last tag
27
+ def users_since_last_tag
28
+ `git --no-pager log $(git describe --tags --abbrev=0)..HEAD --grep="Merge" --pretty=format:"%s" | cut -d' ' -f 6 | cut -d/ -f1 | sort | uniq`
29
+ end
30
+
31
+ namespace :changelog do
32
+ task :generate do
33
+ insert_after_line("CHANGELOG.md", changes_since_last_tag, /^## Next/)
34
+ printf("Users contributed since last release:\n")
35
+ contributors = users_since_last_tag.split("\n").map { |name| "@" + name }
36
+ printf("Huge thanks to all our contributors 🎆\n")
37
+ printf("Special thanks to: " + contributors.join(" ") + "\n")
38
+ printf("\nI'll merge this and release the gem once all tests pass.\n")
39
+ end
40
+ end
@@ -7,6 +7,8 @@ Vagrant.configure("2") do |config|
7
7
 
8
8
  google.zone_config "australia-southeast1-b" do |zone|
9
9
  zone.name = "vagrant-acceptance-preemptible-#{('a'..'z').to_a.sample(8).join}"
10
+ # Some images no longer fit into default 10GB disk size
11
+ zone.disk_size = 30
10
12
  zone.disk_type = "pd-ssd"
11
13
  zone.image_family = "centos-7"
12
14
  end
@@ -30,26 +30,30 @@ describe VagrantPlugins::Google::Config do
30
30
  end
31
31
  end
32
32
 
33
- its("name") { should match "i-[0-9]{10}-[0-9a-f]{4}" }
34
- its("image") { should be_nil }
35
- its("image_family") { should be_nil }
36
- its("image_project_id") { should be_nil }
37
- its("instance_group") { should be_nil }
38
- its("zone") { should == "us-central1-f" }
39
- its("network") { should == "default" }
40
- its("machine_type") { should == "n1-standard-1" }
41
- its("disk_size") { should == 10 }
42
- its("disk_name") { should be_nil }
43
- its("disk_type") { should == "pd-standard" }
44
- its("instance_ready_timeout") { should == 20 }
45
- its("metadata") { should == {} }
46
- its("tags") { should == [] }
47
- its("labels") { should == {} }
48
- its("scopes") { should == nil }
49
- its("additional_disks") { should == [] }
50
- its("preemptible") { should be_falsey }
51
- its("auto_restart") { should }
52
- its("on_host_maintenance") { should == "MIGRATE" }
33
+ its("name") { should match "i-[0-9]{10}-[0-9a-f]{4}" }
34
+ its("image") { should be_nil }
35
+ its("image_family") { should be_nil }
36
+ its("image_project_id") { should be_nil }
37
+ its("instance_group") { should be_nil }
38
+ its("zone") { should == "us-central1-f" }
39
+ its("network") { should == "default" }
40
+ its("machine_type") { should == "n1-standard-1" }
41
+ its("disk_size") { should == 10 }
42
+ its("disk_name") { should be_nil }
43
+ its("disk_type") { should == "pd-standard" }
44
+ its("instance_ready_timeout") { should == 20 }
45
+ its("metadata") { should == {} }
46
+ its("tags") { should == [] }
47
+ its("labels") { should == {} }
48
+ its("scopes") { should == nil }
49
+ its("additional_disks") { should == [] }
50
+ its("preemptible") { should be_falsey }
51
+ its("auto_restart") { should }
52
+ its("on_host_maintenance") { should == "MIGRATE" }
53
+ its("accelerators") { should == [] }
54
+ its("enable_secure_boot") { should be_falsey }
55
+ its("enable_vtpm") { should be_falsey }
56
+ its("enable_integrity_monitoring") { should be_falsey }
53
57
  end
54
58
 
55
59
  describe "overriding defaults" do
@@ -57,8 +61,28 @@ describe VagrantPlugins::Google::Config do
57
61
  # simple boilerplate test, so I cut corners here. It just sets
58
62
  # each of these attributes to "foo" in isolation, and reads the value
59
63
  # and asserts the proper result comes back out.
60
- [:name, :image, :image_family, :image_project_id, :zone, :instance_ready_timeout, :machine_type, :disk_size, :disk_name, :disk_type,
61
- :network, :network_project_id, :metadata, :labels, :can_ip_forward, :external_ip, :autodelete_disk].each do |attribute|
64
+ [
65
+ :name,
66
+ :image,
67
+ :image_family,
68
+ :image_project_id,
69
+ :zone,
70
+ :instance_ready_timeout,
71
+ :machine_type,
72
+ :disk_size,
73
+ :disk_name,
74
+ :disk_type,
75
+ :network,
76
+ :network_project_id,
77
+ :metadata,
78
+ :labels,
79
+ :can_ip_forward,
80
+ :external_ip,
81
+ :autodelete_disk,
82
+ :enable_secure_boot,
83
+ :enable_vtpm,
84
+ :enable_integrity_monitoring,
85
+ ].each do |attribute|
62
86
 
63
87
  it "should not default #{attribute} if overridden" do
64
88
  instance.send("#{attribute}=".to_sym, "foo")
@@ -89,6 +113,14 @@ describe VagrantPlugins::Google::Config do
89
113
  errors = instance.validate("foo")["Google Provider"]
90
114
  expect(errors).to include(/on_host_maintenance_invalid_on_preemptible/)
91
115
  end
116
+
117
+ it "should raise error with accelerators and on_host_maintenance is not TERMINATE" do
118
+ instance.accelerators = [{ :type => "nvidia-tesla-k80" }]
119
+ instance.on_host_maintenance = "MIGRATE"
120
+ instance.finalize!
121
+ errors = instance.validate("foo")["Google Provider"]
122
+ expect(errors).to include(/on_host_maintenance_invalid_with_accelerators/)
123
+ end
92
124
  end
93
125
 
94
126
  describe "getting credentials from environment" do
@@ -128,6 +160,7 @@ describe VagrantPlugins::Google::Config do
128
160
  let(:config_network) { "foo" }
129
161
  let(:can_ip_forward) { true }
130
162
  let(:external_ip) { "foo" }
163
+ let(:accelerators) { [{ :type => "foo" }] }
131
164
 
132
165
  def set_test_values(instance)
133
166
  instance.name = config_name
@@ -140,6 +173,7 @@ describe VagrantPlugins::Google::Config do
140
173
  instance.zone = config_zone
141
174
  instance.can_ip_forward = can_ip_forward
142
175
  instance.external_ip = external_ip
176
+ instance.accelerators = accelerators
143
177
  end
144
178
 
145
179
  it "should raise an exception if not finalized" do
@@ -169,6 +203,7 @@ describe VagrantPlugins::Google::Config do
169
203
  its("zone") { should == config_zone }
170
204
  its("can_ip_forward") { should == can_ip_forward }
171
205
  its("external_ip") { should == external_ip }
206
+ its("accelerators") { should == accelerators }
172
207
  end
173
208
 
174
209
  context "with a specific config set" do
@@ -197,6 +232,7 @@ describe VagrantPlugins::Google::Config do
197
232
  its("zone") { should == zone_name }
198
233
  its("can_ip_forward") { should == can_ip_forward }
199
234
  its("external_ip") { should == external_ip }
235
+ its("accelerators") { should == accelerators }
200
236
  end
201
237
 
202
238
  describe "inheritance of parent config" do
@@ -231,47 +267,76 @@ describe VagrantPlugins::Google::Config do
231
267
  end
232
268
 
233
269
  describe "merging" do
234
- let(:first) { described_class.new }
235
- let(:second) { described_class.new }
270
+ let(:current) { described_class.new }
271
+ let(:other) { described_class.new }
272
+
273
+ subject { current.merge(other) }
236
274
 
237
275
  it "should merge the metadata" do
238
- first.metadata["one"] = "foo"
239
- second.metadata["two"] = "bar"
276
+ current.metadata["one"] = "foo"
277
+ other.metadata["two"] = "bar"
240
278
 
241
- third = first.merge(second)
242
- expect(third.metadata).to eq({
279
+ expect(subject.metadata).to eq({
243
280
  "one" => "foo",
244
281
  "two" => "bar"
245
282
  })
246
283
  end
247
284
 
285
+ it "should merge the metadata and overwrite older values" do
286
+ current.metadata = {
287
+ "one" => "foo",
288
+ "name" => "current",
289
+ }
290
+
291
+ other.metadata = {
292
+ "two" => "bar",
293
+ "name" => "other",
294
+ }
295
+
296
+ expect(subject.metadata).to eq({
297
+ "one" => "foo",
298
+ "two" => "bar",
299
+ "name" => "other",
300
+ })
301
+ end
302
+
248
303
  it "should merge the labels" do
249
- first.labels["one"] = "one"
250
- second.labels["two"] = "two"
304
+ current.labels["one"] = "one"
305
+ other.labels["two"] = "two"
251
306
 
252
- third = first.merge(second)
253
- expect(third.labels).to eq({
307
+ expect(subject.labels).to eq({
254
308
  "one" => "one",
255
309
  "two" => "two"
256
310
  })
257
311
  end
312
+
313
+ it "should merge the labels and overwrite older values" do
314
+ current.labels["one"] = "one"
315
+ current.labels["name"] = "current"
316
+ other.labels["two"] = "two"
317
+ other.labels["name"] = "other"
318
+
319
+ expect(subject.labels).to eq({
320
+ "one" => "one",
321
+ "two" => "two",
322
+ "name" => "other",
323
+ })
324
+ end
258
325
 
259
326
  it "should merge the tags" do
260
- first.tags = ["foo", "bar"]
261
- second.tags = ["biz"]
327
+ current.tags = ["foo", "bar"]
328
+ other.tags = ["biz"]
262
329
 
263
- third = first.merge(second)
264
- expect(third.tags).to include("foo")
265
- expect(third.tags).to include("bar")
266
- expect(third.tags).to include("biz")
330
+ expect(subject.tags).to include("foo")
331
+ expect(subject.tags).to include("bar")
332
+ expect(subject.tags).to include("biz")
267
333
  end
268
334
 
269
335
  it "should merge the additional_disks" do
270
- first.additional_disks = [{:one => "one"}]
271
- second.additional_disks = [{:two => "two"}]
336
+ current.additional_disks = [{:one => "one"}]
337
+ other.additional_disks = [{:two => "two"}]
272
338
 
273
- third = first.merge(second)
274
- expect(third.additional_disks).to contain_exactly(
339
+ expect(subject.additional_disks).to contain_exactly(
275
340
  {:one => "one"}, {:two => "two"}
276
341
  )
277
342
  end