Skip to content

Commit ca24d60

Browse files
committed
providers/hyperv: initial commit
Initial work done by MS Open Tech
1 parent 6b17783 commit ca24d60

36 files changed

+1676
-0
lines changed

plugins/providers/hyperv/action.rb

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
#-------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Open Technologies, Inc.
3+
# All Rights Reserved. Licensed under the MIT License.
4+
#--------------------------------------------------------------------------
5+
6+
require "pathname"
7+
require "vagrant/action/builder"
8+
9+
module VagrantPlugins
10+
module HyperV
11+
module Action
12+
# Include the built-in modules so we can use them as top-level things.
13+
include Vagrant::Action::Builtin
14+
15+
def self.action_reload
16+
Vagrant::Action::Builder.new.tap do |b|
17+
b.use ConfigValidate
18+
b.use Call, IsCreated do |env, b2|
19+
if !env[:result]
20+
b2.use MessageNotCreated
21+
next
22+
end
23+
b2.use action_halt
24+
b2.use Call, WaitForState, :off, 120 do |env2, b3|
25+
if env2[:result]
26+
b3.use action_up
27+
else
28+
env2[:ui].info("Machine did not reload, Check machine's status")
29+
end
30+
end
31+
end
32+
end
33+
end
34+
35+
def self.action_halt
36+
Vagrant::Action::Builder.new.tap do |b|
37+
b.use ConfigValidate
38+
b.use Call, IsCreated do |env, b2|
39+
if !env[:result]
40+
b2.use MessageNotCreated
41+
next
42+
end
43+
b2.use StopInstance
44+
end
45+
end
46+
end
47+
48+
def self.action_start
49+
Vagrant::Action::Builder.new.tap do |b|
50+
b.use StartInstance
51+
b.use ShareFolders
52+
b.use SyncFolders
53+
end
54+
end
55+
56+
def self.action_up
57+
Vagrant::Action::Builder.new.tap do |b|
58+
b.use HandleBoxUrl
59+
b.use ConfigValidate
60+
b.use Call, IsCreated do |env1, b1|
61+
if env1[:result]
62+
b1.use Call, IsStopped do |env2, b2|
63+
if env2[:result]
64+
b2.use action_start
65+
else
66+
b2.use MessageAlreadyCreated
67+
end
68+
end
69+
else
70+
b1.use Import
71+
b1.use action_start
72+
end
73+
end
74+
end
75+
end
76+
77+
def self.action_read_state
78+
Vagrant::Action::Builder.new.tap do |b|
79+
b.use ConfigValidate
80+
b.use ReadState
81+
end
82+
end
83+
84+
def self.action_ssh
85+
Vagrant::Action::Builder.new.tap do |b|
86+
b.use ConfigValidate
87+
b.use Call, IsCreated do |env, b2|
88+
if !env[:result]
89+
b2.use MessageNotCreated
90+
next
91+
end
92+
b2.use Call, IsStopped do |env1, b3|
93+
if env1[:result]
94+
b3.use MessageNotRunning
95+
else
96+
b3.use SSHExec
97+
end
98+
end
99+
end
100+
end
101+
end
102+
103+
def self.action_read_guest_ip
104+
Vagrant::Action::Builder.new.tap do |b|
105+
b.use ConfigValidate
106+
b.use ReadGuestIP
107+
end
108+
end
109+
110+
111+
# The autoload farm
112+
action_root = Pathname.new(File.expand_path("../action", __FILE__))
113+
autoload :IsCreated, action_root.join("is_created")
114+
autoload :IsStopped, action_root.join("is_stopped")
115+
autoload :ReadState, action_root.join("read_state")
116+
autoload :Import, action_root.join("import")
117+
autoload :StartInstance, action_root.join('start_instance')
118+
autoload :StopInstance, action_root.join('stop_instance')
119+
autoload :MessageNotCreated, action_root.join('message_not_created')
120+
autoload :MessageAlreadyCreated, action_root.join('message_already_created')
121+
autoload :MessageNotRunning, action_root.join('message_not_running')
122+
autoload :SyncFolders, action_root.join('sync_folders')
123+
autoload :WaitForState, action_root.join('wait_for_state')
124+
autoload :ReadGuestIP, action_root.join('read_guest_ip')
125+
autoload :ShareFolders, action_root.join('share_folders')
126+
end
127+
end
128+
end
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
#-------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Open Technologies, Inc.
3+
# All Rights Reserved. Licensed under the MIT License.
4+
#--------------------------------------------------------------------------
5+
6+
require "log4r"
7+
module VagrantPlugins
8+
module HyperV
9+
module Action
10+
class Import
11+
def initialize(app, env)
12+
@app = app
13+
@logger = Log4r::Logger.new("vagrant::hyperv::connection")
14+
end
15+
16+
def call(env)
17+
box_directory = env[:machine].box.directory.to_s
18+
path = Pathname.new(box_directory.to_s + '/Virtual Machines')
19+
config_path = ""
20+
path.each_child do |f|
21+
config_path = f.to_s if f.extname.downcase == ".xml"
22+
end
23+
24+
path = Pathname.new(box_directory.to_s + '/Virtual Hard Disks')
25+
vhdx_path = ""
26+
path.each_child do |f|
27+
vhdx_path = f.to_s if f.extname.downcase == ".vhdx"
28+
end
29+
30+
options = {
31+
vm_xml_config: config_path.gsub("/", "\\"),
32+
vhdx_path: vhdx_path.gsub("/", "\\")
33+
}
34+
35+
env[:ui].info "Importing a Hyper-V instance"
36+
begin
37+
server = env[:machine].provider.driver.execute('import_vm.ps1', options)
38+
rescue Error::SubprocessError => e
39+
env[:ui].info e.message
40+
return
41+
end
42+
env[:ui].info "Successfully imported a VM with name #{server['name']}"
43+
env[:machine].id = server["id"]
44+
@app.call(env)
45+
end
46+
end
47+
end
48+
end
49+
end
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#-------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Open Technologies, Inc.
3+
# All Rights Reserved. Licensed under the MIT License.
4+
#--------------------------------------------------------------------------
5+
6+
require "log4r"
7+
module VagrantPlugins
8+
module HyperV
9+
module Action
10+
class IsCreated
11+
def initialize(app, env)
12+
@app = app
13+
end
14+
15+
def call(env)
16+
env[:result] = env[:machine].state.id != :not_created
17+
@app.call(env)
18+
end
19+
end
20+
end
21+
end
22+
end
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#-------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Open Technologies, Inc.
3+
# All Rights Reserved. Licensed under the MIT License.
4+
#--------------------------------------------------------------------------
5+
6+
require "log4r"
7+
module VagrantPlugins
8+
module HyperV
9+
module Action
10+
class IsStopped
11+
def initialize(app, env)
12+
@app = app
13+
end
14+
15+
def call(env)
16+
env[:result] = env[:machine].state.id == :off
17+
@app.call(env)
18+
end
19+
end
20+
end
21+
end
22+
end
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#-------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Open Technologies, Inc.
3+
# All Rights Reserved. Licensed under the MIT License.
4+
#--------------------------------------------------------------------------
5+
6+
require "log4r"
7+
module VagrantPlugins
8+
module HyperV
9+
module Action
10+
class MessageAlreadyCreated
11+
def initialize(app, env)
12+
@app = app
13+
end
14+
15+
def call(env)
16+
env[:ui].info("Machine already created")
17+
@app.call(env)
18+
end
19+
end
20+
end
21+
end
22+
end
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#-------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Open Technologies, Inc.
3+
# All Rights Reserved. Licensed under the MIT License.
4+
#--------------------------------------------------------------------------
5+
6+
require "log4r"
7+
module VagrantPlugins
8+
module HyperV
9+
module Action
10+
class MessageNotCreated
11+
def initialize(app, env)
12+
@app = app
13+
end
14+
15+
def call(env)
16+
env[:ui].info("Machine not created")
17+
@app.call(env)
18+
end
19+
end
20+
end
21+
end
22+
end
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#-------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Open Technologies, Inc.
3+
# All Rights Reserved. Licensed under the MIT License.
4+
#--------------------------------------------------------------------------
5+
6+
require "log4r"
7+
module VagrantPlugins
8+
module HyperV
9+
module Action
10+
class MessageNotRunning
11+
def initialize(app, env)
12+
@app = app
13+
end
14+
15+
def call(env)
16+
env[:ui].info("Machine is not running, Please turn it on.")
17+
@app.call(env)
18+
end
19+
end
20+
end
21+
end
22+
end
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
#-------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Open Technologies, Inc.
3+
# All Rights Reserved. Licensed under the MIT License.
4+
#--------------------------------------------------------------------------
5+
require "log4r"
6+
require "timeout"
7+
8+
module VagrantPlugins
9+
module HyperV
10+
module Action
11+
# This action reads the SSH info for the machine and puts it into the
12+
# `:machine_ssh_info` key in the environment.
13+
class ReadGuestIP
14+
def initialize(app, env)
15+
@app = app
16+
@logger = Log4r::Logger.new("vagrant::hyperv::connection")
17+
end
18+
19+
def call(env)
20+
env[:machine_ssh_info] = read_host_ip(env)
21+
@app.call(env)
22+
end
23+
24+
def read_host_ip(env)
25+
return nil if env[:machine].id.nil?
26+
# Get Network details from WMI Provider
27+
# Wait for 120 sec By then the machine should be ready
28+
host_ip = nil
29+
begin
30+
Timeout.timeout(120) do
31+
begin
32+
options = { vm_id: env[:machine].id }
33+
network_info = env[:machine].provider.driver.execute('get_network_config.ps1', options)
34+
host_ip = network_info["ip"]
35+
sleep 10 if host_ip.empty?
36+
end while host_ip.empty?
37+
end
38+
rescue Timeout::Error
39+
@logger.info("Cannot find the IP address of the virtual machine")
40+
end
41+
return { host: host_ip } unless host_ip.nil?
42+
end
43+
end
44+
end
45+
end
46+
end
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
#-------------------------------------------------------------------------
2+
# Copyright (c) Microsoft Open Technologies, Inc.
3+
# All Rights Reserved. Licensed under the MIT License.
4+
#--------------------------------------------------------------------------
5+
require "debugger"
6+
require "log4r"
7+
module VagrantPlugins
8+
module HyperV
9+
module Action
10+
class ReadState
11+
def initialize(app, env)
12+
@app = app
13+
@logger = Log4r::Logger.new("vagrant::hyperv::connection")
14+
end
15+
16+
def call(env)
17+
if env[:machine].id
18+
begin
19+
options = { vm_id: env[:machine].id }
20+
response = env[:machine].provider.driver.execute('get_vm_status.ps1', options)
21+
env[:machine_state_id] = response["state"].downcase.to_sym
22+
rescue Error::SubprocessError => e
23+
env[:machine].id = nil
24+
env[:ui].info "Could not find a machine, assuming it to be deleted or terminated."
25+
env[:machine_state_id] = :not_created
26+
end
27+
else
28+
env[:machine_state_id] = :not_created
29+
end
30+
@app.call(env)
31+
end
32+
33+
end
34+
end
35+
end
36+
end

0 commit comments

Comments
 (0)