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
|
||||
|
||||
# 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
|
||||
Vagrant::Action::Builder.new.tap do |b|
|
||||
b.use ConfigValidate
|
||||
|
@ -261,9 +283,16 @@ module VagrantPlugins
|
|||
|
||||
# The autoload farm
|
||||
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 :DeleteVM, action_root.join("delete_vm")
|
||||
autoload :Import, action_root.join("import")
|
||||
autoload :Package, action_root.join("package")
|
||||
autoload :IsWindows, action_root.join("is_windows")
|
||||
autoload :ReadState, action_root.join("read_state")
|
||||
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 })
|
||||
end
|
||||
|
||||
def export(path)
|
||||
execute('export_vm.ps1', {VmId: vm_id, Path: path})
|
||||
end
|
||||
|
||||
def read_guest_ip
|
||||
execute('get_network_config.ps1', { VmId: vm_id })
|
||||
end
|
||||
|
||||
def read_mac_address
|
||||
execute('get_network_mac.ps1', { VmId: vm_id })
|
||||
end
|
||||
|
||||
def resume
|
||||
execute('resume_vm.ps1', { VmId: vm_id })
|
||||
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 ProviderVirtualBox
|
||||
module Action
|
||||
class PackageSetupFiles
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
|
||||
env["package.include"] ||= []
|
||||
env["package.vagrantfile"] ||= nil
|
||||
end
|
||||
|
||||
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)
|
||||
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)
|
||||
general_call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,36 +1,16 @@
|
|||
require "fileutils"
|
||||
|
||||
require_relative "../../../../lib/vagrant/action/general/package"
|
||||
require_relative "../../../../lib/vagrant/action/general/package_setup_folders"
|
||||
|
||||
module VagrantPlugins
|
||||
module ProviderVirtualBox
|
||||
module Action
|
||||
class PackageSetupFolders
|
||||
include Vagrant::Util::Presence
|
||||
|
||||
def initialize(app, env)
|
||||
@app = app
|
||||
end
|
||||
|
||||
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)
|
||||
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
|
||||
general_call(env)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue