vagrant-azure 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/Gemfile +19 -0
- data/LICENSE +4 -0
- data/README.md +9 -0
- data/Rakefile +14 -0
- data/lib/vagrant-azure.rb +24 -0
- data/lib/vagrant-azure/action.rb +249 -0
- data/lib/vagrant-azure/action/connect_azure.rb +41 -0
- data/lib/vagrant-azure/action/provision.rb +40 -0
- data/lib/vagrant-azure/action/rdp.rb +62 -0
- data/lib/vagrant-azure/action/read_ssh_info.rb +51 -0
- data/lib/vagrant-azure/action/read_state.rb +46 -0
- data/lib/vagrant-azure/action/restart_vm.rb +27 -0
- data/lib/vagrant-azure/action/run_instance.rb +111 -0
- data/lib/vagrant-azure/action/start_instance.rb +35 -0
- data/lib/vagrant-azure/action/stop_instance.rb +38 -0
- data/lib/vagrant-azure/action/terminate_instance.rb +34 -0
- data/lib/vagrant-azure/action/wait_for_state.rb +49 -0
- data/lib/vagrant-azure/command/rdp/command.rb +21 -0
- data/lib/vagrant-azure/config.rb +147 -0
- data/lib/vagrant-azure/driver.rb +79 -0
- data/lib/vagrant-azure/plugin.rb +87 -0
- data/lib/vagrant-azure/provider.rb +70 -0
- data/lib/vagrant-azure/provisioner/puppet.rb +109 -0
- data/lib/vagrant-azure/scripts/check_winrm.ps1 +41 -0
- data/lib/vagrant-azure/scripts/export_vm.ps1 +31 -0
- data/lib/vagrant-azure/scripts/file_sync.ps1 +145 -0
- data/lib/vagrant-azure/scripts/host_info.ps1 +25 -0
- data/lib/vagrant-azure/scripts/hyperv_manager.ps1 +36 -0
- data/lib/vagrant-azure/scripts/run_in_remote.ps1 +32 -0
- data/lib/vagrant-azure/scripts/upload_file.ps1 +95 -0
- data/lib/vagrant-azure/scripts/utils/create_session.ps1 +34 -0
- data/lib/vagrant-azure/scripts/utils/write_messages.ps1 +18 -0
- data/lib/vagrant-azure/version.rb +10 -0
- data/locales/en.yml +14 -0
- data/vagrant-azure.gemspec +58 -0
- metadata +167 -0
@@ -0,0 +1,79 @@
|
|
1
|
+
#---------------------------------------------------------------------------
|
2
|
+
# Copyright (c) Microsoft Open Technologies, Inc.
|
3
|
+
# All Rights Reserved. Licensed under the Apache 2.0 License.
|
4
|
+
#--------------------------------------------------------------------------
|
5
|
+
require 'json'
|
6
|
+
require "#{Vagrant::source_root}/plugins/providers/hyperv/driver"
|
7
|
+
|
8
|
+
module VagrantPlugins
|
9
|
+
module WinAzure
|
10
|
+
class Driver < VagrantPlugins::HyperV::Driver
|
11
|
+
def initialize(machine)
|
12
|
+
@id = machine.id
|
13
|
+
@machine = machine
|
14
|
+
end
|
15
|
+
|
16
|
+
def ssh_info
|
17
|
+
@ssh_info ||= @machine.provider.winrm_info
|
18
|
+
@ssh_info[:username] ||= @machine.config.ssh.username
|
19
|
+
@ssh_info[:password] ||= @machine.config.ssh.password
|
20
|
+
@ssh_info
|
21
|
+
end
|
22
|
+
|
23
|
+
def remote_credentials
|
24
|
+
@remote_credentials ||= {
|
25
|
+
guest_ip: ssh_info[:host],
|
26
|
+
guest_port: ssh_info[:port],
|
27
|
+
username: ssh_info[:username],
|
28
|
+
password: ssh_info[:password]
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
def run_remote_ps(command, &block)
|
33
|
+
options = remote_credentials.merge(command: command)
|
34
|
+
script_path = local_script_path('run_in_remote.ps1')
|
35
|
+
|
36
|
+
ps_options = []
|
37
|
+
|
38
|
+
options.each do |key, value|
|
39
|
+
ps_options << "-#{key}"
|
40
|
+
ps_options << "'#{value}'"
|
41
|
+
end
|
42
|
+
|
43
|
+
ps_options << '-ErrorAction' << 'Stop'
|
44
|
+
opts = { notify: [:stdout, :stderr, :stdin] }
|
45
|
+
Vagrant::Util::PowerShell.execute(
|
46
|
+
script_path,
|
47
|
+
*ps_options,
|
48
|
+
**opts,
|
49
|
+
&block
|
50
|
+
)
|
51
|
+
end
|
52
|
+
|
53
|
+
def upload(from, to)
|
54
|
+
options = {
|
55
|
+
host_path: windows_path(from),
|
56
|
+
guest_path: windows_path(to)
|
57
|
+
}.merge(remote_credentials)
|
58
|
+
|
59
|
+
script_path = local_script_path('upload_file.ps1')
|
60
|
+
execute(script_path, options)
|
61
|
+
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
|
65
|
+
def local_script_path(path)
|
66
|
+
lib_path = Pathname.new(File.expand_path('../scripts', __FILE__))
|
67
|
+
windows_path(lib_path.join(path).to_s)
|
68
|
+
end
|
69
|
+
|
70
|
+
def windows_path(path)
|
71
|
+
if path
|
72
|
+
path = path.gsub('/', "\\")
|
73
|
+
path = "c:#{path}" if path =~ /^\\/
|
74
|
+
end
|
75
|
+
path
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
#--------------------------------------------------------------------------
|
2
|
+
# Copyright (c) Microsoft Open Technologies, Inc.
|
3
|
+
# All Rights Reserved. Licensed under the Apache 2.0 License.
|
4
|
+
#--------------------------------------------------------------------------
|
5
|
+
begin
|
6
|
+
require 'vagrant'
|
7
|
+
rescue LoadError
|
8
|
+
raise 'The Vagrant Azure plugin must be run within Vagrant.'
|
9
|
+
end
|
10
|
+
|
11
|
+
# This is a sanity check to make sure no one is attempting to install this into
|
12
|
+
# an early Vagrant version.
|
13
|
+
if Vagrant::VERSION < '1.2.0'
|
14
|
+
raise 'The Vagrant Azure plugin is only compatible with Vagrant 1.2+'
|
15
|
+
end
|
16
|
+
|
17
|
+
module VagrantPlugins
|
18
|
+
module WinAzure
|
19
|
+
class Plugin < Vagrant.plugin('2')
|
20
|
+
name 'azure'
|
21
|
+
description <<-DESC
|
22
|
+
This plugin installs a provider that allows Vagrant to manage
|
23
|
+
machines in Windows Azure.
|
24
|
+
DESC
|
25
|
+
|
26
|
+
config(:azure, :provider) do
|
27
|
+
require_relative 'config'
|
28
|
+
Config
|
29
|
+
end
|
30
|
+
|
31
|
+
provider(:azure, parallel: true) do
|
32
|
+
# Setup logging and i18n
|
33
|
+
setup_logging
|
34
|
+
setup_i18n
|
35
|
+
|
36
|
+
# Return the provider
|
37
|
+
require_relative 'provider'
|
38
|
+
Provider
|
39
|
+
end
|
40
|
+
|
41
|
+
command 'rdp' do
|
42
|
+
require_relative 'command/rdp/command'
|
43
|
+
Command
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.setup_i18n
|
47
|
+
I18n.load_path << File.expand_path(
|
48
|
+
'locales/en.yml',
|
49
|
+
WinAzure.source_root
|
50
|
+
)
|
51
|
+
I18n.load_path << File.expand_path(
|
52
|
+
'templates/locales/providers_hyperv.yml',
|
53
|
+
Vagrant.source_root
|
54
|
+
)
|
55
|
+
I18n.reload!
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.setup_logging
|
59
|
+
require 'log4r'
|
60
|
+
|
61
|
+
level = nil
|
62
|
+
begin
|
63
|
+
level = Log4r.const_get(ENV['VAGRANT_LOG'].upcase)
|
64
|
+
rescue NameError
|
65
|
+
# This means that the logging constant wasn't found,
|
66
|
+
# which is fine. We just keep `level` as `nil`. But
|
67
|
+
# we tell the user.
|
68
|
+
level = nil
|
69
|
+
end
|
70
|
+
|
71
|
+
# Some constants, such as "true" resolve to booleans, so the
|
72
|
+
# above error checking doesn't catch it. This will check to make
|
73
|
+
# sure that the log level is an integer, as Log4r requires.
|
74
|
+
level = nil if !level.is_a?(Integer)
|
75
|
+
|
76
|
+
# Set the logging level on all "vagrant" namespaced logs as long as
|
77
|
+
# we have a valid level
|
78
|
+
if level
|
79
|
+
logger = Log4r::Logger.new("vagrant_azure")
|
80
|
+
logger.outputters = Log4r::Outputter.stderr
|
81
|
+
logger.level = level
|
82
|
+
logger = nil
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
#--------------------------------------------------------------------------
|
2
|
+
# Copyright (c) Microsoft Open Technologies, Inc.
|
3
|
+
# All Rights Reserved. Licensed under the Apache 2.0 License.
|
4
|
+
#--------------------------------------------------------------------------
|
5
|
+
require 'log4r'
|
6
|
+
require 'vagrant'
|
7
|
+
|
8
|
+
module VagrantPlugins
|
9
|
+
module WinAzure
|
10
|
+
class Provider < Vagrant.plugin('2', :provider)
|
11
|
+
attr_reader :driver
|
12
|
+
|
13
|
+
def initialize(machine)
|
14
|
+
@machine = machine
|
15
|
+
|
16
|
+
# Load the driver
|
17
|
+
machine_id_changed
|
18
|
+
end
|
19
|
+
|
20
|
+
def action(name)
|
21
|
+
# Attempt to get the action method from the Action class if it
|
22
|
+
# exists, otherwise return nil to show that we don't support the
|
23
|
+
# given action.
|
24
|
+
action_method = "action_#{name}"
|
25
|
+
return Action.send(action_method) if Action.respond_to?(action_method)
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def machine_id_changed
|
30
|
+
@driver = Driver.new(@machine)
|
31
|
+
end
|
32
|
+
|
33
|
+
def ssh_info
|
34
|
+
# Run a custom action called "read_ssh_info" which does what it
|
35
|
+
# says and puts the resulting SSH info into the `:machine_ssh_info`
|
36
|
+
# key in the environment.
|
37
|
+
env = @machine.action('read_ssh_info')
|
38
|
+
env[:machine_ssh_info]
|
39
|
+
end
|
40
|
+
|
41
|
+
def rdp_info
|
42
|
+
env = @machine.action('read_rdp_info')
|
43
|
+
env[:machine_ssh_info]
|
44
|
+
end
|
45
|
+
|
46
|
+
def winrm_info
|
47
|
+
env = @machine.action('read_winrm_info')
|
48
|
+
env[:machine_ssh_info]
|
49
|
+
end
|
50
|
+
|
51
|
+
def state
|
52
|
+
# Run a custom action we define called "read_state" which does what it
|
53
|
+
# says. It puts the state in the `:machine_state_id` key in the env
|
54
|
+
env = @machine.action('read_state')
|
55
|
+
state_id = env[:machine_state_id]
|
56
|
+
|
57
|
+
short = "Machine's current state is #{state_id}"
|
58
|
+
long = ""
|
59
|
+
|
60
|
+
# Return the MachineState object
|
61
|
+
Vagrant::MachineState.new(state_id, short, long)
|
62
|
+
end
|
63
|
+
|
64
|
+
def to_s
|
65
|
+
id = @machine.id.nil? ? 'new' : @machine.id
|
66
|
+
"Azure (#{id})"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
#---------------------------------------------------------------------------
|
2
|
+
# Copyright (c) Microsoft Open Technologies, Inc.
|
3
|
+
# All Rights Reserved. Licensed under the Apache 2.0 License.
|
4
|
+
#---------------------------------------------------------------------------
|
5
|
+
require 'fileutils'
|
6
|
+
require 'tempfile'
|
7
|
+
|
8
|
+
module VagrantPlugins
|
9
|
+
module WinAzure
|
10
|
+
module Provisioner
|
11
|
+
class Puppet
|
12
|
+
attr_reader :provisioner
|
13
|
+
|
14
|
+
def initialize(env)
|
15
|
+
@env = env
|
16
|
+
@provisioner = env[:provisioner]
|
17
|
+
end
|
18
|
+
|
19
|
+
def provision_for_windows
|
20
|
+
options = [config.options].flatten
|
21
|
+
@module_paths = provisioner.instance_variable_get('@module_paths')
|
22
|
+
@hiera_config_path = provisioner.instance_variable_get(
|
23
|
+
'@hiera_config_path'
|
24
|
+
)
|
25
|
+
@manifest_file = provisioner.instance_variable_get('@manifest_file')
|
26
|
+
|
27
|
+
# Copy the manifests directory to the guest
|
28
|
+
if config.manifests_path[0].to_sym == :host
|
29
|
+
@env[:machine].provider.driver.upload(
|
30
|
+
File.expand_path(
|
31
|
+
config.manifests_path[1], @env[:machine].env.root_path
|
32
|
+
),
|
33
|
+
provisioner.manifests_guest_path
|
34
|
+
)
|
35
|
+
end
|
36
|
+
|
37
|
+
# Copy the module paths to the guest
|
38
|
+
@module_paths.each do |from, to|
|
39
|
+
@env[:machine].provider.driver.upload(from.to_s, to)
|
40
|
+
end
|
41
|
+
|
42
|
+
module_paths = @module_paths.map { |_, to| to }
|
43
|
+
unless module_paths.empty?
|
44
|
+
# Prepend the default module path
|
45
|
+
module_paths.unshift('/ProgramData/PuppetLabs/puppet/etc/modules')
|
46
|
+
|
47
|
+
# Add the command line switch to add the module path
|
48
|
+
options << "--modulepath \"#{module_paths.join(':')}\""
|
49
|
+
end
|
50
|
+
|
51
|
+
if @hiera_config_path
|
52
|
+
options << "--hiera_config=#{@hiera_config_path}"
|
53
|
+
|
54
|
+
# Upload Hiera configuration if we have it
|
55
|
+
local_hiera_path = File.expand_path(
|
56
|
+
config.hiera_config_path,
|
57
|
+
@env[:machine].env.root_path
|
58
|
+
)
|
59
|
+
|
60
|
+
@env[:machine].provider.driver.upload(
|
61
|
+
local_hiera_path,
|
62
|
+
@hiera_config_path
|
63
|
+
)
|
64
|
+
end
|
65
|
+
|
66
|
+
options << "--manifestdir #{provisioner.manifests_guest_path}"
|
67
|
+
options << "--detailed-exitcodes"
|
68
|
+
options << @manifest_file
|
69
|
+
options = options.join(' ')
|
70
|
+
|
71
|
+
# Build up the custome facts if we have any
|
72
|
+
facter = ''
|
73
|
+
unless config.facter.empty?
|
74
|
+
facts = []
|
75
|
+
config.facter.each do |key, value|
|
76
|
+
facts << "FACTER_#{key}='#{value}'"
|
77
|
+
end
|
78
|
+
|
79
|
+
facter = "#{facts.join(' ')}"
|
80
|
+
end
|
81
|
+
|
82
|
+
command = "#{facter}puppet apply #{options}"
|
83
|
+
|
84
|
+
if config.working_directory
|
85
|
+
command = "cd #{config.working_directory} && #{command}"
|
86
|
+
end
|
87
|
+
|
88
|
+
@env[:ui].info I18n.t(
|
89
|
+
'vagrant_azure.provisioners.puppet.running_puppet',
|
90
|
+
manifest: config.manifest_file
|
91
|
+
)
|
92
|
+
@env[:ui].info 'Executing puppet script in Windows Azure VM'
|
93
|
+
@env[:machine].provider.driver.run_remote_ps(command) do |type, data|
|
94
|
+
# Output the data with the proper color based on the stream.
|
95
|
+
if (type == :stdout || type == :stderr)
|
96
|
+
@env[:ui].detail data
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
protected
|
102
|
+
|
103
|
+
def config
|
104
|
+
provisioner.config
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
#-------------------------------------------------------------------------
|
2
|
+
# Copyright (c) Microsoft Open Technologies, Inc.
|
3
|
+
# All Rights Reserved. Licensed under the Apache 2.0 License.
|
4
|
+
#--------------------------------------------------------------------------
|
5
|
+
param (
|
6
|
+
[string]$guest_ip = $(throw "-guest_ip is required."),
|
7
|
+
[string]$username = $(throw "-guest_username is required."),
|
8
|
+
[string]$password = $(throw "-guest_password is required.")
|
9
|
+
)
|
10
|
+
|
11
|
+
# Include the following modules
|
12
|
+
$presentDir = Split-Path -parent $PSCommandPath
|
13
|
+
. ([System.IO.Path]::Combine($presentDir, "utils\write_messages.ps1"))
|
14
|
+
. ([System.IO.Path]::Combine($presentDir, "utils\create_session.ps1"))
|
15
|
+
|
16
|
+
try {
|
17
|
+
$response = Create-Remote-Session $guest_ip $username $password
|
18
|
+
if (!$response["session"] -and $response["error"]) {
|
19
|
+
Write-Host $response["error"]
|
20
|
+
return
|
21
|
+
}
|
22
|
+
function Remote-Execute() {
|
23
|
+
$winrm_state = ""
|
24
|
+
get-service winrm | ForEach-Object {
|
25
|
+
$winrm_state = $_.status
|
26
|
+
}
|
27
|
+
return "$winrm_state"
|
28
|
+
}
|
29
|
+
$result = Invoke-Command -Session $response["session"] -ScriptBlock ${function:Remote-Execute} -ErrorAction "stop"
|
30
|
+
$resultHash = @{
|
31
|
+
message = "$result"
|
32
|
+
}
|
33
|
+
Write-Output-Message $resultHash
|
34
|
+
} catch {
|
35
|
+
$errortHash = @{
|
36
|
+
type = "PowerShellError"
|
37
|
+
error ="Failed to copy file $_"
|
38
|
+
}
|
39
|
+
Write-Error-Message $errortHash
|
40
|
+
return
|
41
|
+
}
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#-------------------------------------------------------------------------
|
2
|
+
# Copyright (c) Microsoft Open Technologies, Inc.
|
3
|
+
# All Rights Reserved. Licensed under the Apache 2.0 License.
|
4
|
+
#--------------------------------------------------------------------------
|
5
|
+
|
6
|
+
param (
|
7
|
+
[string]$vm_id = $(throw "-vm_id is required."),
|
8
|
+
[string]$path = $(throw "-path is required.")
|
9
|
+
)
|
10
|
+
|
11
|
+
# Include the following modules
|
12
|
+
$presentDir = Split-Path -parent $PSCommandPath
|
13
|
+
. ([System.IO.Path]::Combine($presentDir, "utils\write_messages.ps1"))
|
14
|
+
|
15
|
+
|
16
|
+
# Export the Virtual Machine
|
17
|
+
try {
|
18
|
+
$vm = Get-Vm -Id $vm_id
|
19
|
+
$vm | Export-VM -Path $path -ErrorAction "stop"
|
20
|
+
$name = $vm.name
|
21
|
+
$resultHash = @{
|
22
|
+
name = "$name"
|
23
|
+
}
|
24
|
+
Write-Output-Message $resultHash
|
25
|
+
} catch {
|
26
|
+
$errortHash = @{
|
27
|
+
type = "PowerShellError"
|
28
|
+
error = "Failed to export a VM $_"
|
29
|
+
}
|
30
|
+
Write-Error-Message $errortHash
|
31
|
+
}
|
@@ -0,0 +1,145 @@
|
|
1
|
+
#-------------------------------------------------------------------------
|
2
|
+
# Copyright (c) Microsoft Open Technologies, Inc.
|
3
|
+
# All Rights Reserved. Licensed under the Apache 2.0 License.
|
4
|
+
#--------------------------------------------------------------------------
|
5
|
+
|
6
|
+
param (
|
7
|
+
[string]$vm_id = $(throw "-vm_id is required."),
|
8
|
+
[string]$guest_ip = $(throw "-guest_ip is required."),
|
9
|
+
[string]$username = $(throw "-guest_username is required."),
|
10
|
+
[string]$password = $(throw "-guest_password is required."),
|
11
|
+
[string]$host_path = $(throw "-host_path is required."),
|
12
|
+
[string]$guest_path = $(throw "-guest_path is required.")
|
13
|
+
)
|
14
|
+
|
15
|
+
# Include the following modules
|
16
|
+
$presentDir = Split-Path -parent $PSCommandPath
|
17
|
+
$modules = @()
|
18
|
+
$modules += $presentDir + "\utils\write_messages.ps1"
|
19
|
+
$modules += $presentDir + "\utils\create_session.ps1"
|
20
|
+
forEach ($module in $modules) { . $module }
|
21
|
+
|
22
|
+
function Get-file-hash($source_path, $delimiter) {
|
23
|
+
$source_files = @()
|
24
|
+
(Get-ChildItem $source_path -rec -force | ForEach-Object -Process {
|
25
|
+
Get-FileHash -Path $_.FullName -Algorithm MD5 } ) |
|
26
|
+
ForEach-Object -Process {
|
27
|
+
$source_files += $_.Path.Replace($source_path, "") + $delimiter + $_.Hash
|
28
|
+
}
|
29
|
+
$source_files
|
30
|
+
}
|
31
|
+
|
32
|
+
function Get-remote-file-hash($source_path, $delimiter, $session) {
|
33
|
+
Invoke-Command -Session $session -ScriptBlock ${function:Get-file-hash} -ArgumentList $source_path, $delimiter
|
34
|
+
# TODO:
|
35
|
+
# Check if remote PS Scripting errors
|
36
|
+
}
|
37
|
+
|
38
|
+
function Sync-Remote-Machine($machine, $remove_files, $copy_files, $host_path, $guest_path) {
|
39
|
+
ForEach ($item in $copy_files) {
|
40
|
+
$from = $host_path + $item
|
41
|
+
$to = $guest_path + $item
|
42
|
+
# Copy VM can also take a VM object
|
43
|
+
Copy-VMFile -VM $machine -SourcePath $from -DestinationPath $to -CreateFullPath -FileSource Host -Force
|
44
|
+
}
|
45
|
+
}
|
46
|
+
|
47
|
+
function Create-Remote-Folders($empty_source_folders, $guest_path) {
|
48
|
+
|
49
|
+
ForEach ($item in $empty_source_folders) {
|
50
|
+
$new_name = $guest_path + $item
|
51
|
+
New-Item "$new_name" -type directory -Force
|
52
|
+
}
|
53
|
+
}
|
54
|
+
|
55
|
+
function Create-Guest-Folder($guest_path) {
|
56
|
+
try {
|
57
|
+
if (Test-Path $guest_path) {
|
58
|
+
$junction = Get-Item $guest_path
|
59
|
+
$junction.Delete()
|
60
|
+
}
|
61
|
+
}
|
62
|
+
# Catch any [IOException]
|
63
|
+
catch {
|
64
|
+
Remove-Item "$guest_path" -Force -Recurse
|
65
|
+
}
|
66
|
+
New-Item "$guest_path" -type directory -Force
|
67
|
+
}
|
68
|
+
|
69
|
+
function Get-Empty-folders-From-Source($host_path) {
|
70
|
+
Get-ChildItem $host_path -recurse |
|
71
|
+
Where-Object {$_.PSIsContainer -eq $True} |
|
72
|
+
Where-Object {$_.GetFiles().Count -eq 0} |
|
73
|
+
Select-Object FullName | ForEach-Object -Process {
|
74
|
+
$empty_source_folders += ($_.FullName.Replace($host_path, ""))
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
$delimiter = " || "
|
79
|
+
|
80
|
+
$machine = Get-VM -Id $vm_id
|
81
|
+
|
82
|
+
# FIXME: PowerShell guys please fix this.
|
83
|
+
# The below script checks for all VMIntegrationService which are not enabled
|
84
|
+
# and will enable this.
|
85
|
+
# When when all the services are enabled this throws an error.
|
86
|
+
# Enable VMIntegrationService to true
|
87
|
+
try {
|
88
|
+
Get-VM -Id $vm_id | Get-VMIntegrationService -Name "Guest Service Interface" | Enable-VMIntegrationService -Passthru
|
89
|
+
}
|
90
|
+
catch { }
|
91
|
+
|
92
|
+
|
93
|
+
$response = Create-Remote-Session $guest_ip $username $password
|
94
|
+
if (!$response["session"] -and $response["error"]) {
|
95
|
+
$errortHash = @{
|
96
|
+
type = "PowerShellError"
|
97
|
+
error = $response["error"]
|
98
|
+
}
|
99
|
+
Write-Error-Message $errortHash
|
100
|
+
return
|
101
|
+
}
|
102
|
+
|
103
|
+
$session = $response["session"]
|
104
|
+
# Create the guest folder if not exist
|
105
|
+
$result = Invoke-Command -Session $session -ScriptBlock ${function:Create-Guest-Folder} -ArgumentList $guest_path
|
106
|
+
|
107
|
+
|
108
|
+
$source_files = Get-file-hash $host_path $delimiter
|
109
|
+
$destination_files = Get-remote-file-hash $guest_path $delimiter $session
|
110
|
+
|
111
|
+
if (!$destination_files) {
|
112
|
+
$destination_files = @()
|
113
|
+
}
|
114
|
+
if (!$source_files) {
|
115
|
+
$source_files = @()
|
116
|
+
}
|
117
|
+
|
118
|
+
# Compare source and destination files
|
119
|
+
$remove_files = @()
|
120
|
+
$copy_files = @()
|
121
|
+
|
122
|
+
|
123
|
+
Compare-Object -ReferenceObject $source_files -DifferenceObject $destination_files | ForEach-Object {
|
124
|
+
if ($_.SideIndicator -eq '=>') {
|
125
|
+
$remove_files += $_.InputObject.Split($delimiter)[0]
|
126
|
+
} else {
|
127
|
+
$copy_files += $_.InputObject.Split($delimiter)[0]
|
128
|
+
}
|
129
|
+
}
|
130
|
+
|
131
|
+
# Update the files to remote machine
|
132
|
+
Sync-Remote-Machine $machine $remove_files $copy_files $host_path $guest_path
|
133
|
+
|
134
|
+
# Create any empty folders which missed to sync to remote machine
|
135
|
+
$empty_source_folders = @()
|
136
|
+
$directories = Get-Empty-folders-From-Source $host_path
|
137
|
+
|
138
|
+
$result = Invoke-Command -Session $session -ScriptBlock ${function:Create-Remote-Folders} -ArgumentList $empty_source_folders, $guest_path
|
139
|
+
# Always remove the connection after Use
|
140
|
+
Remove-PSSession -Id $session.Id
|
141
|
+
|
142
|
+
$resultHash = @{
|
143
|
+
message = "OK"
|
144
|
+
}
|
145
|
+
Write-Output-Message $resultHash
|