vagrant-google 2.5.0 → 2.6.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.
@@ -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