Merge pull request #7867 from bbrala/hyperv-package
Package Hyper-V boxes
This commit is contained in:
commit
23c41f4461
|
@ -0,0 +1,51 @@
|
||||||
|
module Vagrant
|
||||||
|
module Action
|
||||||
|
module General
|
||||||
|
class PackageSetupFiles
|
||||||
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
|
||||||
|
env["package.include"] ||= []
|
||||||
|
env["package.vagrantfile"] ||= nil
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
files = {}
|
||||||
|
env["package.include"].each do |file|
|
||||||
|
source = Pathname.new(file)
|
||||||
|
dest = nil
|
||||||
|
|
||||||
|
# If the source is relative then we add the file as-is to the include
|
||||||
|
# directory. Otherwise, we copy only the file into the root of the
|
||||||
|
# include directory. Kind of strange, but seems to match what people
|
||||||
|
# expect based on history.
|
||||||
|
if source.relative?
|
||||||
|
dest = source
|
||||||
|
else
|
||||||
|
dest = source.basename
|
||||||
|
end
|
||||||
|
|
||||||
|
# Assign the mapping
|
||||||
|
files[file] = dest
|
||||||
|
end
|
||||||
|
|
||||||
|
if env["package.vagrantfile"]
|
||||||
|
# Vagrantfiles are treated special and mapped to a specific file
|
||||||
|
files[env["package.vagrantfile"]] = "_Vagrantfile"
|
||||||
|
end
|
||||||
|
|
||||||
|
# Verify the mapping
|
||||||
|
files.each do |from, _|
|
||||||
|
raise Vagrant::Errors::PackageIncludeMissing,
|
||||||
|
file: from if !File.exist?(from)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Save the mapping
|
||||||
|
env["package.files"] = files
|
||||||
|
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,37 @@
|
||||||
|
require "fileutils"
|
||||||
|
require_relative "package"
|
||||||
|
|
||||||
|
module Vagrant
|
||||||
|
module Action
|
||||||
|
module General
|
||||||
|
class PackageSetupFolders
|
||||||
|
include Vagrant::Util::Presence
|
||||||
|
|
||||||
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
env["package.output"] ||= "package.box"
|
||||||
|
env["package.directory"] ||= Dir.mktmpdir("vagrant-package-", env[:tmp_path])
|
||||||
|
|
||||||
|
# Match up a couple environmental variables so that the other parts of
|
||||||
|
# Vagrant will do the right thing.
|
||||||
|
env["export.temp_dir"] = env["package.directory"]
|
||||||
|
|
||||||
|
Vagrant::Action::General::Package.validate!(
|
||||||
|
env["package.output"], env["package.directory"])
|
||||||
|
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
|
||||||
|
def recover(env)
|
||||||
|
dir = env["package.directory"]
|
||||||
|
if File.exist?(dir)
|
||||||
|
FileUtils.rm_rf(dir)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -64,6 +64,28 @@ module VagrantPlugins
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# This action packages the virtual machine into a single box file.
|
||||||
|
def self.action_package
|
||||||
|
Vagrant::Action::Builder.new.tap do |b|
|
||||||
|
b.use CheckEnabled
|
||||||
|
b.use Call, IsState, :not_created do |env1, b2|
|
||||||
|
if env1[:result]
|
||||||
|
b2.use Message, I18n.t("vagrant_hyperv.message_not_created")
|
||||||
|
next
|
||||||
|
end
|
||||||
|
|
||||||
|
b2.use PackageSetupFolders
|
||||||
|
b2.use PackageSetupFiles
|
||||||
|
b2.use action_halt
|
||||||
|
b2.use SyncedFolderCleanup
|
||||||
|
b2.use Package
|
||||||
|
b2.use PackageVagrantfile
|
||||||
|
b2.use PackageMetadataJson
|
||||||
|
b2.use Export
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def self.action_provision
|
def self.action_provision
|
||||||
Vagrant::Action::Builder.new.tap do |b|
|
Vagrant::Action::Builder.new.tap do |b|
|
||||||
b.use ConfigValidate
|
b.use ConfigValidate
|
||||||
|
@ -261,9 +283,16 @@ module VagrantPlugins
|
||||||
|
|
||||||
# The autoload farm
|
# The autoload farm
|
||||||
action_root = Pathname.new(File.expand_path("../action", __FILE__))
|
action_root = Pathname.new(File.expand_path("../action", __FILE__))
|
||||||
|
autoload :PackageSetupFolders, action_root.join("package_setup_folders")
|
||||||
|
autoload :PackageSetupFiles, action_root.join("package_setup_files")
|
||||||
|
autoload :PackageVagrantfile, action_root.join("package_vagrantfile")
|
||||||
|
autoload :PackageMetadataJson, action_root.join("package_metadata_json")
|
||||||
|
autoload :Export, action_root.join("export")
|
||||||
|
|
||||||
autoload :CheckEnabled, action_root.join("check_enabled")
|
autoload :CheckEnabled, action_root.join("check_enabled")
|
||||||
autoload :DeleteVM, action_root.join("delete_vm")
|
autoload :DeleteVM, action_root.join("delete_vm")
|
||||||
autoload :Import, action_root.join("import")
|
autoload :Import, action_root.join("import")
|
||||||
|
autoload :Package, action_root.join("package")
|
||||||
autoload :IsWindows, action_root.join("is_windows")
|
autoload :IsWindows, action_root.join("is_windows")
|
||||||
autoload :ReadState, action_root.join("read_state")
|
autoload :ReadState, action_root.join("read_state")
|
||||||
autoload :ResumeVM, action_root.join("resume_vm")
|
autoload :ResumeVM, action_root.join("resume_vm")
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
require "fileutils"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
module Action
|
||||||
|
class Export
|
||||||
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
@env = env
|
||||||
|
|
||||||
|
@env[:ui].info @env[:machine].state.id.to_s
|
||||||
|
|
||||||
|
raise Vagrant::Errors::VMPowerOffToPackage if
|
||||||
|
@env[:machine].state.id != :off
|
||||||
|
|
||||||
|
export
|
||||||
|
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
|
||||||
|
def export
|
||||||
|
@env[:ui].info I18n.t("vagrant.actions.vm.export.exporting")
|
||||||
|
@env[:machine].provider.driver.export(@env["export.temp_dir"]) do |progress|
|
||||||
|
@env[:ui].clear_line
|
||||||
|
@env[:ui].report_progress(progress.percent, 100, false)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Clear the line a final time so the next data can appear
|
||||||
|
# alone on the line.
|
||||||
|
@env[:ui].clear_line
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,16 @@
|
||||||
|
require_relative "../../../../lib/vagrant/action/general/package"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
module Action
|
||||||
|
class Package < Vagrant::Action::General::Package
|
||||||
|
# Doing this so that we can test that the parent is properly
|
||||||
|
# called in the unit tests.
|
||||||
|
alias_method :general_call, :call
|
||||||
|
def call(env)
|
||||||
|
general_call(env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,34 @@
|
||||||
|
require "json"
|
||||||
|
|
||||||
|
#require 'vagrant/util/template_renderer'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
module Action
|
||||||
|
class PackageMetadataJson
|
||||||
|
# For TemplateRenderer
|
||||||
|
include Vagrant::Util
|
||||||
|
|
||||||
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
@env = env
|
||||||
|
create_metadata
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
|
||||||
|
# This method creates a metadata.json file to tell vagrant this is a
|
||||||
|
# Hyper V box
|
||||||
|
def create_metadata
|
||||||
|
File.open(File.join(@env["export.temp_dir"], "metadata.json"), "w") do |f|
|
||||||
|
f.write(JSON.generate({
|
||||||
|
provider: "hyperv"
|
||||||
|
}))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,16 @@
|
||||||
|
require_relative "../../../../lib/vagrant/action/general/package_setup_files"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
module Action
|
||||||
|
class PackageSetupFiles < Vagrant::Action::General::PackageSetupFiles
|
||||||
|
# Doing this so that we can test that the parent is properly
|
||||||
|
# called in the unit tests.
|
||||||
|
alias_method :general_call, :call
|
||||||
|
def call(env)
|
||||||
|
general_call(env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,18 @@
|
||||||
|
require "fileutils"
|
||||||
|
|
||||||
|
require_relative "../../../../lib/vagrant/action/general/package_setup_folders"
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
module Action
|
||||||
|
class PackageSetupFolders < Vagrant::Action::General::PackageSetupFolders
|
||||||
|
# Doing this so that we can test that the parent is properly
|
||||||
|
# called in the unit tests.
|
||||||
|
alias_method :general_call, :call
|
||||||
|
def call(env)
|
||||||
|
general_call(env)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,34 @@
|
||||||
|
require 'vagrant/util/template_renderer'
|
||||||
|
|
||||||
|
module VagrantPlugins
|
||||||
|
module HyperV
|
||||||
|
module Action
|
||||||
|
class PackageVagrantfile
|
||||||
|
# For TemplateRenderer
|
||||||
|
include Vagrant::Util
|
||||||
|
|
||||||
|
def initialize(app, env)
|
||||||
|
@app = app
|
||||||
|
end
|
||||||
|
|
||||||
|
def call(env)
|
||||||
|
@env = env
|
||||||
|
create_vagrantfile
|
||||||
|
@app.call(env)
|
||||||
|
end
|
||||||
|
|
||||||
|
# This method creates the auto-generated Vagrantfile at the root of the
|
||||||
|
# box. This Vagrantfile contains the MAC address so that the user doesn't
|
||||||
|
# have to worry about it.
|
||||||
|
def create_vagrantfile
|
||||||
|
File.open(File.join(@env["export.temp_dir"], "Vagrantfile"), "w") do |f|
|
||||||
|
mac_address = @env[:machine].provider.driver.read_mac_address
|
||||||
|
f.write(TemplateRenderer.render("package_Vagrantfile", {
|
||||||
|
base_mac: mac_address["mac"]
|
||||||
|
}))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -53,10 +53,18 @@ module VagrantPlugins
|
||||||
execute('delete_vm.ps1', { VmId: vm_id })
|
execute('delete_vm.ps1', { VmId: vm_id })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def export(path)
|
||||||
|
execute('export_vm.ps1', {VmId: vm_id, Path: path})
|
||||||
|
end
|
||||||
|
|
||||||
def read_guest_ip
|
def read_guest_ip
|
||||||
execute('get_network_config.ps1', { VmId: vm_id })
|
execute('get_network_config.ps1', { VmId: vm_id })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def read_mac_address
|
||||||
|
execute('get_network_mac.ps1', { VmId: vm_id })
|
||||||
|
end
|
||||||
|
|
||||||
def resume
|
def resume
|
||||||
execute('resume_vm.ps1', { VmId: vm_id })
|
execute('resume_vm.ps1', { VmId: vm_id })
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,15 @@
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]$VmId,
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]$Path
|
||||||
|
)
|
||||||
|
|
||||||
|
$vm = Get-VM -Id $VmId -ErrorAction "Stop"
|
||||||
|
$vm | Export-VM -Path $Path
|
||||||
|
|
||||||
|
# Prepare directory structure for box import
|
||||||
|
$name = $vm.Name
|
||||||
|
Move-Item $Path/$name/* $Path
|
||||||
|
Remove-Item -Path $Path/Snapshots -Force -Recurse
|
||||||
|
Remove-Item -Path $Path/$name -Force
|
|
@ -0,0 +1,28 @@
|
||||||
|
Param(
|
||||||
|
[Parameter(Mandatory=$true)]
|
||||||
|
[string]$VmId
|
||||||
|
)
|
||||||
|
|
||||||
|
# Include the following modules
|
||||||
|
$Dir = Split-Path $script:MyInvocation.MyCommand.Path
|
||||||
|
. ([System.IO.Path]::Combine($Dir, "utils\write_messages.ps1"))
|
||||||
|
|
||||||
|
$ip_address = ""
|
||||||
|
$vm = Get-VM -Id $VmId -ErrorAction "Stop"
|
||||||
|
$networks = Get-VMNetworkAdapter -VM $vm
|
||||||
|
foreach ($network in $networks) {
|
||||||
|
if ($network.MacAddress -gt 0) {
|
||||||
|
$mac_address = $network.MacAddress
|
||||||
|
if (-Not ([string]::IsNullOrEmpty($mac_address))) {
|
||||||
|
# We found our mac address!
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
$resultHash = @{
|
||||||
|
mac = "$mac_address"
|
||||||
|
}
|
||||||
|
$result = ConvertTo-Json $resultHash
|
||||||
|
Write-Output-Message $result
|
|
@ -1,49 +1,14 @@
|
||||||
|
require_relative "../../../../lib/vagrant/action/general/package_setup_files"
|
||||||
|
|
||||||
module VagrantPlugins
|
module VagrantPlugins
|
||||||
module ProviderVirtualBox
|
module ProviderVirtualBox
|
||||||
module Action
|
module Action
|
||||||
class PackageSetupFiles
|
class PackageSetupFiles < Vagrant::Action::General::PackageSetupFiles
|
||||||
def initialize(app, env)
|
# Doing this so that we can test that the parent is properly
|
||||||
@app = app
|
# called in the unit tests.
|
||||||
|
alias_method :general_call, :call
|
||||||
env["package.include"] ||= []
|
|
||||||
env["package.vagrantfile"] ||= nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def call(env)
|
def call(env)
|
||||||
files = {}
|
general_call(env)
|
||||||
env["package.include"].each do |file|
|
|
||||||
source = Pathname.new(file)
|
|
||||||
dest = nil
|
|
||||||
|
|
||||||
# If the source is relative then we add the file as-is to the include
|
|
||||||
# directory. Otherwise, we copy only the file into the root of the
|
|
||||||
# include directory. Kind of strange, but seems to match what people
|
|
||||||
# expect based on history.
|
|
||||||
if source.relative?
|
|
||||||
dest = source
|
|
||||||
else
|
|
||||||
dest = source.basename
|
|
||||||
end
|
|
||||||
|
|
||||||
# Assign the mapping
|
|
||||||
files[file] = dest
|
|
||||||
end
|
|
||||||
|
|
||||||
if env["package.vagrantfile"]
|
|
||||||
# Vagrantfiles are treated special and mapped to a specific file
|
|
||||||
files[env["package.vagrantfile"]] = "_Vagrantfile"
|
|
||||||
end
|
|
||||||
|
|
||||||
# Verify the mapping
|
|
||||||
files.each do |from, _|
|
|
||||||
raise Vagrant::Errors::PackageIncludeMissing,
|
|
||||||
file: from if !File.exist?(from)
|
|
||||||
end
|
|
||||||
|
|
||||||
# Save the mapping
|
|
||||||
env["package.files"] = files
|
|
||||||
|
|
||||||
@app.call(env)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,36 +1,16 @@
|
||||||
require "fileutils"
|
require "fileutils"
|
||||||
|
|
||||||
require_relative "../../../../lib/vagrant/action/general/package"
|
require_relative "../../../../lib/vagrant/action/general/package_setup_folders"
|
||||||
|
|
||||||
module VagrantPlugins
|
module VagrantPlugins
|
||||||
module ProviderVirtualBox
|
module ProviderVirtualBox
|
||||||
module Action
|
module Action
|
||||||
class PackageSetupFolders
|
class PackageSetupFolders < Vagrant::Action::General::PackageSetupFolders
|
||||||
include Vagrant::Util::Presence
|
# Doing this so that we can test that the parent is properly
|
||||||
|
# called in the unit tests.
|
||||||
def initialize(app, env)
|
alias_method :general_call, :call
|
||||||
@app = app
|
|
||||||
end
|
|
||||||
|
|
||||||
def call(env)
|
def call(env)
|
||||||
env["package.output"] ||= "package.box"
|
general_call(env)
|
||||||
env["package.directory"] ||= Dir.mktmpdir("vagrant-package-", env[:tmp_path])
|
|
||||||
|
|
||||||
# Match up a couple environmental variables so that the other parts of
|
|
||||||
# Vagrant will do the right thing.
|
|
||||||
env["export.temp_dir"] = env["package.directory"]
|
|
||||||
|
|
||||||
Vagrant::Action::General::Package.validate!(
|
|
||||||
env["package.output"], env["package.directory"])
|
|
||||||
|
|
||||||
@app.call(env)
|
|
||||||
end
|
|
||||||
|
|
||||||
def recover(env)
|
|
||||||
dir = env["package.directory"]
|
|
||||||
if File.exist?(dir)
|
|
||||||
FileUtils.rm_rf(dir)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue