Skip to content

Commit

Permalink
Support for dynamically generated password for Windows boxes (Issue
Browse files Browse the repository at this point in the history
  • Loading branch information
fred06fr committed Feb 16, 2017
1 parent 876ad73 commit f50a691
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 0 deletions.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ cloud.
* Halt and reboot instances
* Suspend and resume instances
* SSH into the instances
* Login into Windows instances using WinRM (even with dynamic passwords)
* Automatic SSH key generation and Nova public key provisioning
* Automatic floating IP allocation and association
* Provision the instances with any built-in Vagrant provisioner
Expand Down Expand Up @@ -328,6 +329,7 @@ creating and connecting to OpenStack machines
* `ssh.username` - Username used by vagrant for SSH login
* `ssh.port` - Default SSH port is 22. If set, this option will override the default for SSH login
* `ssh.private_key_path` - If set, vagrant will use this private key path to SSH on the machine. If you set this option, the `public_key_path` option of the provider should be set.
* `winrm.password` - Password used by vagrant for WinRM login on a Windows box (i.e. when config.vm.communicator=:winrm). If set to the special value :dynamic, the password will be automatically retrieved from Open Stack. This is useful for images that dynamically create passwords on provisioning.

## Box Format

Expand Down
13 changes: 13 additions & 0 deletions source/lib/vagrant-openstack-provider/action.rb
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,18 @@ def self.action_read_ssh_info
b.use ReadSSHInfo
end
end

# This action is called to read the server password of the machine. The
# resulting state is expected to be put into the `config.winrm.password`
# key.
def self.action_read_server_password
new_builder.tap do |b|
b.use ConfigValidate
b.use ConnectOpenstack
b.use ReadSSHInfo
b.use ReadServerPassword
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`
Expand Down Expand Up @@ -244,6 +256,7 @@ def self.action_reload
autoload :StopServer, action_root.join('stop_server')
autoload :StartServer, action_root.join('start_server')
autoload :ReadSSHInfo, action_root.join('read_ssh_info')
autoload :ReadServerPassword, action_root.join('read_server_password')
autoload :ReadState, action_root.join('read_state')
autoload :SyncFolders, action_root.join('sync_folders')
autoload :Suspend, action_root.join('suspend')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
require 'log4r'

require 'vagrant-openstack-provider/config_resolver'
require 'vagrant-openstack-provider/utils'
require 'vagrant-openstack-provider/action/abstract_action'

module VagrantPlugins
module Openstack
module Action
# This action reads the server password for the machine and puts it into the
# `config.winrm.password` key in the environment.

class ReadServerPassword < AbstractAction
def initialize(app, _env)
@app = app
@logger = Log4r::Logger.new('vagrant_openstack::action::read_server_password')
end

def execute(env)
read_server_password(env)
@app.call(env)
end

private

def read_server_password(env)
require 'openssl'
require 'base64'
machine=env[:machine]
if VagrantPlugins::Openstack::Cap.need_dynamic_password_update(machine.config)
@logger.info 'Reading server password from openstack'
encoded_passwd_b64=env[:openstack_client].nova.get_server_password(env, machine.id)
if (encoded_passwd_b64==nil || encoded_passwd_b64=='')
@logger.info "no password yet, the machine is not ready"
else
@logger.debug "encoded password b64 #{encoded_passwd_b64}"
encoded_passwd=Base64.decode64(encoded_passwd_b64)
ssh_key_path=env[:machine_ssh_info][:private_key_path]
@logger.debug "key path #{ssh_key_path}"
ssh_key = OpenSSL::PKey::RSA.new File.read(ssh_key_path)
clear_passwd = ssh_key.private_decrypt(encoded_passwd)
VagrantPlugins::Openstack::Cap.update_dynamic_password(machine.config,clear_passwd)
end
end
end
end
end
end
end
38 changes: 38 additions & 0 deletions source/lib/vagrant-openstack-provider/cap.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
module VagrantPlugins
module Openstack
module Cap
@logger = Log4r::Logger.new('vagrant_openstack::capability::winrm_info')

def self.winrm_info(machine)
# if we need dynamic password update from openstack?
if need_dynamic_password_update(machine.config)
@logger.info "config.winrm.password needs dynamic update, will retrieve it from openstack"
env = machine.action('read_server_password', lock: false)
# is password now updated?
if need_dynamic_password_update(env[:machine].config)
# if we have no server password yet in openstack, we are not ready. Return nil to tell that.
return nil
end
else
@logger.info "config.winrm.password is set to a non-dynamic value (i.e. not ':dynamic'), keeping it"
end
# if ok with password, return just nil values for host and port, so that winrm executes its default code.
return {
host: nil,
port: nil
}
end

def self.need_dynamic_password_update(config)
return config.winrm.password == :dynamic
end

def self.update_dynamic_password(config,new_password)
if config.winrm.password == :dynamic
config.winrm.password=new_password
@logger.info "config.winrm.password changed to the dynamic one from openstack"
end
end
end
end
end
7 changes: 7 additions & 0 deletions source/lib/vagrant-openstack-provider/client/nova.rb
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,13 @@ def get_server_details(env, server_id)
JSON.parse(server_details)['server']
end
end

def get_server_password(env, server_id)
instance_exists do
server_password = get(env, "#{@session.endpoints[:compute]}/servers/#{server_id}/os-server-password")
JSON.parse(server_password)['password']
end
end

def add_floating_ip(env, server_id, floating_ip)
instance_exists do
Expand Down
6 changes: 6 additions & 0 deletions source/lib/vagrant-openstack-provider/plugin.rb
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ class Plugin < Vagrant.plugin('2')
require_relative 'provider'
Provider
end

# add a capability to get proper winrm_info (password) from openstack
provider_capability(:openstack, :winrm_info) do
require_relative "cap"
Cap
end

command('openstack') do
Openstack.init_i18n
Expand Down

0 comments on commit f50a691

Please sign in to comment.