Skip to content

Commit

Permalink
Adds WinRM support using fog-google password reset ability
Browse files Browse the repository at this point in the history
  • Loading branch information
dvanbrug committed Apr 27, 2020
1 parent 1577290 commit 344826e
Show file tree
Hide file tree
Showing 7 changed files with 122 additions and 14 deletions.
10 changes: 10 additions & 0 deletions lib/vagrant-google/action.rb
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,15 @@ def self.action_read_ssh_info
end
end

# This action is called to setup the Windows user/password on the machine.
def self.action_setup_winrm_password
Vagrant::Action::Builder.new.tap do |b|
b.use ConfigValidate
b.use ConnectGoogle
b.use SetupWinrmPassword
end
end

# This action is called to read the state of the machine. The
# resulting state is expected to be put into the `:machine_state_id`
# key.
Expand Down Expand Up @@ -182,6 +191,7 @@ def self.action_reload
autoload :MessageNotCreated, action_root.join("message_not_created")
autoload :MessageWillNotDestroy, action_root.join("message_will_not_destroy")
autoload :ReadSSHInfo, action_root.join("read_ssh_info")
autoload :SetupWinrmPassword, action_root.join('setup_winrm_password')
autoload :ReadState, action_root.join("read_state")
autoload :RunInstance, action_root.join("run_instance")
autoload :StartInstance, action_root.join("start_instance")
Expand Down
27 changes: 22 additions & 5 deletions lib/vagrant-google/action/run_instance.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
require "log4r"
require 'vagrant/util/retryable'
require 'vagrant-google/util/timer'
require 'vagrant-google/action/setup_winrm_password'

module VagrantPlugins
module Google
Expand Down Expand Up @@ -287,19 +288,35 @@ def call(env) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
env[:interrupted] = true
end

# Parse out the image project in case it was not set
# and check if it is part of a public windows project
img_project = image.split("/")[6]
is_windows_image = img_project.eql?("windows-cloud") || img_project.eql?("windows-sql-cloud")

# Reset the password if a windows image unless flag overrides
setup_winrm_password = zone_config.setup_winrm_password
if setup_winrm_password.nil? && is_windows_image
setup_winrm_password = true
end

if setup_winrm_password
env[:ui].info("Setting up WinRM Password")
env[:action_runner].run(Action.action_setup_winrm_password, env)
end

unless env[:terminated]
env[:metrics]["instance_ssh_time"] = Util::Timer.time do
# Wait for SSH to be ready.
env[:ui].info(I18n.t("vagrant_google.waiting_for_ssh"))
env[:metrics]["instance_comm_time"] = Util::Timer.time do
# Wait for Comms to be ready.
env[:ui].info(I18n.t("vagrant_google.waiting_for_comm"))
while true
# If we're interrupted just back out
break if env[:interrupted]
break if env[:machine].communicate.ready?
sleep 2
end
end
@logger.info("Time for SSH ready: #{env[:metrics]["instance_ssh_time"]}")
env[:ui].info(I18n.t("vagrant_google.ready_ssh")) unless env[:interrupted]
@logger.info("Time for Comms ready: #{env[:metrics]["instance_comm_time"]}")
env[:ui].info(I18n.t("vagrant_google.ready_comm")) unless env[:interrupted]
end

# Terminate the instance if we were interrupted
Expand Down
72 changes: 72 additions & 0 deletions lib/vagrant-google/action/setup_winrm_password.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Copyright 2015 Google Inc. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# Changes:
# April 2019: Modified example found here:
# https://github.com/GoogleCloudPlatform/compute-image-windows/blob/master/examples/windows_auth_python_sample.py
# to enable WinRM with vagrant.

module VagrantPlugins
module Google
module Action
# Sets up a temporary WinRM password using Google's method for
# establishing a new password over encrypted channels.
class SetupWinrmPassword
def initialize(app, env)
@app = app
@logger = Log4r::Logger.new("vagrant_google::action::setup_winrm_password")
end

def setup_password(env, instance, zone, user)
# Setup
compute = env[:google_compute]
server = compute.servers.get(instance, zone)
password = server.reset_windows_password(user)

env[:ui].info("Temp Password: #{password}")

password
end

def call(env)
# Get the configs
zone = env[:machine].provider_config.zone
zone_config = env[:machine].provider_config.get_zone_config(zone)

instance = zone_config.name
user = env[:machine].config.winrm.username
pass = env[:machine].config.winrm.password

# Get Temporary Password, set WinRM password
temp_pass = setup_password(env, instance, zone, user)
env[:machine].config.winrm.password = temp_pass

# Wait for WinRM To be Ready
env[:ui].info("Waiting for WinRM To be ready")
env[:machine].communicate.wait_for_ready(60)

# Use WinRM to Change Password to one in Vagrantfile
env[:ui].info("Changing password from temporary to winrm password")
winrmcomm = VagrantPlugins::CommunicatorWinRM::Communicator.new(env[:machine])
cmd = "net user #{user} #{pass}"
opts = { elevated: true }
winrmcomm.test(cmd, opts)

# Update WinRM password to reflect updated one
env[:machine].config.winrm.password = pass
end
end
end
end
end
8 changes: 4 additions & 4 deletions lib/vagrant-google/action/start_instance.rb
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,9 @@ def call(env)
@logger.info("Time to instance ready: #{env[:metrics]["instance_ready_time"]}")

unless env[:interrupted]
env[:metrics]["instance_ssh_time"] = Util::Timer.time do
# Wait for SSH to be ready.
env[:ui].info(I18n.t("vagrant_google.waiting_for_ssh"))
env[:metrics]["instance_comm_time"] = Util::Timer.time do
# Wait for Comms to be ready.
env[:ui].info(I18n.t("vagrant_google.waiting_for_comm"))
while true
# If we're interrupted then just back out
break if env[:interrupted]
Expand All @@ -76,7 +76,7 @@ def call(env)
end
end

@logger.info("Time for SSH ready: #{env[:metrics]["instance_ssh_time"]}")
@logger.info("Time for Comms ready: #{env[:metrics]["instance_comm_time"]}")

# Ready and booted!
env[:ui].info(I18n.t("vagrant_google.ready"))
Expand Down
9 changes: 9 additions & 0 deletions lib/vagrant-google/config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,11 @@ class Config < Vagrant.plugin("2", :config) # rubocop:disable Metrics/ClassLengt
# @return [Array<Hash>]
attr_accessor :additional_disks

# (Optional - Override default WinRM setup before for Public Windows images)
#
# @return [Boolean]
attr_accessor :setup_winrm_password

def initialize(zone_specific=false)
@google_json_key_location = UNSET_VALUE
@google_project_id = UNSET_VALUE
Expand Down Expand Up @@ -210,6 +215,7 @@ def initialize(zone_specific=false)
@service_accounts = UNSET_VALUE
@service_account = UNSET_VALUE
@additional_disks = []
@setup_winrm_password = UNSET_VALUE

# Internal state (prefix with __ so they aren't automatically
# merged)
Expand Down Expand Up @@ -382,6 +388,9 @@ def finalize! # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedC
# Default IAM service account
@service_account = nil if @service_account == UNSET_VALUE

# Default Setup WinRM Password
@setup_winrm_password = nil if @setup_winrm_password == UNSET_VALUE

# Config option service_accounts is deprecated
if @service_accounts
@scopes = @service_accounts
Expand Down
8 changes: 4 additions & 4 deletions locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ en:
Instance is not created. Please run `vagrant up` first.
ready: |-
Machine is booted and ready for use!
ready_ssh: |-
Machine is ready for SSH access!
ready_comm: |-
Machine is ready for Communicator access!
rsync_not_found_warning: |-
Warning! Folder sync disabled because the rsync binary is missing.
Make sure rsync is installed and the binary can be found in the PATH.
Expand All @@ -31,8 +31,8 @@ en:
Waiting for GCP operation '%{name}' to finish...
waiting_for_ready: |-
Waiting for instance to become "ready"...
waiting_for_ssh: |-
Waiting for SSH to become available...
waiting_for_comm: |-
Waiting for Communicator to become available...
warn_networks: |-
Warning! The Google provider doesn't support any of the Vagrant
high-level network configurations (`config.vm.network`). They
Expand Down
2 changes: 1 addition & 1 deletion vagrant-google.gemspec
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ Gem::Specification.new do |s|
s.required_rubygems_version = ">= 1.3.6"
s.rubyforge_project = "vagrant-google"

s.add_runtime_dependency "fog-google", "~> 1.9.1"
s.add_runtime_dependency "fog-google", "~> 1.10.0"

# This is a restriction to avoid errors on `failure_message_for_should`
# TODO: revise after vagrant_spec goes past >0.0.1 (at master@e623a56)
Expand Down

0 comments on commit 344826e

Please sign in to comment.