providers/hyperv: initial commit
Initial work done by MS Open Tech
This commit is contained in:
parent
6b17783688
commit
ca24d60d8f
|
@ -0,0 +1,128 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
require "pathname"
|
||||||
|
require "vagrant/action/builder"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
module Action
|
||||||
|
# Include the built-in modules so we can use them as top-level things.
|
||||||
|
include Vagrant::Action::Builtin
|
||||||
|
|
||||||
|
def self.action_reload
|
||||||
|
Vagrant::Action::Builder.new.tap do |b|
|
||||||
|
b.use ConfigValidate
|
||||||
|
b.use Call, IsCreated do |env, b2|
|
||||||
|
if !env[:result]
|
||||||
|
b2.use MessageNotCreated
|
||||||
|
next
|
||||||
|
end
|
||||||
|
b2.use action_halt
|
||||||
|
b2.use Call, WaitForState, :off, 120 do |env2, b3|
|
||||||
|
if env2[:result]
|
||||||
|
b3.use action_up
|
||||||
|
else
|
||||||
|
env2[:ui].info("Machine did not reload, Check machine's status")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.action_halt
|
||||||
|
Vagrant::Action::Builder.new.tap do |b|
|
||||||
|
b.use ConfigValidate
|
||||||
|
b.use Call, IsCreated do |env, b2|
|
||||||
|
if !env[:result]
|
||||||
|
b2.use MessageNotCreated
|
||||||
|
next
|
||||||
|
end
|
||||||
|
b2.use StopInstance
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.action_start
|
||||||
|
Vagrant::Action::Builder.new.tap do |b|
|
||||||
|
b.use StartInstance
|
||||||
|
b.use ShareFolders
|
||||||
|
b.use SyncFolders
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.action_up
|
||||||
|
Vagrant::Action::Builder.new.tap do |b|
|
||||||
|
b.use HandleBoxUrl
|
||||||
|
b.use ConfigValidate
|
||||||
|
b.use Call, IsCreated do |env1, b1|
|
||||||
|
if env1[:result]
|
||||||
|
b1.use Call, IsStopped do |env2, b2|
|
||||||
|
if env2[:result]
|
||||||
|
b2.use action_start
|
||||||
|
else
|
||||||
|
b2.use MessageAlreadyCreated
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
b1.use Import
|
||||||
|
b1.use action_start
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.action_read_state
|
||||||
|
Vagrant::Action::Builder.new.tap do |b|
|
||||||
|
b.use ConfigValidate
|
||||||
|
b.use ReadState
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.action_ssh
|
||||||
|
Vagrant::Action::Builder.new.tap do |b|
|
||||||
|
b.use ConfigValidate
|
||||||
|
b.use Call, IsCreated do |env, b2|
|
||||||
|
if !env[:result]
|
||||||
|
b2.use MessageNotCreated
|
||||||
|
next
|
||||||
|
end
|
||||||
|
b2.use Call, IsStopped do |env1, b3|
|
||||||
|
if env1[:result]
|
||||||
|
b3.use MessageNotRunning
|
||||||
|
else
|
||||||
|
b3.use SSHExec
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.action_read_guest_ip
|
||||||
|
Vagrant::Action::Builder.new.tap do |b|
|
||||||
|
b.use ConfigValidate
|
||||||
|
b.use ReadGuestIP
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
# The autoload farm
|
||||||
|
action_root = Pathname.new(File.expand_path("../action", __FILE__))
|
||||||
|
autoload :IsCreated, action_root.join("is_created")
|
||||||
|
autoload :IsStopped, action_root.join("is_stopped")
|
||||||
|
autoload :ReadState, action_root.join("read_state")
|
||||||
|
autoload :Import, action_root.join("import")
|
||||||
|
autoload :StartInstance, action_root.join('start_instance')
|
||||||
|
autoload :StopInstance, action_root.join('stop_instance')
|
||||||
|
autoload :MessageNotCreated, action_root.join('message_not_created')
|
||||||
|
autoload :MessageAlreadyCreated, action_root.join('message_already_created')
|
||||||
|
autoload :MessageNotRunning, action_root.join('message_not_running')
|
||||||
|
autoload :SyncFolders, action_root.join('sync_folders')
|
||||||
|
autoload :WaitForState, action_root.join('wait_for_state')
|
||||||
|
autoload :ReadGuestIP, action_root.join('read_guest_ip')
|
||||||
|
autoload :ShareFolders, action_root.join('share_folders')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,49 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
require "log4r"
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
module Action
|
||||||
|
class Import
|
||||||
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
@logger = Log4r::Logger.new("vagrant::hyperv::connection")
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
box_directory = env[:machine].box.directory.to_s
|
||||||
|
path = Pathname.new(box_directory.to_s + '/Virtual Machines')
|
||||||
|
config_path = ""
|
||||||
|
path.each_child do |f|
|
||||||
|
config_path = f.to_s if f.extname.downcase == ".xml"
|
||||||
|
end
|
||||||
|
|
||||||
|
path = Pathname.new(box_directory.to_s + '/Virtual Hard Disks')
|
||||||
|
vhdx_path = ""
|
||||||
|
path.each_child do |f|
|
||||||
|
vhdx_path = f.to_s if f.extname.downcase == ".vhdx"
|
||||||
|
end
|
||||||
|
|
||||||
|
options = {
|
||||||
|
vm_xml_config: config_path.gsub("/", "\\"),
|
||||||
|
vhdx_path: vhdx_path.gsub("/", "\\")
|
||||||
|
}
|
||||||
|
|
||||||
|
env[:ui].info "Importing a Hyper-V instance"
|
||||||
|
begin
|
||||||
|
server = env[:machine].provider.driver.execute('import_vm.ps1', options)
|
||||||
|
rescue Error::SubprocessError => e
|
||||||
|
env[:ui].info e.message
|
||||||
|
return
|
||||||
|
end
|
||||||
|
env[:ui].info "Successfully imported a VM with name #{server['name']}"
|
||||||
|
env[:machine].id = server["id"]
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,22 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
require "log4r"
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
module Action
|
||||||
|
class IsCreated
|
||||||
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
env[:result] = env[:machine].state.id != :not_created
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,22 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
require "log4r"
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
module Action
|
||||||
|
class IsStopped
|
||||||
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
env[:result] = env[:machine].state.id == :off
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,22 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
require "log4r"
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
module Action
|
||||||
|
class MessageAlreadyCreated
|
||||||
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
env[:ui].info("Machine already created")
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,22 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
require "log4r"
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
module Action
|
||||||
|
class MessageNotCreated
|
||||||
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
env[:ui].info("Machine not created")
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,22 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
require "log4r"
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
module Action
|
||||||
|
class MessageNotRunning
|
||||||
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
env[:ui].info("Machine is not running, Please turn it on.")
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,46 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
require "log4r"
|
||||||
|
require "timeout"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
module Action
|
||||||
|
# This action reads the SSH info for the machine and puts it into the
|
||||||
|
# `:machine_ssh_info` key in the environment.
|
||||||
|
class ReadGuestIP
|
||||||
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
@logger = Log4r::Logger.new("vagrant::hyperv::connection")
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
env[:machine_ssh_info] = read_host_ip(env)
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
|
||||||
|
def read_host_ip(env)
|
||||||
|
return nil if env[:machine].id.nil?
|
||||||
|
# Get Network details from WMI Provider
|
||||||
|
# Wait for 120 sec By then the machine should be ready
|
||||||
|
host_ip = nil
|
||||||
|
begin
|
||||||
|
Timeout.timeout(120) do
|
||||||
|
begin
|
||||||
|
options = { vm_id: env[:machine].id }
|
||||||
|
network_info = env[:machine].provider.driver.execute('get_network_config.ps1', options)
|
||||||
|
host_ip = network_info["ip"]
|
||||||
|
sleep 10 if host_ip.empty?
|
||||||
|
end while host_ip.empty?
|
||||||
|
end
|
||||||
|
rescue Timeout::Error
|
||||||
|
@logger.info("Cannot find the IP address of the virtual machine")
|
||||||
|
end
|
||||||
|
return { host: host_ip } unless host_ip.nil?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,36 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
require "debugger"
|
||||||
|
require "log4r"
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
module Action
|
||||||
|
class ReadState
|
||||||
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
@logger = Log4r::Logger.new("vagrant::hyperv::connection")
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
if env[:machine].id
|
||||||
|
begin
|
||||||
|
options = { vm_id: env[:machine].id }
|
||||||
|
response = env[:machine].provider.driver.execute('get_vm_status.ps1', options)
|
||||||
|
env[:machine_state_id] = response["state"].downcase.to_sym
|
||||||
|
rescue Error::SubprocessError => e
|
||||||
|
env[:machine].id = nil
|
||||||
|
env[:ui].info "Could not find a machine, assuming it to be deleted or terminated."
|
||||||
|
env[:machine_state_id] = :not_created
|
||||||
|
end
|
||||||
|
else
|
||||||
|
env[:machine_state_id] = :not_created
|
||||||
|
end
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,123 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
require "debugger"
|
||||||
|
require "vagrant/util/subprocess"
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
module Action
|
||||||
|
class ShareFolders
|
||||||
|
|
||||||
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
@env = env
|
||||||
|
smb_shared_folders
|
||||||
|
prepare_smb_share
|
||||||
|
# A BIG Clean UP
|
||||||
|
# There should be a communicator class which branches between windows
|
||||||
|
# and Linux
|
||||||
|
if @smb_shared_folders.length > 0
|
||||||
|
env[:ui].info('Mounting shared folders with VM, This process may take few minutes.')
|
||||||
|
end
|
||||||
|
if env[:machine].config.vm.guest == :windows
|
||||||
|
env[:ui].info "Mounting shared folders to windows is under development."
|
||||||
|
# mount_shared_folders_to_windows
|
||||||
|
elsif env[:machine].config.vm.guest == :linux
|
||||||
|
mount_shared_folders_to_linux
|
||||||
|
end
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
|
||||||
|
def smb_shared_folders
|
||||||
|
@smb_shared_folders = {}
|
||||||
|
@env[:machine].config.vm.synced_folders.each do |id, data|
|
||||||
|
# Ignore disabled shared folders
|
||||||
|
next if data[:disabled]
|
||||||
|
|
||||||
|
# Collect all SMB shares
|
||||||
|
next unless data[:smb]
|
||||||
|
# This to prevent overwriting the actual shared folders data
|
||||||
|
@smb_shared_folders[id] = data.dup
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def prepare_smb_share
|
||||||
|
@smb_shared_folders.each do |id, data|
|
||||||
|
begin
|
||||||
|
hostpath = File.expand_path(data[:hostpath], @env[:root_path])
|
||||||
|
host_share_username = @env[:machine].provider_config.host_share.username
|
||||||
|
options = {:path => hostpath,
|
||||||
|
:share_name => data[:share_name],
|
||||||
|
:host_share_username => host_share_username}
|
||||||
|
response = @env[:machine].provider.driver.execute('set_smb_share.ps1', options)
|
||||||
|
if response["message"] == "OK"
|
||||||
|
@env[:ui].info "Successfully created SMB share for #{hostpath} with name #{data[:share_name]}"
|
||||||
|
end
|
||||||
|
rescue Error::SubprocessError => e
|
||||||
|
@env[:ui].info e.message
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def ssh_info
|
||||||
|
@ssh_info || @env[:machine].ssh_info
|
||||||
|
end
|
||||||
|
|
||||||
|
def mount_shared_folders_to_windows
|
||||||
|
result = @env[:machine].provider.driver.execute('host_info.ps1', {})
|
||||||
|
@smb_shared_folders.each do |id, data|
|
||||||
|
begin
|
||||||
|
options = { :share_name => data[:share_name],
|
||||||
|
:guest_path => data[:guestpath].gsub("/", "\\"),
|
||||||
|
:guest_ip => ssh_info[:host],
|
||||||
|
:username => ssh_info[:username],
|
||||||
|
:host_ip => result["host_ip"],
|
||||||
|
:password => @env[:machine].provider_config.guest.password,
|
||||||
|
:host_share_username => @env[:machine].provider_config.host_share.username,
|
||||||
|
:host_share_password => @env[:machine].provider_config.host_share.password}
|
||||||
|
@env[:ui].info("Linking #{data[:share_name]} to Guest at #{data[:guestpath]} ...")
|
||||||
|
@env[:machine].provider.driver.execute('mount_share.ps1', options)
|
||||||
|
rescue Error::SubprocessError => e
|
||||||
|
@env[:ui].info "Failed to link #{data[:share_name]} to Guest"
|
||||||
|
@env[:ui].info e.message
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def mount_shared_folders_to_linux
|
||||||
|
# Find Host Machine's credentials
|
||||||
|
result = @env[:machine].provider.driver.execute('host_info.ps1', {})
|
||||||
|
host_share_username = @env[:machine].provider_config.host_share.username
|
||||||
|
host_share_password = @env[:machine].provider_config.host_share.password
|
||||||
|
@smb_shared_folders.each do |id, data|
|
||||||
|
begin
|
||||||
|
# Mount the Network drive to Guest VM
|
||||||
|
@env[:ui].info("Linking #{data[:share_name]} to Guest at #{data[:guestpath]} ...")
|
||||||
|
|
||||||
|
# Create a location in guest to guestpath
|
||||||
|
@env[:machine].communicate.sudo("mkdir -p #{data[:guestpath]}")
|
||||||
|
owner = data[:owner] || ssh_info[:username]
|
||||||
|
group = data[:group] || ssh_info[:username]
|
||||||
|
|
||||||
|
mount_options = "-o rw,username=#{host_share_username},pass=#{host_share_password},"
|
||||||
|
mount_options += "sec=ntlm,file_mode=0777,dir_mode=0777,"
|
||||||
|
mount_options += "uid=`id -u #{owner}`,gid=`id -g #{group}`,rw #{data[:guestpath]}"
|
||||||
|
|
||||||
|
command = "mount -t cifs //#{result["host_ip"]}/#{data[:share_name]} #{mount_options}"
|
||||||
|
|
||||||
|
@env[:machine].communicate.sudo(command)
|
||||||
|
|
||||||
|
rescue RuntimeError => e
|
||||||
|
@env[:ui].error(e.message)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,29 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
module Action
|
||||||
|
class StartInstance
|
||||||
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
env[:ui].info('Starting the Machine')
|
||||||
|
options = { vm_id: env[:machine].id }
|
||||||
|
begin
|
||||||
|
response = env[:machine].provider.driver.execute('start_vm.ps1', options)
|
||||||
|
env[:ui].info "Machine #{response["name"]} started"
|
||||||
|
rescue Error::SubprocessError => e
|
||||||
|
env[:ui].info e.message
|
||||||
|
return
|
||||||
|
end
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,24 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
require "log4r"
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
module Action
|
||||||
|
class StopInstance
|
||||||
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
env[:ui].info('Stopping the Machine')
|
||||||
|
options = { vm_id: env[:machine].id }
|
||||||
|
response = env[:machine].provider.driver.execute('stop_vm.ps1', options)
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,74 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
require "debugger"
|
||||||
|
require "log4r"
|
||||||
|
require "vagrant/util/subprocess"
|
||||||
|
require "vagrant/util/which"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
module Action
|
||||||
|
class SyncFolders
|
||||||
|
|
||||||
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
@logger = Log4r::Logger.new("vagrant_hyperv::action::sync_folders")
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
@env = env
|
||||||
|
@app.call(env)
|
||||||
|
if env[:machine].config.vm.guest == :windows
|
||||||
|
sync_folders_to_windows
|
||||||
|
elsif env[:machine].config.vm.guest == :linux
|
||||||
|
sync_folders_to_linux
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def ssh_info
|
||||||
|
@ssh_info ||= @env[:machine].ssh_info
|
||||||
|
end
|
||||||
|
|
||||||
|
def sync_folders_to_windows
|
||||||
|
@env[:machine].config.vm.synced_folders.each do |id, data|
|
||||||
|
# Ignore disabled shared folders
|
||||||
|
next if data[:disabled] || data[:smb]
|
||||||
|
hostpath = File.expand_path(data[:hostpath], @env[:root_path]).gsub("/", "\\")
|
||||||
|
guestpath = data[:guestpath].gsub("/", "\\")
|
||||||
|
options = { :guest_ip => ssh_info[:host],
|
||||||
|
:username => ssh_info[:username],
|
||||||
|
:host_path => hostpath,
|
||||||
|
:guest_path => guestpath,
|
||||||
|
:vm_id => @env[:machine].id,
|
||||||
|
:password => @env[:machine].provider_config.guest.password }
|
||||||
|
response = @env[:machine].provider.driver.execute('file_sync.ps1', options)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def sync_folders_to_linux
|
||||||
|
if ssh_info.nil?
|
||||||
|
@env[:ui].info('SSH Info not available, Aborting Sync folder')
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
@env[:machine].config.vm.synced_folders.each do |id, data|
|
||||||
|
# Ignore disabled shared folders
|
||||||
|
next if data[:disabled] || data[:smb]
|
||||||
|
hostpath = File.expand_path(data[:hostpath], @env[:root_path])
|
||||||
|
guestpath = data[:guestpath]
|
||||||
|
@env[:ui].info('Starting Sync folders')
|
||||||
|
begin
|
||||||
|
@env[:machine].communicate.upload(hostpath, guestpath)
|
||||||
|
rescue RuntimeError => e
|
||||||
|
@env[:ui].error(e.message)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,40 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
require "log4r"
|
||||||
|
require "timeout"
|
||||||
|
require "debugger"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
module Action
|
||||||
|
class WaitForState
|
||||||
|
def initialize(app, env, state, timeout)
|
||||||
|
@app = app
|
||||||
|
@state = state
|
||||||
|
@timeout = timeout
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
env[:result] = true
|
||||||
|
# Wait until the Machine's state is disabled (ie State of Halt)
|
||||||
|
unless env[:machine].state.id == @state
|
||||||
|
env[:ui].info("Waiting for machine to #{@state}")
|
||||||
|
begin
|
||||||
|
Timeout.timeout(@timeout) do
|
||||||
|
until env[:machine].state.id == @state
|
||||||
|
sleep 2
|
||||||
|
end
|
||||||
|
end
|
||||||
|
rescue Timeout::Error
|
||||||
|
env[:result] = false # couldn't reach state in time
|
||||||
|
end
|
||||||
|
end
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,13 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
module Communicator
|
||||||
|
lib_path = Pathname.new(File.expand_path("../communicator", __FILE__))
|
||||||
|
autoload :SSH, lib_path.join("ssh")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,50 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
require "vagrant"
|
||||||
|
require_relative "guest_config/config"
|
||||||
|
require_relative "host_share/config"
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
class Config < Vagrant.plugin("2", :config)
|
||||||
|
# If set to `true`, then VirtualBox will be launched with a GUI.
|
||||||
|
#
|
||||||
|
# @return [Boolean]
|
||||||
|
attr_accessor :gui
|
||||||
|
attr_reader :host_share, :guest
|
||||||
|
|
||||||
|
def host_config(&block)
|
||||||
|
block.call(@host_share)
|
||||||
|
end
|
||||||
|
|
||||||
|
def guest_config(&block)
|
||||||
|
block.call(@guest)
|
||||||
|
end
|
||||||
|
|
||||||
|
def finalize!
|
||||||
|
@gui = nil if @gui == UNSET_VALUE
|
||||||
|
end
|
||||||
|
|
||||||
|
def initialize(region_specific=false)
|
||||||
|
@gui = UNSET_VALUE
|
||||||
|
@host_share = HostShare::Config.new
|
||||||
|
@guest = GuestConfig::Config.new
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate(machine)
|
||||||
|
errors = _detected_errors
|
||||||
|
unless host_share.valid_config?
|
||||||
|
errors << host_share.errors.flatten.join(" ")
|
||||||
|
end
|
||||||
|
|
||||||
|
unless guest.valid_config?
|
||||||
|
errors << guest.errors.flatten.join(" ")
|
||||||
|
end
|
||||||
|
{ "HyperV" => errors }
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,13 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
module Driver
|
||||||
|
lib_path = Pathname.new(File.expand_path("../driver", __FILE__))
|
||||||
|
autoload :Base, lib_path.join("base")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,110 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
require "debugger"
|
||||||
|
require "json"
|
||||||
|
require "vagrant/util/which"
|
||||||
|
require "vagrant/util/subprocess"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
module Driver
|
||||||
|
class Base
|
||||||
|
attr_reader :vmid
|
||||||
|
|
||||||
|
def initialize(id=nil)
|
||||||
|
@vmid = id
|
||||||
|
check_power_shell
|
||||||
|
@output = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute(path, options)
|
||||||
|
r = execute_powershell(path, options) do |type, data|
|
||||||
|
process_output(type, data)
|
||||||
|
end
|
||||||
|
if success?
|
||||||
|
JSON.parse(json_output[:success].join) unless json_output[:success].empty?
|
||||||
|
else
|
||||||
|
message = json_output[:error].join unless json_output[:error].empty?
|
||||||
|
raise Error::SubprocessError, message if message
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def raw_execute(command)
|
||||||
|
command = [command , {notify: [:stdout, :stderr, :stdin]}].flatten
|
||||||
|
clear_output_buffer
|
||||||
|
Vagrant::Util::Subprocess.execute(*command) do |type, data|
|
||||||
|
process_output(type, data)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def json_output
|
||||||
|
return @json_output if @json_output
|
||||||
|
json_success_begin = false
|
||||||
|
json_error_begin = false
|
||||||
|
success = []
|
||||||
|
error = []
|
||||||
|
@output.split("\n").each do |line|
|
||||||
|
json_error_begin = false if line.include?("===End-Error===")
|
||||||
|
json_success_begin = false if line.include?("===End-Output===")
|
||||||
|
message = ""
|
||||||
|
if json_error_begin || json_success_begin
|
||||||
|
message = line.gsub("\\'","\"")
|
||||||
|
end
|
||||||
|
success << message if json_success_begin
|
||||||
|
error << message if json_error_begin
|
||||||
|
json_success_begin = true if line.include?("===Begin-Output===")
|
||||||
|
json_error_begin = true if line.include?("===Begin-Error===")
|
||||||
|
end
|
||||||
|
@json_output = { :success => success, :error => error }
|
||||||
|
end
|
||||||
|
|
||||||
|
def success?
|
||||||
|
@error_messages.empty? && json_output[:error].empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
def process_output(type, data)
|
||||||
|
if type == :stdout
|
||||||
|
@output = data.gsub("\r\n", "\n")
|
||||||
|
end
|
||||||
|
if type == :stdin
|
||||||
|
# $stdin.gets.chomp || ""
|
||||||
|
end
|
||||||
|
if type == :stderr
|
||||||
|
@error_messages = data.gsub("\r\n", "\n")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def clear_output_buffer
|
||||||
|
@output = ""
|
||||||
|
@error_messages = ""
|
||||||
|
@json_output = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def check_power_shell
|
||||||
|
unless Vagrant::Util::Which.which('powershell')
|
||||||
|
raise "Power Shell not found"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def execute_powershell(path, options, &block)
|
||||||
|
lib_path = Pathname.new(File.expand_path("../../scripts", __FILE__))
|
||||||
|
path = lib_path.join(path).to_s.gsub("/", "\\")
|
||||||
|
options = options || {}
|
||||||
|
ps_options = []
|
||||||
|
options.each do |key, value|
|
||||||
|
ps_options << "-#{key}"
|
||||||
|
ps_options << "'#{value}'"
|
||||||
|
end
|
||||||
|
clear_output_buffer
|
||||||
|
command = ["powershell", "-NoProfile", "-ExecutionPolicy",
|
||||||
|
"Bypass", path, ps_options, {notify: [:stdout, :stderr, :stdin]}].flatten
|
||||||
|
Vagrant::Util::Subprocess.execute(*command, &block)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,13 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
module Error
|
||||||
|
lib_path = Pathname.new(File.expand_path("../error", __FILE__))
|
||||||
|
autoload :SubprocessError, lib_path.join("subprocess_error")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,24 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
require "json"
|
||||||
|
require "vagrant/util/which"
|
||||||
|
require "vagrant/util/subprocess"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
module Error
|
||||||
|
class SubprocessError < RuntimeError
|
||||||
|
def initialize(message)
|
||||||
|
@message = JSON.parse(message) if message
|
||||||
|
end
|
||||||
|
|
||||||
|
def message
|
||||||
|
@message["error"]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,33 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
module GuestConfig
|
||||||
|
class Config < Vagrant.plugin("2", :config)
|
||||||
|
attr_accessor :username, :password
|
||||||
|
|
||||||
|
def errors
|
||||||
|
@errors
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate
|
||||||
|
@errors = []
|
||||||
|
if username.nil?
|
||||||
|
@errors << "Please configure a Guest VM's username"
|
||||||
|
end
|
||||||
|
if password.nil?
|
||||||
|
@errors << "Please configure a Guest VM's password"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def valid_config?
|
||||||
|
validate
|
||||||
|
errors.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,33 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
module HostShare
|
||||||
|
class Config < Vagrant.plugin("2", :config)
|
||||||
|
attr_accessor :username, :password
|
||||||
|
|
||||||
|
def errors
|
||||||
|
@errors
|
||||||
|
end
|
||||||
|
|
||||||
|
def validate
|
||||||
|
@errors = []
|
||||||
|
if username.nil?
|
||||||
|
@errors << "Please configure a Windows user account to share folders"
|
||||||
|
end
|
||||||
|
if password.nil?
|
||||||
|
@errors << "Please configure a Windows user account password to share folders"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def valid_config?
|
||||||
|
validate
|
||||||
|
errors.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,76 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
begin
|
||||||
|
require "vagrant"
|
||||||
|
rescue LoadError
|
||||||
|
raise "The Vagrant Hyper-V plugin must be run within Vagrant."
|
||||||
|
end
|
||||||
|
|
||||||
|
# This is a sanity check to make sure no one is attempting to install
|
||||||
|
# this into an early Vagrant version.
|
||||||
|
if Vagrant::VERSION < "1.3.5"
|
||||||
|
raise "The Vagrant Hyper-V plugin is only compatible with Vagrant 1.3+"
|
||||||
|
end
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
class Plugin < Vagrant.plugin("2")
|
||||||
|
name "HyperV"
|
||||||
|
description <<-DESC
|
||||||
|
This plugin installs a provider that allows Vagrant to manage
|
||||||
|
machines in Hyper-V.
|
||||||
|
DESC
|
||||||
|
|
||||||
|
config(:hyperv, :provider) do
|
||||||
|
require_relative "config"
|
||||||
|
Config
|
||||||
|
end
|
||||||
|
|
||||||
|
provider(:hyperv, parallel: true) do
|
||||||
|
# Setup logging and i18n
|
||||||
|
# setup_logging
|
||||||
|
# setup_i18n
|
||||||
|
|
||||||
|
# Return the provider
|
||||||
|
require_relative "provider"
|
||||||
|
Provider
|
||||||
|
end
|
||||||
|
|
||||||
|
# This initializes the internationalization strings.
|
||||||
|
def self.setup_i18n
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
# This sets up our log level to be whatever VAGRANT_LOG is.
|
||||||
|
def self.setup_logging
|
||||||
|
require "log4r"
|
||||||
|
level = nil
|
||||||
|
begin
|
||||||
|
level = Log4r.const_get(ENV["VAGRANT_LOG"].upcase)
|
||||||
|
rescue NameError
|
||||||
|
# This means that the logging constant wasn't found,
|
||||||
|
# which is fine. We just keep `level` as `nil`. But
|
||||||
|
# we tell the user.
|
||||||
|
level = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
# Some constants, such as "true" resolve to booleans, so the
|
||||||
|
# above error checking doesn't catch it. This will check to make
|
||||||
|
# sure that the log level is an integer, as Log4r requires.
|
||||||
|
level = nil if !level.is_a?(Integer)
|
||||||
|
|
||||||
|
# Set the logging level on all "vagrant" namespaced
|
||||||
|
# logs as long as we have a valid level.
|
||||||
|
if level
|
||||||
|
logger = Log4r::Logger.new("vagrant_hyperv")
|
||||||
|
logger.outputters = Log4r::Outputter.stderr
|
||||||
|
logger.level = level
|
||||||
|
logger = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,61 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
require "log4r"
|
||||||
|
require "vagrant"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
class Provider < Vagrant.plugin("2", :provider)
|
||||||
|
|
||||||
|
def initialize(machine)
|
||||||
|
@machine = machine
|
||||||
|
end
|
||||||
|
|
||||||
|
def action(name)
|
||||||
|
# Attempt to get the action method from the Action class if it
|
||||||
|
# exists, otherwise return nil to show that we don't support the
|
||||||
|
# given action.
|
||||||
|
action_method = "action_#{name}"
|
||||||
|
return Action.send(action_method) if Action.respond_to?(action_method)
|
||||||
|
nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def state
|
||||||
|
# Run a custom action we define called "read_state" which does
|
||||||
|
# what it says. It puts the state in the `:machine_state_id`
|
||||||
|
# key in the environment.
|
||||||
|
env = @machine.action("read_state")
|
||||||
|
state_id = env[:machine_state_id]
|
||||||
|
|
||||||
|
# Get the short and long description
|
||||||
|
# TODO
|
||||||
|
short = "Machine's current state is #{state_id}"
|
||||||
|
long = ""
|
||||||
|
|
||||||
|
# Return the MachineState object
|
||||||
|
Vagrant::MachineState.new(state_id, short, long)
|
||||||
|
end
|
||||||
|
|
||||||
|
def to_s
|
||||||
|
id = @machine.id.nil? ? "new" : @machine.id
|
||||||
|
"Hyper-V (#{id})"
|
||||||
|
end
|
||||||
|
|
||||||
|
def ssh_info
|
||||||
|
# Run a custom action called "read_guest_ip" which does what it
|
||||||
|
# says and puts the resulting SSH info into the `:machine_ssh_info`
|
||||||
|
# key in the environment.
|
||||||
|
env = @machine.action("read_guest_ip")
|
||||||
|
if env[:machine_ssh_info]
|
||||||
|
env[:machine_ssh_info].merge!(:port => 22)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def driver
|
||||||
|
@driver ||= Driver::Base.new()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,123 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
param (
|
||||||
|
[string]$vm_id = $(throw "-vm_id is required."),
|
||||||
|
[string]$guest_ip = $(throw "-guest_ip is required."),
|
||||||
|
[string]$username = $(throw "-guest_username is required."),
|
||||||
|
[string]$password = $(throw "-guest_password is required."),
|
||||||
|
[string]$host_path = $(throw "-host_path is required."),
|
||||||
|
[string]$guest_path = $(throw "-guest_path is required.")
|
||||||
|
)
|
||||||
|
|
||||||
|
# Include the following modules
|
||||||
|
$presentDir = Split-Path -parent $PSCommandPath
|
||||||
|
$modules = @()
|
||||||
|
$modules += $presentDir + "\utils\write_messages.ps1"
|
||||||
|
forEach ($module in $modules) { . $module }
|
||||||
|
|
||||||
|
function Get-file-hash($source_path, $delimiter) {
|
||||||
|
$source_files = @()
|
||||||
|
(Get-ChildItem $source_path -rec | ForEach-Object -Process {
|
||||||
|
Get-FileHash -Path $_.FullName -Algorithm MD5 } ) |
|
||||||
|
ForEach-Object -Process {
|
||||||
|
$source_files += $_.Path.Replace($source_path, "") + $delimiter + $_.Hash
|
||||||
|
}
|
||||||
|
$source_files
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-Remote-Session($guest_ip, $username, $password) {
|
||||||
|
$secstr = convertto-securestring -AsPlainText -Force -String $password
|
||||||
|
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $secstr
|
||||||
|
New-PSSession -ComputerName $guest_ip -Credential $cred
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-remote-file-hash($source_path, $delimiter, $session) {
|
||||||
|
Invoke-Command -Session $session -ScriptBlock ${function:Get-file-hash} -ArgumentList $source_path, $delimiter
|
||||||
|
# TODO:
|
||||||
|
# Check if remote PS Scripting errors
|
||||||
|
}
|
||||||
|
|
||||||
|
function Sync-Remote-Machine($machine, $remove_files, $copy_files, $host_path, $guest_path) {
|
||||||
|
ForEach ($item in $copy_files) {
|
||||||
|
$from = $host_path + $item
|
||||||
|
$to = $guest_path + $item
|
||||||
|
# Copy VM can also take a VM object
|
||||||
|
Copy-VMFile -VM $machine -SourcePath $from -DestinationPath $to -CreateFullPath -FileSource Host -Force
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Create-Remote-Folders($empty_source_folders, $guest_path) {
|
||||||
|
ForEach ($item in $empty_source_folders) {
|
||||||
|
$new_name = $guest_path + $item
|
||||||
|
New-Item "$new_name" -type directory -Force
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function Get-Empty-folders-From-Source($host_path) {
|
||||||
|
Get-ChildItem $host_path -recurse |
|
||||||
|
Where-Object {$_.PSIsContainer -eq $True} |
|
||||||
|
Where-Object {$_.GetFiles().Count -eq 0} |
|
||||||
|
Select-Object FullName | ForEach-Object -Process {
|
||||||
|
$empty_source_folders += ($_.FullName.Replace($host_path, ""))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$delimiter = " || "
|
||||||
|
|
||||||
|
$machine = Get-VM -Id $vm_id
|
||||||
|
|
||||||
|
# FIXME: PowerShell guys please fix this.
|
||||||
|
# The below script checks for all VMIntegrationService which are not enabled
|
||||||
|
# and will enable this.
|
||||||
|
# When when all the services are enabled this throws an error.
|
||||||
|
# Enable VMIntegrationService to true
|
||||||
|
try {
|
||||||
|
Get-VM -Id $vm_id | Get-VMIntegrationService -Name "Guest Service Interface" | Enable-VMIntegrationService -Passthru
|
||||||
|
}
|
||||||
|
catch { }
|
||||||
|
|
||||||
|
$session = Get-Remote-Session $guest_ip $username $password
|
||||||
|
|
||||||
|
$source_files = Get-file-hash $host_path $delimiter
|
||||||
|
$destination_files = Get-remote-file-hash $guest_path $delimiter $session
|
||||||
|
|
||||||
|
if (!$destination_files) {
|
||||||
|
$destination_files = @()
|
||||||
|
}
|
||||||
|
if (!$source_files) {
|
||||||
|
$source_files = @()
|
||||||
|
}
|
||||||
|
|
||||||
|
# Compare source and destination files
|
||||||
|
$remove_files = @()
|
||||||
|
$copy_files = @()
|
||||||
|
|
||||||
|
|
||||||
|
Compare-Object -ReferenceObject $source_files -DifferenceObject $destination_files | ForEach-Object {
|
||||||
|
if ($_.SideIndicator -eq '=>') {
|
||||||
|
$remove_files += $_.InputObject.Split($delimiter)[0]
|
||||||
|
} else {
|
||||||
|
$copy_files += $_.InputObject.Split($delimiter)[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# Update the files to remote machine
|
||||||
|
Sync-Remote-Machine $machine $remove_files $copy_files $host_path $guest_path
|
||||||
|
|
||||||
|
# Create any empty folders which missed to sync to remote machine
|
||||||
|
$empty_source_folders = @()
|
||||||
|
$directories = Get-Empty-folders-From-Source $host_path
|
||||||
|
|
||||||
|
$result = Invoke-Command -Session $session -ScriptBlock ${function:Create-Remote-Folders} -ArgumentList $empty_source_folders, $guest_path
|
||||||
|
# Always remove the connection after Use
|
||||||
|
Remove-PSSession -Id $session.Id
|
||||||
|
|
||||||
|
$resultHash = @{
|
||||||
|
message = "OK"
|
||||||
|
}
|
||||||
|
$result = ConvertTo-Json $resultHash
|
||||||
|
Write-Output-Message $result
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
param (
|
||||||
|
[string]$vm_id = $(throw "-vm_id is required.")
|
||||||
|
)
|
||||||
|
|
||||||
|
# Include the following modules
|
||||||
|
$presentDir = Split-Path -parent $PSCommandPath
|
||||||
|
$modules = @()
|
||||||
|
$modules += $presentDir + "\utils\write_messages.ps1"
|
||||||
|
forEach ($module in $modules) { . $module }
|
||||||
|
|
||||||
|
try {
|
||||||
|
$vm = Get-VM -Id $vm_id -ErrorAction "stop"
|
||||||
|
$network = Get-VMNetworkAdapter -VM $vm
|
||||||
|
$ip_address = $network.IpAddresses[0]
|
||||||
|
$resultHash = @{
|
||||||
|
ip = "$ip_address"
|
||||||
|
}
|
||||||
|
$result = ConvertTo-Json $resultHash
|
||||||
|
Write-Output-Message $result
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Error-Message "Failed to obtain network info of VM $_"
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
param (
|
||||||
|
[string]$vm_id = $(throw "-vm_id is required.")
|
||||||
|
)
|
||||||
|
|
||||||
|
# Include the following modules
|
||||||
|
$presentDir = Split-Path -parent $PSCommandPath
|
||||||
|
$modules = @()
|
||||||
|
$modules += $presentDir + "\utils\write_messages.ps1"
|
||||||
|
forEach ($module in $modules) { . $module }
|
||||||
|
|
||||||
|
try {
|
||||||
|
$vm = Get-VM -Id $vm_id -ErrorAction "stop"
|
||||||
|
$state = $vm.state
|
||||||
|
$status = $vm.status
|
||||||
|
$resultHash = @{
|
||||||
|
state = "$state"
|
||||||
|
status = "$status"
|
||||||
|
}
|
||||||
|
$result = ConvertTo-Json $resultHash
|
||||||
|
Write-Output-Message $result
|
||||||
|
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Error-Message $_
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
# Include the following modules
|
||||||
|
$presentDir = Split-Path -parent $PSCommandPath
|
||||||
|
$modules = @()
|
||||||
|
$modules += $presentDir + "\utils\write_messages.ps1"
|
||||||
|
forEach ($module in $modules) { . $module }
|
||||||
|
|
||||||
|
try {
|
||||||
|
$hostname = $(whoami)
|
||||||
|
$ip = (Get-WmiObject -class win32_NetworkAdapterConfiguration -Filter 'ipenabled = "true"').ipaddress[0]
|
||||||
|
$resultHash = @{
|
||||||
|
host_name = "$username"
|
||||||
|
host_ip = "$ip"
|
||||||
|
}
|
||||||
|
$result = ConvertTo-Json $resultHash
|
||||||
|
Write-Output-Message $result
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Error-Message $_
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,150 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
param (
|
||||||
|
[string]$vm_xml_config = $(throw "-vm_xml_config is required."),
|
||||||
|
[string]$vhdx_path = $(throw "-vhdx_path is required.")
|
||||||
|
)
|
||||||
|
|
||||||
|
# Include the following modules
|
||||||
|
$presentDir = Split-Path -parent $PSCommandPath
|
||||||
|
$modules = @()
|
||||||
|
$modules += $presentDir + "\utils\write_messages.ps1"
|
||||||
|
forEach ($module in $modules) { . $module }
|
||||||
|
|
||||||
|
try {
|
||||||
|
[xml]$vmconfig = Get-Content -Path $vm_xml_config
|
||||||
|
|
||||||
|
$vm_name = $vmconfig.configuration.properties.name.'#text'
|
||||||
|
$processors = $vmconfig.configuration.settings.processors.count.'#text'
|
||||||
|
|
||||||
|
function Get_unique_name($name) {
|
||||||
|
Get-VM | ForEach-Object -Process {
|
||||||
|
if ($name -eq $_.Name) {
|
||||||
|
$name = $name + "_1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $name
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
$name = $vm_name
|
||||||
|
$vm_name = Get_unique_name $name
|
||||||
|
} while ($vm_name -ne $name)
|
||||||
|
|
||||||
|
$memory = (Select-Xml -xml $vmconfig -XPath "//memory").node.Bank
|
||||||
|
if ($memory.dynamic_memory_enabled."#text" -eq "True") {
|
||||||
|
$dynamicmemory = $True
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$dynamicmemory = $False
|
||||||
|
}
|
||||||
|
|
||||||
|
# Memory values need to be in bytes
|
||||||
|
$MemoryMaximumBytes = ($memory.limit."#text" -as [int]) * 1MB
|
||||||
|
$MemoryStartupBytes = ($memory.size."#text" -as [int]) * 1MB
|
||||||
|
$MemoryMinimumBytes = ($memory.reservation."#text" -as [int]) * 1MB
|
||||||
|
|
||||||
|
# Get the name of the virtual switch
|
||||||
|
$switchname = (Select-Xml -xml $vmconfig -XPath "//AltSwitchName").node."#text"
|
||||||
|
|
||||||
|
# Determine boot device
|
||||||
|
Switch ((Select-Xml -xml $vmconfig -XPath "//boot").node.device0."#text") {
|
||||||
|
"Floppy" { $bootdevice = "floppy" }
|
||||||
|
"HardDrive" { $bootdevice = "IDE" }
|
||||||
|
"Optical" { $bootdevice = "CD" }
|
||||||
|
"Network" { $bootdevice = "LegacyNetworkAdapter" }
|
||||||
|
"Default" { $bootdevice = "IDE" }
|
||||||
|
} #switch
|
||||||
|
|
||||||
|
# Define a hash map of parameter values for New-VM
|
||||||
|
|
||||||
|
$vm_params = @{
|
||||||
|
Name = $vm_name
|
||||||
|
NoVHD = $True
|
||||||
|
MemoryStartupBytes = $MemoryStartupBytes
|
||||||
|
SwitchName = $switchname
|
||||||
|
BootDevice = $bootdevice
|
||||||
|
ErrorAction = "Stop"
|
||||||
|
}
|
||||||
|
|
||||||
|
# Create the VM using the values in the hash map
|
||||||
|
|
||||||
|
$vm = New-VM @vm_params
|
||||||
|
|
||||||
|
$notes = (Select-Xml -xml $vmconfig -XPath "//notes").node.'#text'
|
||||||
|
|
||||||
|
# Set-VM parameters to configure new VM with old values
|
||||||
|
|
||||||
|
$more_vm_params = @{
|
||||||
|
ProcessorCount = $processors
|
||||||
|
MemoryStartupBytes = $MemoryStartupBytes
|
||||||
|
}
|
||||||
|
|
||||||
|
If ($dynamicmemory) {
|
||||||
|
$more_vm_params.Add("DynamicMemory",$True)
|
||||||
|
$more_vm_params.Add("MemoryMinimumBytes",$MemoryMinimumBytes)
|
||||||
|
$more_vm_params.Add("MemoryMaximumBytes", $MemoryMaximumBytes)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$more_vm_params.Add("StaticMemory",$True)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($notes) {
|
||||||
|
$more_vm_params.Add("Notes",$notes)
|
||||||
|
}
|
||||||
|
|
||||||
|
# Set the values on the VM
|
||||||
|
$vm | Set-VM @more_vm_params -Passthru
|
||||||
|
|
||||||
|
# Add drives to the virtual machine
|
||||||
|
$controllers = Select-Xml -xml $vmconfig -xpath "//*[starts-with(name(.),'controller')]"
|
||||||
|
# A regular expression pattern to pull the number from controllers
|
||||||
|
[regex]$rx="\d"
|
||||||
|
|
||||||
|
foreach ($controller in $controllers) {
|
||||||
|
$node = $controller.Node
|
||||||
|
# Check for SCSI
|
||||||
|
if ($node.ParentNode.ChannelInstanceGuid) {
|
||||||
|
$ControllerType = "SCSI"
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$ControllerType = "IDE"
|
||||||
|
}
|
||||||
|
|
||||||
|
$drives = $node.ChildNodes | where {$_.pathname."#text"}
|
||||||
|
foreach ($drive in $drives) {
|
||||||
|
#if drive type is ISO then set DVD Drive accordingly
|
||||||
|
$driveType = $drive.type."#text"
|
||||||
|
|
||||||
|
$addDriveParam = @{
|
||||||
|
ControllerNumber = $rx.Match($controller.node.name).value
|
||||||
|
Path = $vhdx_path
|
||||||
|
}
|
||||||
|
if ($drive.pool_id."#text") {
|
||||||
|
$ResourcePoolName = $drive.pool_id."#text"
|
||||||
|
$addDriveParam.Add("ResourcePoolname",$ResourcePoolName)
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($drivetype -eq 'VHD') {
|
||||||
|
$addDriveParam.add("ControllerType",$ControllerType)
|
||||||
|
$vm | Add-VMHardDiskDrive @AddDriveparam
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$vm_id = (Get-VM $vm_name).id.guid
|
||||||
|
$resultHash = @{
|
||||||
|
name = $vm_name
|
||||||
|
id = $vm_id
|
||||||
|
}
|
||||||
|
$result = ConvertTo-Json $resultHash
|
||||||
|
Write-Output-Message $result
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Error-Message $_
|
||||||
|
return
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
param (
|
||||||
|
[string]$share_name = $(throw "-share_name is required."),
|
||||||
|
[string]$guest_path = $(throw "-guest_path is required."),
|
||||||
|
[string]$guest_ip = $(throw "-guest_ip is required."),
|
||||||
|
[string]$username = $(throw "-username is required."),
|
||||||
|
[string]$password = $(throw "-password is required."),
|
||||||
|
[string]$host_ip = $(throw "-host_ip is required."),
|
||||||
|
[string]$host_share_username = $(throw "-host_share_username is required."),
|
||||||
|
[string]$host_share_password = $(throw "-host_share_password is required.")
|
||||||
|
)
|
||||||
|
|
||||||
|
# Include the following modules
|
||||||
|
$presentDir = Split-Path -parent $PSCommandPath
|
||||||
|
$modules = @()
|
||||||
|
$modules += $presentDir + "\utils\create_session.ps1"
|
||||||
|
$modules += $presentDir + "\utils\write_messages.ps1"
|
||||||
|
|
||||||
|
forEach ($module in $modules) { . $module }
|
||||||
|
|
||||||
|
try {
|
||||||
|
function Mount-File($share_name, $guest_path, $host_path, $host_share_username, $host_share_password) {
|
||||||
|
try {
|
||||||
|
# TODO: Check for folder exist.
|
||||||
|
# Use net use and prompt for password
|
||||||
|
$guest_path = $guest_path.replace("/", "\")
|
||||||
|
# Map a network drive to the guest machine
|
||||||
|
$result = net use * $host_path /user:$host_share_username $host_share_password /persistent:yes
|
||||||
|
$mapped_drive = (($result -match "\w:") -split (" "))[1]
|
||||||
|
Write-Host cmd /c mklink /d $guest_path $mapped_drive
|
||||||
|
# If a folder exist remove it.
|
||||||
|
if (Test-Path $guest_path) {
|
||||||
|
$junction = Get-Item $guest_path
|
||||||
|
$junction.Delete()
|
||||||
|
}
|
||||||
|
cmd /c mklink /d $guest_path $mapped_drive
|
||||||
|
} catch {
|
||||||
|
return $_
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = Create-Remote-Session $guest_ip $username $password
|
||||||
|
|
||||||
|
if (!$response["session"] -and $response["error"]) {
|
||||||
|
Write-Error-Message $response["error"]
|
||||||
|
return
|
||||||
|
}
|
||||||
|
$host_path = "\\$host_ip\$share_name"
|
||||||
|
$host_share_username = "$host_ip\$host_share_username"
|
||||||
|
$result = Invoke-Command -Session $response["session"] -ScriptBlock ${function:Mount-File} -ArgumentList $share_name, $guest_path, $host_path, $host_share_username, $host_share_password -ErrorAction "stop"
|
||||||
|
Remove-PSSession -Id $response["session"].Id
|
||||||
|
Write-Error-Message $result
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Error-Message "Failed to mount files VM $_"
|
||||||
|
return
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
param (
|
||||||
|
[string]$path = $(throw "-path is required."),
|
||||||
|
[string]$share_name = $(throw "-share_name is required."),
|
||||||
|
[string]$host_share_username = $(throw "-host_share_username is required")
|
||||||
|
)
|
||||||
|
|
||||||
|
# Include the following modules
|
||||||
|
$presentDir = Split-Path -parent $PSCommandPath
|
||||||
|
$modules = @()
|
||||||
|
$modules += $presentDir + "\utils\write_messages.ps1"
|
||||||
|
forEach ($module in $modules) { . $module }
|
||||||
|
|
||||||
|
try {
|
||||||
|
# See all available shares and check alert user for existing / conflicting share name
|
||||||
|
$shared_folders = net share
|
||||||
|
$reg = "$share_name(\s+)$path(\s)"
|
||||||
|
$existing_share = $shared_folders -Match $reg
|
||||||
|
if ($existing_share) {
|
||||||
|
# Always clear the existing share name and create a new one
|
||||||
|
net share $share_name /delete /y
|
||||||
|
}
|
||||||
|
|
||||||
|
$computer_name = $(Get-WmiObject Win32_Computersystem).name
|
||||||
|
$grant_permission = "$computer_name\$host_share_username,Full"
|
||||||
|
$result = net share $share_name=$path /unlimited /GRANT:$grant_permission
|
||||||
|
if ($result -Match "$share_name was shared successfully.") {
|
||||||
|
$resultHash = @{
|
||||||
|
message = "OK"
|
||||||
|
}
|
||||||
|
$result = ConvertTo-Json $resultHash
|
||||||
|
Write-Output-Message $result
|
||||||
|
} else {
|
||||||
|
$reg = "^$share_name(\s+)"
|
||||||
|
$existing_share = $shared_folders -Match $reg
|
||||||
|
Write-Error-Message "IGNORING Conflicting share name, A share name already exist $existing_share"
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
Write-Error-Message $_
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
param (
|
||||||
|
[string]$vm_id = $(throw "-vm_id is required.")
|
||||||
|
)
|
||||||
|
|
||||||
|
# Include the following modules
|
||||||
|
$presentDir = Split-Path -parent $PSCommandPath
|
||||||
|
$modules = @()
|
||||||
|
$modules += $presentDir + "\utils\write_messages.ps1"
|
||||||
|
forEach ($module in $modules) { . $module }
|
||||||
|
|
||||||
|
try {
|
||||||
|
$vm = Get-VM -Id $vm_id -ErrorAction "stop"
|
||||||
|
Start-VM $vm
|
||||||
|
$state = $vm.state
|
||||||
|
$status = $vm.status
|
||||||
|
$name = $vm.name
|
||||||
|
$resultHash = @{
|
||||||
|
state = "$state"
|
||||||
|
status = "$status"
|
||||||
|
name = "$name"
|
||||||
|
}
|
||||||
|
$result = ConvertTo-Json $resultHash
|
||||||
|
Write-Output-Message $result
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Error-Message "Failed to start a VM $_"
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
param (
|
||||||
|
[string]$vm_id = $(throw "-vm_id is required.")
|
||||||
|
)
|
||||||
|
|
||||||
|
# Include the following modules
|
||||||
|
$presentDir = Split-Path -parent $PSCommandPath
|
||||||
|
$modules = @()
|
||||||
|
$modules += $presentDir + "\utils\write_messages.ps1"
|
||||||
|
forEach ($module in $modules) { . $module }
|
||||||
|
|
||||||
|
try {
|
||||||
|
$vm = Get-VM -Id $vm_id -ErrorAction stop
|
||||||
|
# Shuts down virtual machine regardless of any unsaved application data
|
||||||
|
Stop-VM $vm -Force
|
||||||
|
$state = $vm.state
|
||||||
|
$status = $vm.status
|
||||||
|
$resultHash = @{
|
||||||
|
state = "$state"
|
||||||
|
status = "$status"
|
||||||
|
}
|
||||||
|
$result = ConvertTo-Json $resultHash
|
||||||
|
Write-Output-Message $result
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Error-Message "Failed to stop a VM $_"
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function Get-Remote-Session($guest_ip, $username, $password) {
|
||||||
|
$secstr = convertto-securestring -AsPlainText -Force -String $password
|
||||||
|
$cred = new-object -typename System.Management.Automation.PSCredential -argumentlist $username, $secstr
|
||||||
|
New-PSSession -ComputerName $guest_ip -Credential $cred -ErrorAction "stop"
|
||||||
|
}
|
||||||
|
|
||||||
|
function Create-Remote-Session($guest_ip, $username, $password) {
|
||||||
|
$count = 0
|
||||||
|
$session_error = ""
|
||||||
|
$session = ""
|
||||||
|
do {
|
||||||
|
$count++
|
||||||
|
try {
|
||||||
|
$session = Get-Remote-Session $guest_ip $username $password
|
||||||
|
$session_error = ""
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Start-Sleep -s 1
|
||||||
|
$session_error = $_
|
||||||
|
$session = ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (!$session -and $count -lt 20)
|
||||||
|
|
||||||
|
return @{
|
||||||
|
session = $session
|
||||||
|
error = $session_error
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
function Write-Error-Message($message) {
|
||||||
|
$error_message = @{
|
||||||
|
error = "$message"
|
||||||
|
}
|
||||||
|
Write-Host "===Begin-Error==="
|
||||||
|
$result = ConvertTo-json $error_message
|
||||||
|
Write-Host $result
|
||||||
|
Write-Host "===End-Error==="
|
||||||
|
}
|
||||||
|
|
||||||
|
function Write-Output-Message($message) {
|
||||||
|
Write-Host "===Begin-Output==="
|
||||||
|
Write-Host $message
|
||||||
|
Write-Host "===End-Output==="
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||||
|
# All Rights Reserved. Licensed under the MIT License.
|
||||||
|
#--------------------------------------------------------------------------
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
VERSION = "0.0.1"
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue