зеркало из https://github.com/Azure/vagrant-azure.git
Removed add_role parameters.
added code for puppet provisioning.
This commit is contained in:
Родитель
b4ee15e5d0
Коммит
0baec895d7
|
@ -12,6 +12,9 @@ module VagrantPlugins
|
|||
autoload :Action, lib_path.join('action')
|
||||
autoload :Error, lib_path.join('errors')
|
||||
|
||||
monkey_patch = Pathname.new(File.expand_path("../vagrant-azure/monkey_patch", __FILE__))
|
||||
require monkey_patch.join("util/powershell")
|
||||
|
||||
# This returns the path to the source of this plugin.
|
||||
#
|
||||
# @return [Pathname]
|
||||
|
@ -20,4 +23,3 @@ module VagrantPlugins
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,12 +1,7 @@
|
|||
#---------------------------------------------------------------------------
|
||||
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||
# All Rights Reserved. Licensed under the Apache 2.0 License.
|
||||
#--------------------------------------------------------------------------
|
||||
|
||||
# Overriding the core vagrant class because of the lack of non-ssh based
|
||||
# communication infrastructure.
|
||||
# This will be moved to an 'rdp' communicator when the core supports it.
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
module VagrantPlugins
|
||||
module WinAzure
|
||||
module Action
|
||||
|
@ -17,14 +12,23 @@ module VagrantPlugins
|
|||
|
||||
env[:machine].id =~ /@/
|
||||
vm = env[:azure_vm_service].get_virtual_machine($`, $')
|
||||
env[:ui].info "VM OS: #{vm.os_type.to_s}"
|
||||
env[:ui].info "VM OS: #{vm.os_type.to_sym}"
|
||||
|
||||
if vm.os_type.to_s == :Windows
|
||||
if vm.os_type.to_sym == :Windows
|
||||
# Raise an error if we're not on a Windows Host.
|
||||
# Non-Windows OS will be supported once we move to WinRb/WinRm
|
||||
env[:ui].info "Is Host OS Windows?: #{Vagrant::Util::Platform.windows?}"
|
||||
raise 'Unsupported OS for Windows Provisioning' unless \
|
||||
Vagrant::Util::Platform.windows?
|
||||
env[:ui].info "Provisioning for Windows"
|
||||
|
||||
# TODO: Add Shell, Chef-solo and other provisioners
|
||||
case env[:provisioner].class.to_s
|
||||
when "VagrantPlugins::Puppet::Provisioner::Puppet"
|
||||
VagrantPlugins::WinAzure::Provisioner::Puppet.new(
|
||||
env
|
||||
).provision_for_windows
|
||||
end
|
||||
else
|
||||
env[:ui].info "Provisioning using SSH"
|
||||
env[:provisioner].provision
|
||||
|
|
|
@ -59,10 +59,31 @@ module VagrantPlugins
|
|||
options[:availability_set_name] = config.availability_set_name unless \
|
||||
config.availability_set_name.nil?
|
||||
|
||||
add_role = config.add_role
|
||||
add_role = false
|
||||
|
||||
env[:ui].info(params.inspect)
|
||||
env[:ui].info(options.inspect)
|
||||
|
||||
# Check if the cloud service exists and if yes, does it contain
|
||||
# a deployment.
|
||||
if config.cloud_service_name && !config.cloud_service_name.empty?
|
||||
begin
|
||||
cloud_service = ManagementHttpRequest.new(
|
||||
:get,
|
||||
"/services/hostedservices/#{config.cloud_service_name}?embed-detail=true"
|
||||
).call
|
||||
|
||||
deployments = cloud_service.css 'HostedService Deployments Deployment'
|
||||
|
||||
# Lets see if any deployments exist. Set add_role = true if yes.
|
||||
# We're not worried about deployment slots, because the SDK has
|
||||
# hard coded 'Production' as deployment slot and you can have only
|
||||
# one deployment per deployment slot.
|
||||
add_role = deployments.length == 1
|
||||
rescue Exception => e
|
||||
add_role = false
|
||||
end
|
||||
end
|
||||
env[:ui].info("Add Role? - #{add_role}")
|
||||
|
||||
server = env[:azure_vm_service].create_virtual_machine(
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
# All Rights Reserved. Licensed under the Apache 2.0 License.
|
||||
#--------------------------------------------------------------------------
|
||||
require 'vagrant'
|
||||
require 'azure'
|
||||
|
||||
module VagrantPlugins
|
||||
module WinAzure
|
||||
|
@ -29,7 +30,6 @@ module VagrantPlugins
|
|||
attr_accessor :vm_size
|
||||
attr_accessor :winrm_transport
|
||||
attr_accessor :availability_set_name
|
||||
attr_accessor :add_role
|
||||
|
||||
attr_accessor :state_read_timeout
|
||||
|
||||
|
@ -56,7 +56,6 @@ module VagrantPlugins
|
|||
@vm_size = UNSET_VALUE
|
||||
@winrm_transport = UNSET_VALUE
|
||||
@availability_set_name = UNSET_VALUE
|
||||
@add_role = UNSET_VALUE
|
||||
@state_read_timeout = UNSET_VALUE
|
||||
end
|
||||
|
||||
|
@ -89,9 +88,21 @@ module VagrantPlugins
|
|||
@winrm_transport = nil if @winrm_transport == UNSET_VALUE
|
||||
@availability_set_name = nil if @availability_set_name == UNSET_VALUE
|
||||
|
||||
@add_role = false if @add_role == UNSET_VALUE
|
||||
|
||||
@state_read_timeout = 360 if @state_read_timeout == UNSET_VALUE
|
||||
|
||||
# This done due to a bug in Ruby SDK - it doesn't generate a storage
|
||||
# account name if add_role = true
|
||||
if @storage_acct_name.nil? || @storage_acct_name.empty?
|
||||
@storage_acct_name = Azure::Core::Utility.random_string(
|
||||
"#{@vm_name}storage"
|
||||
).gsub(/[^0-9a-z ]/i, '').downcase[0..23]
|
||||
end
|
||||
|
||||
if @cloud_service_name.nil? || @cloud_service_name.empty?
|
||||
@cloud_service_name = Azure::Core::Utility.random_string(
|
||||
"#{@vm_name}-service-"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def merge(other)
|
||||
|
@ -122,8 +133,6 @@ module VagrantPlugins
|
|||
|
||||
# Azure Virtual Machine related validation
|
||||
errors << "vagrant_azure.vm_name.required" if @vm_name.nil?
|
||||
errors << "vagrant_azure.cloud_serivce_name.required" if \
|
||||
@cloud_service_name.nil?
|
||||
|
||||
{ "Windows Azure Provider" => errors }
|
||||
end
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
#---------------------------------------------------------------------------
|
||||
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||
# All Rights Reserved. Licensed under the Apache 2.0 License.
|
||||
#--------------------------------------------------------------------------
|
||||
require 'json'
|
||||
require "#{Vagrant::source_root}/plugins/providers/hyperv/driver"
|
||||
require 'vagrant/util/powershell'
|
||||
|
||||
module VagrantPlugins
|
||||
module WinAzure
|
||||
class Driver < VagrantPlugins::HyperV::Driver
|
||||
def initialize(machine)
|
||||
@id = machine.id
|
||||
@machine = machine
|
||||
end
|
||||
|
||||
def ssh_info
|
||||
@ssh_info ||= machine.ssh_info
|
||||
end
|
||||
|
||||
def remote_credentials
|
||||
@remote_credentials ||= {
|
||||
guest_ip: ssh_info[:host],
|
||||
username: ssh_info[:username],
|
||||
password: ssh_info[:password]
|
||||
}
|
||||
end
|
||||
|
||||
def run_remote_ps(command, &block)
|
||||
options = remote_credentials.merge(command: command)
|
||||
script_path = local_script_path('run_in_remote.ps1')
|
||||
|
||||
ps_options = []
|
||||
|
||||
options.each do |key, value|
|
||||
ps_options << "-#{key}"
|
||||
ps_options << "'#{value}'"
|
||||
end
|
||||
|
||||
ps_options << '-ErrorAction' << 'Stop'
|
||||
opts = { notify: [:stdout, :stderr, :stdin] }
|
||||
Vagrant::Util::PowerShell.execute(
|
||||
script_path,
|
||||
*ps_options,
|
||||
**opts,
|
||||
&block
|
||||
)
|
||||
end
|
||||
|
||||
def upload(from, to)
|
||||
options = {
|
||||
vm_id: vm_id,
|
||||
host_path: windows_path(from),
|
||||
guest_path: windows_path(to)
|
||||
}.merge(remote_credentials)
|
||||
|
||||
script_path = local_script_path('upload_file.ps1')
|
||||
execute(script_path, remote_credentials)
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def local_script_path(path)
|
||||
lib_path = Pathname.new(File.expand_path('../scripts', __FILE__))
|
||||
lib_path.join(path).to_s
|
||||
end
|
||||
|
||||
def windows_path(path)
|
||||
if path
|
||||
path = path.gsub('/', '\\')
|
||||
path = "c:#{path}" if path =~ /^\\/
|
||||
end
|
||||
path
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,37 @@
|
|||
#-------------------------------------------------------------------------
|
||||
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||
# All Rights Reserved. Licensed under the Apache 2.0 License.
|
||||
#--------------------------------------------------------------------------
|
||||
|
||||
require "#{Vagrant::source_root}/lib/vagrant/util/which"
|
||||
require "#{Vagrant::source_root}/lib/vagrant/util/subprocess"
|
||||
|
||||
module Vagrant
|
||||
module Util
|
||||
# Executes PowerShell scripts.
|
||||
#
|
||||
# This is primarily a convenience wrapper around Subprocess that
|
||||
# properly sets powershell flags for you.
|
||||
class PowerShell
|
||||
# Monkey patch to fix a bug with Vagrant 1.5.1.
|
||||
# https://github.com/mitchellh/vagrant/issues/3192.
|
||||
# This has been fixed in 1.5.2. by
|
||||
# https://github.com/jyggen/vagrant/commit/d7320399e2497aae9b9c3fa83d94b7210d21bfb5
|
||||
def self.execute(path, *args, **opts, &block)
|
||||
command = [
|
||||
"powershell",
|
||||
"-NoProfile",
|
||||
"-ExecutionPolicy", "Bypass",
|
||||
"&('#{path}')",
|
||||
args
|
||||
].flatten
|
||||
|
||||
# Append on the options hash since Subprocess doesn't use
|
||||
# Ruby 2.0 style options yet.
|
||||
command << opts
|
||||
|
||||
Subprocess.execute(*command, &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -4,12 +4,18 @@
|
|||
#--------------------------------------------------------------------------
|
||||
require 'log4r'
|
||||
require 'vagrant'
|
||||
require_relative 'driver'
|
||||
|
||||
module VagrantPlugins
|
||||
module WinAzure
|
||||
class Provider < Vagrant.plugin('2', :provider)
|
||||
attr_reader :driver
|
||||
|
||||
def initialize(machine)
|
||||
@machine = machine
|
||||
|
||||
# Load the driver
|
||||
machine_id_changed
|
||||
end
|
||||
|
||||
def action(name)
|
||||
|
@ -21,6 +27,10 @@ module VagrantPlugins
|
|||
nil
|
||||
end
|
||||
|
||||
def machine_id_changed
|
||||
@driver = Driver.new(@machine)
|
||||
end
|
||||
|
||||
def ssh_info
|
||||
# Run a custom action called "read_ssh_info" which does what it
|
||||
# says and puts the resulting SSH info into the `:machine_ssh_info`
|
||||
|
|
|
@ -0,0 +1,109 @@
|
|||
#---------------------------------------------------------------------------
|
||||
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||
# All Rights Reserved. Licensed under the Apache 2.0 License.
|
||||
#---------------------------------------------------------------------------
|
||||
require 'fileutils'
|
||||
require 'tempfile'
|
||||
|
||||
module VagrantPlugins
|
||||
module WinAzure
|
||||
module Provisioner
|
||||
class Puppet
|
||||
attr_reader :provisioner
|
||||
|
||||
def initialize(env)
|
||||
@env = env
|
||||
@provisioner = env[:provisioner]
|
||||
end
|
||||
|
||||
def provision_for_windows
|
||||
options = [config.options].flatten
|
||||
@module_paths = provisioner.instance_variable_get('@module_paths')
|
||||
@hiera_config_path = provisioner.instance_variable_get(
|
||||
'@hiera_config_path'
|
||||
)
|
||||
@manifest_file = provisioner.instance_variable_get('@manifest_file')
|
||||
|
||||
# Copy the manifests directory to the guest
|
||||
if config.manifests_path[0].to_sym == :host
|
||||
@env[:machine].provider.driver.upload(
|
||||
File.expand_path(
|
||||
config.manifests_path[1], @env[:machine].env.root_path
|
||||
),
|
||||
provisioner.manifests_guest_path
|
||||
)
|
||||
end
|
||||
|
||||
# Copy the module paths to the guest
|
||||
@module_paths.each do |from, to|
|
||||
@env[:machine].provider.driver.upload(from, to)
|
||||
end
|
||||
|
||||
module_paths = @module_paths.map { |_, to| to }
|
||||
unless module_paths.empty?
|
||||
# Prepend the default module path
|
||||
module_paths.unshift('/ProgramData/PuppetLabs/puppet/etc/modules')
|
||||
|
||||
# Add the command line switch to add the module path
|
||||
options << "--modulepath '#{module_paths.join(':')}'"
|
||||
end
|
||||
|
||||
if @hiera_config_path
|
||||
options << "--hiera_config=#{@hiera_config_path}"
|
||||
|
||||
# Upload Hiera configuration if we have it
|
||||
local_hiera_path = File.expand_path(
|
||||
config.hiera_config_path,
|
||||
@env[:machine].env.root_path
|
||||
)
|
||||
|
||||
@env[:machine].provider.driver.upload(
|
||||
local_hiera_path,
|
||||
@hiera_config_path
|
||||
)
|
||||
end
|
||||
|
||||
options << "--manifestdir #{provisioner.manifests_guest_path}"
|
||||
options << "--detailed-exitcodes"
|
||||
options << @manifest_file
|
||||
options = options.join(' ')
|
||||
|
||||
# Build up the custome facts if we have any
|
||||
facter = ''
|
||||
unless config.facter.empty?
|
||||
facts = []
|
||||
config.facter.each do |key, value|
|
||||
facts << "FACTER_#{key}='#{value}'"
|
||||
end
|
||||
|
||||
facter = "#{facts.join(' ')}"
|
||||
end
|
||||
|
||||
command = "#{facter}puppet apply #{options}"
|
||||
|
||||
if config.working_directory
|
||||
command = "cd #{config.working_directory} && #{command}"
|
||||
end
|
||||
|
||||
@env[:ui].info I18n.t(
|
||||
'vagrant_azure.provisioners.puppet.running_puppet',
|
||||
manifest: config.manifest_file
|
||||
)
|
||||
@env[:ui].info 'Executing puppet script in Windows Azure VM'
|
||||
@env[:machine].provdier.driver.run_remote_ps(command) do |type, data|
|
||||
# Output the data with the proper color based on the stream.
|
||||
if (type == :stdout || type == :stderr)
|
||||
@env[:ui].detail data
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def config
|
||||
provisioner.config
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,41 @@
|
|||
#-------------------------------------------------------------------------
|
||||
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||
# All Rights Reserved. Licensed under the Apache 2.0 License.
|
||||
#--------------------------------------------------------------------------
|
||||
param (
|
||||
[string]$guest_ip = $(throw "-guest_ip is required."),
|
||||
[string]$username = $(throw "-guest_username is required."),
|
||||
[string]$password = $(throw "-guest_password is required.")
|
||||
)
|
||||
|
||||
# Include the following modules
|
||||
$presentDir = Split-Path -parent $PSCommandPath
|
||||
. ([System.IO.Path]::Combine($presentDir, "utils\write_messages.ps1"))
|
||||
. ([System.IO.Path]::Combine($presentDir, "utils\create_session.ps1"))
|
||||
|
||||
try {
|
||||
$response = Create-Remote-Session $guest_ip $username $password
|
||||
if (!$response["session"] -and $response["error"]) {
|
||||
Write-Host $response["error"]
|
||||
return
|
||||
}
|
||||
function Remote-Execute() {
|
||||
$winrm_state = ""
|
||||
get-service winrm | ForEach-Object {
|
||||
$winrm_state = $_.status
|
||||
}
|
||||
return "$winrm_state"
|
||||
}
|
||||
$result = Invoke-Command -Session $response["session"] -ScriptBlock ${function:Remote-Execute} -ErrorAction "stop"
|
||||
$resultHash = @{
|
||||
message = "$result"
|
||||
}
|
||||
Write-Output-Message $resultHash
|
||||
} catch {
|
||||
$errortHash = @{
|
||||
type = "PowerShellError"
|
||||
error ="Failed to copy file $_"
|
||||
}
|
||||
Write-Error-Message $errortHash
|
||||
return
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
#-------------------------------------------------------------------------
|
||||
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||
# All Rights Reserved. Licensed under the Apache 2.0 License.
|
||||
#--------------------------------------------------------------------------
|
||||
|
||||
param (
|
||||
[string]$vm_id = $(throw "-vm_id is required."),
|
||||
[string]$path = $(throw "-path is required.")
|
||||
)
|
||||
|
||||
# Include the following modules
|
||||
$presentDir = Split-Path -parent $PSCommandPath
|
||||
. ([System.IO.Path]::Combine($presentDir, "utils\write_messages.ps1"))
|
||||
|
||||
|
||||
# Export the Virtual Machine
|
||||
try {
|
||||
$vm = Get-Vm -Id $vm_id
|
||||
$vm | Export-VM -Path $path -ErrorAction "stop"
|
||||
$name = $vm.name
|
||||
$resultHash = @{
|
||||
name = "$name"
|
||||
}
|
||||
Write-Output-Message $resultHash
|
||||
} catch {
|
||||
$errortHash = @{
|
||||
type = "PowerShellError"
|
||||
error = "Failed to export a VM $_"
|
||||
}
|
||||
Write-Error-Message $errortHash
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
#-------------------------------------------------------------------------
|
||||
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||
# All Rights Reserved. Licensed under the Apache 2.0 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"
|
||||
$modules += $presentDir + "\utils\create_session.ps1"
|
||||
forEach ($module in $modules) { . $module }
|
||||
|
||||
function Get-file-hash($source_path, $delimiter) {
|
||||
$source_files = @()
|
||||
(Get-ChildItem $source_path -rec -force | 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-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 Create-Guest-Folder($guest_path) {
|
||||
try {
|
||||
if (Test-Path $guest_path) {
|
||||
$junction = Get-Item $guest_path
|
||||
$junction.Delete()
|
||||
}
|
||||
}
|
||||
# Catch any [IOException]
|
||||
catch {
|
||||
Remove-Item "$guest_path" -Force -Recurse
|
||||
}
|
||||
New-Item "$guest_path" -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 { }
|
||||
|
||||
|
||||
$response = Create-Remote-Session $guest_ip $username $password
|
||||
if (!$response["session"] -and $response["error"]) {
|
||||
$errortHash = @{
|
||||
type = "PowerShellError"
|
||||
error = $response["error"]
|
||||
}
|
||||
Write-Error-Message $errortHash
|
||||
return
|
||||
}
|
||||
|
||||
$session = $response["session"]
|
||||
# Create the guest folder if not exist
|
||||
$result = Invoke-Command -Session $session -ScriptBlock ${function:Create-Guest-Folder} -ArgumentList $guest_path
|
||||
|
||||
|
||||
$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"
|
||||
}
|
||||
Write-Output-Message $resultHash
|
|
@ -0,0 +1,25 @@
|
|||
#-------------------------------------------------------------------------
|
||||
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||
# All Rights Reserved. Licensed under the Apache 2.0 License.
|
||||
#--------------------------------------------------------------------------
|
||||
|
||||
# Include the following modules
|
||||
$presentDir = Split-Path -parent $PSCommandPath
|
||||
. ([System.IO.Path]::Combine($presentDir, "utils\write_messages.ps1"))
|
||||
|
||||
try {
|
||||
$hostname = $(whoami)
|
||||
$ip = (Get-WmiObject -class win32_NetworkAdapterConfiguration -Filter 'ipenabled = "true"').ipaddress[0]
|
||||
$resultHash = @{
|
||||
host_name = "$username"
|
||||
host_ip = "$ip"
|
||||
}
|
||||
Write-Output-Message $resultHash
|
||||
}
|
||||
catch {
|
||||
$errortHash = @{
|
||||
type = "PowerShellError"
|
||||
error = "$_"
|
||||
}
|
||||
Write-Error-Message $errortHash
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
#-------------------------------------------------------------------------
|
||||
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||
# All Rights Reserved. Licensed under the Apache 2.0 License.
|
||||
#--------------------------------------------------------------------------
|
||||
|
||||
param (
|
||||
[string]$vm_id = $(throw "-vm_id is required."),
|
||||
[string]$command = ""
|
||||
)
|
||||
|
||||
# Include the following modules
|
||||
$presentDir = Split-Path -parent $PSCommandPath
|
||||
. ([System.IO.Path]::Combine($presentDir, "utils\write_messages.ps1"))
|
||||
|
||||
try {
|
||||
$vm = Get-VM -Id $vm_id -ErrorAction "stop"
|
||||
switch ($command) {
|
||||
"start" { Start-VM $vm }
|
||||
"stop" { Stop-VM $vm }
|
||||
"suspend" { Suspend-VM $vm }
|
||||
"resume" { Resume-VM $vm }
|
||||
}
|
||||
|
||||
$state = $vm.state
|
||||
$status = $vm.status
|
||||
$name = $vm.name
|
||||
} catch [Microsoft.HyperV.PowerShell.VirtualizationOperationFailedException] {
|
||||
$state = "not_created"
|
||||
$status = "Not Created"
|
||||
}
|
||||
$resultHash = @{
|
||||
state = "$state"
|
||||
status = "$status"
|
||||
name = "$name"
|
||||
}
|
||||
Write-Output-Message $resultHash
|
|
@ -0,0 +1,31 @@
|
|||
#-------------------------------------------------------------------------
|
||||
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||
# All Rights Reserved. Licensed under the Apache 2.0 License.
|
||||
#--------------------------------------------------------------------------
|
||||
|
||||
param (
|
||||
[string]$guest_ip = $(throw "-guest_ip is required."),
|
||||
[string]$username = $(throw "-guest_username is required."),
|
||||
[string]$password = $(throw "-guest_password is required."),
|
||||
[string]$command = ""
|
||||
)
|
||||
|
||||
# Include the following modules
|
||||
$presentDir = Split-Path -parent $PSCommandPath
|
||||
. ([System.IO.Path]::Combine($presentDir, "utils\write_messages.ps1"))
|
||||
. ([System.IO.Path]::Combine($presentDir, "utils\create_session.ps1"))
|
||||
|
||||
try {
|
||||
$response = Create-Remote-Session $guest_ip $username $password
|
||||
if (!$response["session"] -and $response["error"]) {
|
||||
Write-Host $response["error"]
|
||||
return
|
||||
}
|
||||
function Remote-Execute($command) {
|
||||
cmd /c $command
|
||||
}
|
||||
Invoke-Command -Session $response["session"] -ScriptBlock ${function:Remote-Execute} -ArgumentList $command -ErrorAction "stop"
|
||||
} catch {
|
||||
Write-Host $_
|
||||
return
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
#-------------------------------------------------------------------------
|
||||
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||
# All Rights Reserved. Licensed under the Apache 2.0 License.
|
||||
#--------------------------------------------------------------------------
|
||||
|
||||
param (
|
||||
[string]$vm_id = $(throw "-vm_id is required."),
|
||||
[string]$host_path = $(throw "-host_path is required."),
|
||||
[string]$guest_path = $(throw "-guest_path is required."),
|
||||
[string]$guest_ip = $(throw "-guest_ip is required."),
|
||||
[string]$username = $(throw "-guest_username is required."),
|
||||
[string]$password = $(throw "-guest_password is required.")
|
||||
)
|
||||
|
||||
# Include the following modules
|
||||
$presentDir = Split-Path -parent $PSCommandPath
|
||||
. ([System.IO.Path]::Combine($presentDir, "utils\write_messages.ps1"))
|
||||
. ([System.IO.Path]::Combine($presentDir, "utils\create_session.ps1"))
|
||||
|
||||
try {
|
||||
# Enable Guest Service Interface if they are disabled
|
||||
try {
|
||||
Get-VM -Id $vm_id | Get-VMIntegrationService -Name "Guest Service Interface" | Enable-VMIntegrationService -Passthru
|
||||
}
|
||||
catch { }
|
||||
|
||||
function Upload-FIle-To-VM($host_path, $guest_path, $machine) {
|
||||
Write-Host $host_path
|
||||
Write-Host $guest_path
|
||||
Copy-VMFile -VM $machine -SourcePath $host_path -DestinationPath $guest_path -CreateFullPath -FileSource Host -Force -ErrorAction stop
|
||||
}
|
||||
|
||||
function Prepare-Guest-Folder($guest_ip, $username, $password) {
|
||||
$response = Create-Remote-Session $guest_ip $username $password
|
||||
if (!$response["session"] -and $response["error"]) {
|
||||
$errortHash = @{
|
||||
type = "PowerShellError"
|
||||
message = $response["error"]
|
||||
}
|
||||
Write-Error-Message $errorResult
|
||||
return
|
||||
}
|
||||
$session = $response["session"]
|
||||
# Create the guest folder if not exist
|
||||
$result = Invoke-Command -Session $session -ScriptBlock ${function:Create-Guest-Folder} -ArgumentList $guest_path
|
||||
}
|
||||
|
||||
function Create-Guest-Folder($guest_path) {
|
||||
try {
|
||||
if (Test-Path $guest_path) {
|
||||
# First attempt to remove a Junction drive. The fall back to removing a
|
||||
# folder
|
||||
$junction = Get-Item $guest_path
|
||||
$junction.Delete()
|
||||
}
|
||||
}
|
||||
# Catch any [IOException]
|
||||
catch {
|
||||
Remove-Item "$guest_path" -Force -Recurse
|
||||
}
|
||||
New-Item "$guest_path" -type directory -Force
|
||||
}
|
||||
|
||||
$machine = Get-VM -Id $vm_id
|
||||
# When Host path is a folder.
|
||||
# Find all files within it and copy to the Guest
|
||||
if (Test-Path $host_path -pathtype container) {
|
||||
# Open a remote PS Session with the guest
|
||||
Prepare-Guest-Folder $guest_ip $username $password
|
||||
# Copy all files from Host path to Guest Path
|
||||
Get-ChildItem $host_path -rec |
|
||||
Where-Object {$_.PSIsContainer -eq $false} |
|
||||
ForEach-Object -Process {
|
||||
$file_name = $_.Fullname.Replace($host_path, "")
|
||||
$from = $host_path + $file_name
|
||||
$to = $guest_path + $file_name
|
||||
# Write-Host $from
|
||||
# Write-Host $to
|
||||
Upload-FIle-To-VM $from $to $machine
|
||||
}
|
||||
} elseif (Test-Path $host_path) {
|
||||
Upload-FIle-To-VM $host_path $guest_path $machine
|
||||
}
|
||||
$resultHash = @{
|
||||
message = "OK"
|
||||
}
|
||||
Write-Output-Message $resultHash
|
||||
} catch {
|
||||
$errortHash = @{
|
||||
type = "PowerShellError"
|
||||
error ="Failed to copy file $_"
|
||||
}
|
||||
Write-Error-Message $errortHash
|
||||
return
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
#-------------------------------------------------------------------------
|
||||
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||
# All Rights Reserved. Licensed under the Apache 2.0 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,18 @@
|
|||
#-------------------------------------------------------------------------
|
||||
# Copyright (c) Microsoft Open Technologies, Inc.
|
||||
# All Rights Reserved. Licensed under the Apache 2.0 License.
|
||||
#--------------------------------------------------------------------------
|
||||
|
||||
function Write-Error-Message($message) {
|
||||
$result = ConvertTo-Json $message
|
||||
Write-Host "===Begin-Error==="
|
||||
Write-Host $result
|
||||
Write-Host "===End-Error==="
|
||||
}
|
||||
|
||||
function Write-Output-Message($message) {
|
||||
$result = ConvertTo-Json $message
|
||||
Write-Host "===Begin-Output==="
|
||||
Write-Host $result
|
||||
Write-Host "===End-Output==="
|
||||
}
|
Загрузка…
Ссылка в новой задаче