Add ovf export capability to vsphere builders (#8764)
* add ovf export capability to vsphere builders * remove unneeded floppy ejection * add prepare step for export. updated output directory to be the actual destination directory * add step export documentation * add extra export options * add ui messages for export step Co-authored-by: Megan Marsh <megan@hashicorp.com> Co-authored-by: Wilken Rivera <dev@wilkenrivera.com>
This commit is contained in:
parent
9aba27bc83
commit
99b0b98311
|
@ -82,6 +82,17 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
},
|
||||
)
|
||||
|
||||
if b.config.Export != nil {
|
||||
steps = append(steps, &common.StepExport{
|
||||
Name: b.config.Export.Name,
|
||||
Force: b.config.Export.Force,
|
||||
Images: b.config.Export.Images,
|
||||
Manifest: b.config.Export.Manifest,
|
||||
OutputDir: b.config.Export.OutputDir.OutputDir,
|
||||
Options: b.config.Export.Options,
|
||||
})
|
||||
}
|
||||
|
||||
b.runner = packerCommon.NewRunner(steps, b.config.PackerConfig, ui)
|
||||
b.runner.Run(ctx, state)
|
||||
|
||||
|
|
|
@ -32,6 +32,8 @@ type Config struct {
|
|||
// Convert VM to a template. Defaults to `false`.
|
||||
ConvertToTemplate bool `mapstructure:"convert_to_template"`
|
||||
|
||||
Export *common.ExportConfig `mapstructure:"export"`
|
||||
|
||||
ctx interpolate.Context
|
||||
}
|
||||
|
||||
|
@ -53,6 +55,9 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
|
|||
errs = packer.MultiErrorAppend(errs, c.WaitIpConfig.Prepare()...)
|
||||
errs = packer.MultiErrorAppend(errs, c.Comm.Prepare(&c.ctx)...)
|
||||
errs = packer.MultiErrorAppend(errs, c.ShutdownConfig.Prepare()...)
|
||||
if c.Export != nil {
|
||||
errs = packer.MultiErrorAppend(errs, c.Export.Prepare(&c.ctx, &c.LocationConfig, &c.PackerConfig)...)
|
||||
}
|
||||
|
||||
if len(errs.Errors) > 0 {
|
||||
return nil, errs
|
||||
|
|
|
@ -3,6 +3,7 @@ package clone
|
|||
|
||||
import (
|
||||
"github.com/hashicorp/hcl/v2/hcldec"
|
||||
"github.com/hashicorp/packer/builder/vsphere/common"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
|
@ -92,6 +93,7 @@ type FlatConfig struct {
|
|||
Timeout *string `mapstructure:"shutdown_timeout" cty:"shutdown_timeout"`
|
||||
CreateSnapshot *bool `mapstructure:"create_snapshot" cty:"create_snapshot"`
|
||||
ConvertToTemplate *bool `mapstructure:"convert_to_template" cty:"convert_to_template"`
|
||||
Export *common.FlatExportConfig `mapstructure:"export" cty:"export"`
|
||||
}
|
||||
|
||||
// FlatMapstructure returns a new FlatConfig.
|
||||
|
@ -189,6 +191,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
|||
"shutdown_timeout": &hcldec.AttrSpec{Name: "shutdown_timeout", Type: cty.String, Required: false},
|
||||
"create_snapshot": &hcldec.AttrSpec{Name: "create_snapshot", Type: cty.Bool, Required: false},
|
||||
"convert_to_template": &hcldec.AttrSpec{Name: "convert_to_template", Type: cty.Bool, Required: false},
|
||||
"export": &hcldec.BlockSpec{TypeName: "export", Nested: hcldec.ObjectSpec((*common.FlatExportConfig)(nil).HCL2Spec())},
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
|
|
@ -0,0 +1,30 @@
|
|||
//go:generate struct-markdown
|
||||
//go:generate mapstructure-to-hcl2 -type OutputConfig
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/hashicorp/packer/common"
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
)
|
||||
|
||||
type OutputConfig struct {
|
||||
// This setting specifies the directory that
|
||||
// artifacts from the build, such as the virtual machine files and disks,
|
||||
// will be output to. The path to the directory may be relative or
|
||||
// absolute. If relative, the path is relative to the working directory
|
||||
// packer is executed from. This directory must not exist or, if
|
||||
// created, must be empty prior to running the builder. By default this is
|
||||
// "output-BUILDNAME" where "BUILDNAME" is the name of the build.
|
||||
OutputDir string `mapstructure:"output_directory" required:"false"`
|
||||
}
|
||||
|
||||
func (c *OutputConfig) Prepare(ctx *interpolate.Context, pc *common.PackerConfig) []error {
|
||||
if c.OutputDir == "" {
|
||||
c.OutputDir = fmt.Sprintf("output-%s", pc.PackerBuildName)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
// Code generated by "mapstructure-to-hcl2 -type OutputConfig"; DO NOT EDIT.
|
||||
package common
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/hcl/v2/hcldec"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// FlatOutputConfig is an auto-generated flat version of OutputConfig.
|
||||
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
|
||||
type FlatOutputConfig struct {
|
||||
OutputDir *string `mapstructure:"output_directory" required:"false" cty:"output_directory"`
|
||||
}
|
||||
|
||||
// FlatMapstructure returns a new FlatOutputConfig.
|
||||
// FlatOutputConfig is an auto-generated flat version of OutputConfig.
|
||||
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
|
||||
func (*OutputConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
|
||||
return new(FlatOutputConfig)
|
||||
}
|
||||
|
||||
// HCL2Spec returns the hcl spec of a OutputConfig.
|
||||
// This spec is used by HCL to read the fields of OutputConfig.
|
||||
// The decoded values from this spec will then be applied to a FlatOutputConfig.
|
||||
func (*FlatOutputConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||
s := map[string]hcldec.Spec{
|
||||
"output_directory": &hcldec.AttrSpec{Name: "output_directory", Type: cty.String, Required: false},
|
||||
}
|
||||
return s
|
||||
}
|
|
@ -0,0 +1,304 @@
|
|||
//go:generate struct-markdown
|
||||
//go:generate mapstructure-to-hcl2 -type ExportConfig
|
||||
|
||||
package common
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/sha1"
|
||||
"crypto/sha256"
|
||||
"crypto/sha512"
|
||||
"fmt"
|
||||
"hash"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/hashicorp/packer/builder/vsphere/driver"
|
||||
"github.com/hashicorp/packer/common"
|
||||
"github.com/hashicorp/packer/helper/multistep"
|
||||
"github.com/hashicorp/packer/packer"
|
||||
"github.com/hashicorp/packer/template/interpolate"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/vmware/govmomi/nfc"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
// You may optionally export an ovf from VSphere to the instance running Packer.
|
||||
//
|
||||
// Example usage:
|
||||
//
|
||||
// ```json
|
||||
// ...
|
||||
// "vm_name": "example-ubuntu",
|
||||
// ...
|
||||
// "export": {
|
||||
// "force": true,
|
||||
// "output_directory": "./output_vsphere"
|
||||
// },
|
||||
// ```
|
||||
// The above configuration would create the following files:
|
||||
//
|
||||
// ```
|
||||
// ./output_vsphere/example-ubuntu-disk-0.vmdk
|
||||
// ./output_vsphere/example-ubuntu.mf
|
||||
// ./output_vsphere/example-ubuntu.ovf
|
||||
// ```
|
||||
type ExportConfig struct {
|
||||
// name of the ovf. defaults to the name of the VM
|
||||
Name string `mapstructure:"name"`
|
||||
// overwrite ovf if it exists
|
||||
Force bool `mapstructure:"force"`
|
||||
// include iso and img image files that are attached to the VM
|
||||
Images bool `mapstructure:"images"`
|
||||
// generate manifest using sha1, sha256, sha512. Defaults to 'sha256'. Use 'none' for no manifest.
|
||||
Manifest string `mapstructure:"manifest"`
|
||||
OutputDir OutputConfig `mapstructure:",squash"`
|
||||
// Advanced ovf export options. Options can include:
|
||||
// * mac - MAC address is exported for all ethernet devices
|
||||
// * uuid - UUID is exported for all virtual machines
|
||||
// * extraconfig - all extra configuration options are exported for a virtual machine
|
||||
// * nodevicesubtypes - resource subtypes for CD/DVD drives, floppy drives, and serial and parallel ports are not exported
|
||||
//
|
||||
// For example, adding the following export config option would output the mac addresses for all Ethernet devices in the ovf file:
|
||||
|
||||
// ```json
|
||||
// ...
|
||||
// "export": {
|
||||
// "options": ["mac"]
|
||||
// },
|
||||
// ```
|
||||
Options []string `mapstructure:"options"`
|
||||
}
|
||||
|
||||
var sha = map[string]func() hash.Hash{
|
||||
"none": nil,
|
||||
"sha1": sha1.New,
|
||||
"sha256": sha256.New,
|
||||
"sha512": sha512.New,
|
||||
}
|
||||
|
||||
func (c *ExportConfig) Prepare(ctx *interpolate.Context, lc *LocationConfig, pc *common.PackerConfig) []error {
|
||||
var errs *packer.MultiError
|
||||
|
||||
errs = packer.MultiErrorAppend(errs, c.OutputDir.Prepare(ctx, pc)...)
|
||||
|
||||
// manifest should default to sha256
|
||||
if c.Manifest == "" {
|
||||
c.Manifest = "sha256"
|
||||
}
|
||||
if _, ok := sha[c.Manifest]; !ok {
|
||||
errs = packer.MultiErrorAppend(errs, fmt.Errorf("unknown hash: %s. available options include available options being 'none', 'sha1', 'sha256', 'sha512'", c.Manifest))
|
||||
}
|
||||
|
||||
if c.Name == "" {
|
||||
c.Name = lc.VMName
|
||||
}
|
||||
target := getTarget(c.OutputDir.OutputDir, c.Name)
|
||||
if !c.Force {
|
||||
if _, err := os.Stat(target); err == nil {
|
||||
errs = packer.MultiErrorAppend(errs, fmt.Errorf("file already exists: %s", target))
|
||||
}
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(c.OutputDir.OutputDir, 0750); err != nil {
|
||||
errs = packer.MultiErrorAppend(errs, errors.Wrap(err, "unable to make directory for export"))
|
||||
}
|
||||
|
||||
if errs != nil && len(errs.Errors) > 0 {
|
||||
return errs.Errors
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func getTarget(dir string, name string) string {
|
||||
return filepath.Join(dir, name+".ovf")
|
||||
}
|
||||
|
||||
type StepExport struct {
|
||||
Name string
|
||||
Force bool
|
||||
Images bool
|
||||
Manifest string
|
||||
OutputDir string
|
||||
Options []string
|
||||
mf bytes.Buffer
|
||||
}
|
||||
|
||||
func (s *StepExport) Cleanup(multistep.StateBag) {
|
||||
}
|
||||
|
||||
func (s *StepExport) Run(ctx context.Context, state multistep.StateBag) multistep.StepAction {
|
||||
ui := state.Get("ui").(packer.Ui)
|
||||
vm := state.Get("vm").(*driver.VirtualMachine)
|
||||
|
||||
ui.Message("Starting export...")
|
||||
lease, err := vm.Export()
|
||||
if err != nil {
|
||||
state.Put("error", errors.Wrap(err, "error exporting vm"))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
info, err := lease.Wait(ctx, nil)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
u := lease.StartUpdater(ctx, info)
|
||||
defer u.Done()
|
||||
|
||||
cdp := types.OvfCreateDescriptorParams{
|
||||
Name: s.Name,
|
||||
}
|
||||
|
||||
m := vm.NewOvfManager()
|
||||
if len(s.Options) > 0 {
|
||||
exportOptions, err := vm.GetOvfExportOptions(m)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
var unknown []string
|
||||
for _, option := range s.Options {
|
||||
found := false
|
||||
for _, exportOpt := range exportOptions {
|
||||
if exportOpt.Option == option {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
unknown = append(unknown, option)
|
||||
}
|
||||
cdp.ExportOption = append(cdp.ExportOption, option)
|
||||
}
|
||||
|
||||
// only printing error message because the unknown options are just ignored by vcenter
|
||||
if len(unknown) > 0 {
|
||||
ui.Error(fmt.Sprintf("unknown export options %s", strings.Join(unknown, ",")))
|
||||
}
|
||||
}
|
||||
|
||||
for _, i := range info.Items {
|
||||
if !s.include(&i) {
|
||||
continue
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(i.Path, s.Name) {
|
||||
i.Path = s.Name + "-" + i.Path
|
||||
}
|
||||
|
||||
ui.Message("Downloading: " + i.File().Path)
|
||||
err = s.Download(ctx, lease, i)
|
||||
if err != nil {
|
||||
state.Put("error", err)
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
ui.Message("Exporting file: " + i.File().Path)
|
||||
cdp.OvfFiles = append(cdp.OvfFiles, i.File())
|
||||
}
|
||||
|
||||
if err = lease.Complete(ctx); err != nil {
|
||||
state.Put("error", errors.Wrap(err, "unable to complete lease"))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
desc, err := vm.CreateDescriptor(m, cdp)
|
||||
if err != nil {
|
||||
state.Put("error", errors.Wrap(err, "unable to create descriptor"))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
target := getTarget(s.OutputDir, s.Name)
|
||||
file, err := os.Create(target)
|
||||
if err != nil {
|
||||
state.Put("error", errors.Wrap(err, "unable to create file: "+target))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
var w io.Writer = file
|
||||
h, ok := s.newHash()
|
||||
if ok {
|
||||
w = io.MultiWriter(file, h)
|
||||
}
|
||||
|
||||
ui.Message("Writing ovf...")
|
||||
_, err = io.WriteString(w, desc.OvfDescriptor)
|
||||
if err != nil {
|
||||
state.Put("error", errors.Wrap(err, "unable to write descriptor"))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
if err = file.Close(); err != nil {
|
||||
state.Put("error", errors.Wrap(err, "unable to close descriptor"))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
if s.Manifest == "none" {
|
||||
// manifest does not need to be created, return
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
ui.Message("Creating manifest...")
|
||||
s.addHash(filepath.Base(target), h)
|
||||
|
||||
file, err = os.Create(filepath.Join(s.OutputDir, s.Name+".mf"))
|
||||
if err != nil {
|
||||
state.Put("error", errors.Wrap(err, "unable to create manifest"))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
_, err = io.Copy(file, &s.mf)
|
||||
if err != nil {
|
||||
state.Put("error", errors.Wrap(err, "unable to write manifest"))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
err = file.Close()
|
||||
if err != nil {
|
||||
state.Put("error", errors.Wrap(err, "unable to close file"))
|
||||
return multistep.ActionHalt
|
||||
}
|
||||
|
||||
ui.Message("Finished exporting...")
|
||||
return multistep.ActionContinue
|
||||
}
|
||||
|
||||
func (s *StepExport) include(item *nfc.FileItem) bool {
|
||||
if s.Images {
|
||||
return true
|
||||
}
|
||||
|
||||
return filepath.Ext(item.Path) == ".vmdk"
|
||||
}
|
||||
|
||||
func (s *StepExport) newHash() (hash.Hash, bool) {
|
||||
// check if function is nil to handle the 'none' case
|
||||
if h, ok := sha[s.Manifest]; ok && h != nil {
|
||||
return h(), true
|
||||
}
|
||||
|
||||
return nil, false
|
||||
}
|
||||
|
||||
func (s *StepExport) addHash(p string, h hash.Hash) {
|
||||
_, _ = fmt.Fprintf(&s.mf, "%s(%s)= %x\n", strings.ToUpper(s.Manifest), p, h.Sum(nil))
|
||||
}
|
||||
|
||||
func (s *StepExport) Download(ctx context.Context, lease *nfc.Lease, item nfc.FileItem) error {
|
||||
path := filepath.Join(s.OutputDir, item.Path)
|
||||
opts := soap.Download{}
|
||||
|
||||
if h, ok := s.newHash(); ok {
|
||||
opts.Writer = h
|
||||
defer s.addHash(item.Path, h)
|
||||
}
|
||||
|
||||
return lease.DownloadFile(ctx, path, item, opts)
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
// Code generated by "mapstructure-to-hcl2 -type ExportConfig"; DO NOT EDIT.
|
||||
package common
|
||||
|
||||
import (
|
||||
"github.com/hashicorp/hcl/v2/hcldec"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// FlatExportConfig is an auto-generated flat version of ExportConfig.
|
||||
// Where the contents of a field with a `mapstructure:,squash` tag are bubbled up.
|
||||
type FlatExportConfig struct {
|
||||
Name *string `mapstructure:"name" cty:"name"`
|
||||
Force *bool `mapstructure:"force" cty:"force"`
|
||||
Images *bool `mapstructure:"images" cty:"images"`
|
||||
Manifest *string `mapstructure:"manifest" cty:"manifest"`
|
||||
OutputDir *string `mapstructure:"output_directory" required:"false" cty:"output_directory"`
|
||||
Options []string `mapstructure:"options" cty:"options"`
|
||||
}
|
||||
|
||||
// FlatMapstructure returns a new FlatExportConfig.
|
||||
// FlatExportConfig is an auto-generated flat version of ExportConfig.
|
||||
// Where the contents a fields with a `mapstructure:,squash` tag are bubbled up.
|
||||
func (*ExportConfig) FlatMapstructure() interface{ HCL2Spec() map[string]hcldec.Spec } {
|
||||
return new(FlatExportConfig)
|
||||
}
|
||||
|
||||
// HCL2Spec returns the hcl spec of a ExportConfig.
|
||||
// This spec is used by HCL to read the fields of ExportConfig.
|
||||
// The decoded values from this spec will then be applied to a FlatExportConfig.
|
||||
func (*FlatExportConfig) HCL2Spec() map[string]hcldec.Spec {
|
||||
s := map[string]hcldec.Spec{
|
||||
"name": &hcldec.AttrSpec{Name: "name", Type: cty.String, Required: false},
|
||||
"force": &hcldec.AttrSpec{Name: "force", Type: cty.Bool, Required: false},
|
||||
"images": &hcldec.AttrSpec{Name: "images", Type: cty.Bool, Required: false},
|
||||
"manifest": &hcldec.AttrSpec{Name: "manifest", Type: cty.String, Required: false},
|
||||
"output_directory": &hcldec.AttrSpec{Name: "output_directory", Type: cty.String, Required: false},
|
||||
"options": &hcldec.AttrSpec{Name: "options", Type: cty.List(cty.String), Required: false},
|
||||
}
|
||||
return s
|
||||
}
|
|
@ -8,6 +8,11 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/vmware/govmomi/property"
|
||||
|
||||
"github.com/vmware/govmomi/nfc"
|
||||
"github.com/vmware/govmomi/ovf"
|
||||
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
|
@ -688,6 +693,27 @@ func (vm *VirtualMachine) AddConfigParams(params map[string]string) error {
|
|||
return err
|
||||
}
|
||||
|
||||
func (vm *VirtualMachine) Export() (*nfc.Lease, error) {
|
||||
return vm.vm.Export(vm.driver.ctx)
|
||||
}
|
||||
|
||||
func (vm *VirtualMachine) CreateDescriptor(m *ovf.Manager, cdp types.OvfCreateDescriptorParams) (*types.OvfCreateDescriptorResult, error) {
|
||||
return m.CreateDescriptor(vm.driver.ctx, vm.vm, cdp)
|
||||
}
|
||||
|
||||
func (vm *VirtualMachine) NewOvfManager() *ovf.Manager {
|
||||
return ovf.NewManager(vm.vm.Client())
|
||||
}
|
||||
|
||||
func (vm *VirtualMachine) GetOvfExportOptions(m *ovf.Manager) ([]types.OvfOptionInfo, error) {
|
||||
var mgr mo.OvfManager
|
||||
err := property.DefaultCollector(vm.vm.Client()).RetrieveOne(vm.driver.ctx, m.Reference(), nil, &mgr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return mgr.OvfExportOption, nil
|
||||
}
|
||||
|
||||
func findNetworkAdapter(l object.VirtualDeviceList) (types.BaseVirtualEthernetCard, error) {
|
||||
c := l.SelectByType((*types.VirtualEthernetCard)(nil))
|
||||
if len(c) == 0 {
|
||||
|
|
|
@ -132,6 +132,16 @@ func (b *Builder) Run(ctx context.Context, ui packer.Ui, hook packer.Hook) (pack
|
|||
},
|
||||
)
|
||||
|
||||
if b.config.Export != nil {
|
||||
steps = append(steps, &common.StepExport{
|
||||
Name: b.config.Export.Name,
|
||||
Force: b.config.Export.Force,
|
||||
Images: b.config.Export.Images,
|
||||
Manifest: b.config.Export.Manifest,
|
||||
OutputDir: b.config.Export.OutputDir.OutputDir,
|
||||
})
|
||||
}
|
||||
|
||||
b.runner = packerCommon.NewRunner(steps, b.config.PackerConfig, ui)
|
||||
b.runner.Run(ctx, state)
|
||||
|
||||
|
|
|
@ -39,6 +39,9 @@ type Config struct {
|
|||
CreateSnapshot bool `mapstructure:"create_snapshot"`
|
||||
// Convert VM to a template. Defaults to `false`.
|
||||
ConvertToTemplate bool `mapstructure:"convert_to_template"`
|
||||
// Configuration for exporting VM to an ovf file.
|
||||
// The VM will not be exported if no [Export Configuration](#export-configuration) is specified.
|
||||
Export *common.ExportConfig `mapstructure:"export"`
|
||||
|
||||
ctx interpolate.Context
|
||||
}
|
||||
|
@ -77,6 +80,9 @@ func (c *Config) Prepare(raws ...interface{}) ([]string, error) {
|
|||
errs = packer.MultiErrorAppend(errs, c.WaitIpConfig.Prepare()...)
|
||||
errs = packer.MultiErrorAppend(errs, c.Comm.Prepare(&c.ctx)...)
|
||||
errs = packer.MultiErrorAppend(errs, c.ShutdownConfig.Prepare()...)
|
||||
if c.Export != nil {
|
||||
errs = packer.MultiErrorAppend(errs, c.Export.Prepare(&c.ctx, &c.LocationConfig, &c.PackerConfig)...)
|
||||
}
|
||||
|
||||
if len(errs.Errors) > 0 {
|
||||
return warnings, errs
|
||||
|
|
|
@ -3,6 +3,7 @@ package iso
|
|||
|
||||
import (
|
||||
"github.com/hashicorp/hcl/v2/hcldec"
|
||||
"github.com/hashicorp/packer/builder/vsphere/common"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
|
@ -119,6 +120,7 @@ type FlatConfig struct {
|
|||
Timeout *string `mapstructure:"shutdown_timeout" cty:"shutdown_timeout"`
|
||||
CreateSnapshot *bool `mapstructure:"create_snapshot" cty:"create_snapshot"`
|
||||
ConvertToTemplate *bool `mapstructure:"convert_to_template" cty:"convert_to_template"`
|
||||
Export *common.FlatExportConfig `mapstructure:"export" cty:"export"`
|
||||
}
|
||||
|
||||
// FlatMapstructure returns a new FlatConfig.
|
||||
|
@ -243,6 +245,7 @@ func (*FlatConfig) HCL2Spec() map[string]hcldec.Spec {
|
|||
"shutdown_timeout": &hcldec.AttrSpec{Name: "shutdown_timeout", Type: cty.String, Required: false},
|
||||
"create_snapshot": &hcldec.AttrSpec{Name: "create_snapshot", Type: cty.Bool, Required: false},
|
||||
"convert_to_template": &hcldec.AttrSpec{Name: "convert_to_template", Type: cty.Bool, Required: false},
|
||||
"export": &hcldec.BlockSpec{TypeName: "export", Nested: hcldec.ObjectSpec((*common.FlatExportConfig)(nil).HCL2Spec())},
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
/*
|
||||
Copyright (c) 2015 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package ovf
|
||||
|
||||
/*
|
||||
Source: http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2.24.0/CIM_VirtualSystemSettingData.xsd
|
||||
*/
|
||||
|
||||
type CIMVirtualSystemSettingData struct {
|
||||
ElementName string `xml:"ElementName"`
|
||||
InstanceID string `xml:"InstanceID"`
|
||||
|
||||
AutomaticRecoveryAction *uint8 `xml:"AutomaticRecoveryAction"`
|
||||
AutomaticShutdownAction *uint8 `xml:"AutomaticShutdownAction"`
|
||||
AutomaticStartupAction *uint8 `xml:"AutomaticStartupAction"`
|
||||
AutomaticStartupActionDelay *string `xml:"AutomaticStartupActionDelay>Interval"`
|
||||
AutomaticStartupActionSequenceNumber *uint16 `xml:"AutomaticStartupActionSequenceNumber"`
|
||||
Caption *string `xml:"Caption"`
|
||||
ConfigurationDataRoot *string `xml:"ConfigurationDataRoot"`
|
||||
ConfigurationFile *string `xml:"ConfigurationFile"`
|
||||
ConfigurationID *string `xml:"ConfigurationID"`
|
||||
CreationTime *string `xml:"CreationTime"`
|
||||
Description *string `xml:"Description"`
|
||||
LogDataRoot *string `xml:"LogDataRoot"`
|
||||
Notes []string `xml:"Notes"`
|
||||
RecoveryFile *string `xml:"RecoveryFile"`
|
||||
SnapshotDataRoot *string `xml:"SnapshotDataRoot"`
|
||||
SuspendDataRoot *string `xml:"SuspendDataRoot"`
|
||||
SwapFileDataRoot *string `xml:"SwapFileDataRoot"`
|
||||
VirtualSystemIdentifier *string `xml:"VirtualSystemIdentifier"`
|
||||
VirtualSystemType *string `xml:"VirtualSystemType"`
|
||||
}
|
||||
|
||||
/*
|
||||
Source: http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2.24.0/CIM_ResourceAllocationSettingData.xsd
|
||||
*/
|
||||
|
||||
type CIMResourceAllocationSettingData struct {
|
||||
ElementName string `xml:"ElementName"`
|
||||
InstanceID string `xml:"InstanceID"`
|
||||
|
||||
ResourceType *uint16 `xml:"ResourceType"`
|
||||
OtherResourceType *string `xml:"OtherResourceType"`
|
||||
ResourceSubType *string `xml:"ResourceSubType"`
|
||||
|
||||
AddressOnParent *string `xml:"AddressOnParent"`
|
||||
Address *string `xml:"Address"`
|
||||
AllocationUnits *string `xml:"AllocationUnits"`
|
||||
AutomaticAllocation *bool `xml:"AutomaticAllocation"`
|
||||
AutomaticDeallocation *bool `xml:"AutomaticDeallocation"`
|
||||
Caption *string `xml:"Caption"`
|
||||
Connection []string `xml:"Connection"`
|
||||
ConsumerVisibility *uint16 `xml:"ConsumerVisibility"`
|
||||
Description *string `xml:"Description"`
|
||||
HostResource []string `xml:"HostResource"`
|
||||
Limit *uint64 `xml:"Limit"`
|
||||
MappingBehavior *uint `xml:"MappingBehavior"`
|
||||
Parent *string `xml:"Parent"`
|
||||
PoolID *string `xml:"PoolID"`
|
||||
Reservation *uint64 `xml:"Reservation"`
|
||||
VirtualQuantity *uint `xml:"VirtualQuantity"`
|
||||
VirtualQuantityUnits *string `xml:"VirtualQuantityUnits"`
|
||||
Weight *uint `xml:"Weight"`
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
Copyright (c) 2015 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
/*
|
||||
Package ovf provides functionality to unmarshal and inspect the structure
|
||||
of an OVF file. It is not a complete implementation of the specification and
|
||||
is intended to be used to import virtual infrastructure into vSphere.
|
||||
|
||||
For a complete specification of the OVF standard, refer to:
|
||||
https://www.dmtf.org/sites/default/files/standards/documents/DSP0243_2.1.0.pdf
|
||||
*/
|
||||
package ovf
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
Copyright (c) 2015 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package ovf
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
|
||||
"github.com/vmware/govmomi/vim25/xml"
|
||||
)
|
||||
|
||||
const (
|
||||
ovfEnvHeader = `<Environment
|
||||
xmlns="http://schemas.dmtf.org/ovf/environment/1"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:oe="http://schemas.dmtf.org/ovf/environment/1"
|
||||
xmlns:ve="http://www.vmware.com/schema/ovfenv"
|
||||
oe:id=""
|
||||
ve:esxId="%s">`
|
||||
ovfEnvPlatformSection = `<PlatformSection>
|
||||
<Kind>%s</Kind>
|
||||
<Version>%s</Version>
|
||||
<Vendor>%s</Vendor>
|
||||
<Locale>%s</Locale>
|
||||
</PlatformSection>`
|
||||
ovfEnvPropertyHeader = `<PropertySection>`
|
||||
ovfEnvPropertyEntry = `<Property oe:key="%s" oe:value="%s"/>`
|
||||
ovfEnvPropertyFooter = `</PropertySection>`
|
||||
ovfEnvFooter = `</Environment>`
|
||||
)
|
||||
|
||||
type Env struct {
|
||||
XMLName xml.Name `xml:"http://schemas.dmtf.org/ovf/environment/1 Environment"`
|
||||
ID string `xml:"id,attr"`
|
||||
EsxID string `xml:"http://www.vmware.com/schema/ovfenv esxId,attr"`
|
||||
|
||||
Platform *PlatformSection `xml:"PlatformSection"`
|
||||
Property *PropertySection `xml:"PropertySection"`
|
||||
}
|
||||
|
||||
type PlatformSection struct {
|
||||
Kind string `xml:"Kind"`
|
||||
Version string `xml:"Version"`
|
||||
Vendor string `xml:"Vendor"`
|
||||
Locale string `xml:"Locale"`
|
||||
}
|
||||
|
||||
type PropertySection struct {
|
||||
Properties []EnvProperty `xml:"Property"`
|
||||
}
|
||||
|
||||
type EnvProperty struct {
|
||||
Key string `xml:"key,attr"`
|
||||
Value string `xml:"value,attr"`
|
||||
}
|
||||
|
||||
// Marshal marshals Env to xml by using xml.Marshal.
|
||||
func (e Env) Marshal() (string, error) {
|
||||
x, err := xml.Marshal(e)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return fmt.Sprintf("%s%s", xml.Header, x), nil
|
||||
}
|
||||
|
||||
// MarshalManual manually marshals Env to xml suitable for a vApp guest.
|
||||
// It exists to overcome the lack of expressiveness in Go's XML namespaces.
|
||||
func (e Env) MarshalManual() string {
|
||||
var buffer bytes.Buffer
|
||||
|
||||
buffer.WriteString(xml.Header)
|
||||
buffer.WriteString(fmt.Sprintf(ovfEnvHeader, e.EsxID))
|
||||
buffer.WriteString(fmt.Sprintf(ovfEnvPlatformSection, e.Platform.Kind, e.Platform.Version, e.Platform.Vendor, e.Platform.Locale))
|
||||
|
||||
buffer.WriteString(fmt.Sprint(ovfEnvPropertyHeader))
|
||||
for _, p := range e.Property.Properties {
|
||||
buffer.WriteString(fmt.Sprintf(ovfEnvPropertyEntry, p.Key, p.Value))
|
||||
}
|
||||
buffer.WriteString(fmt.Sprint(ovfEnvPropertyFooter))
|
||||
|
||||
buffer.WriteString(fmt.Sprint(ovfEnvFooter))
|
||||
|
||||
return buffer.String()
|
||||
}
|
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
Copyright (c) 2015 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package ovf
|
||||
|
||||
type Envelope struct {
|
||||
References []File `xml:"References>File"`
|
||||
|
||||
// Package level meta-data
|
||||
Annotation *AnnotationSection `xml:"AnnotationSection"`
|
||||
Product *ProductSection `xml:"ProductSection"`
|
||||
Network *NetworkSection `xml:"NetworkSection"`
|
||||
Disk *DiskSection `xml:"DiskSection"`
|
||||
OperatingSystem *OperatingSystemSection `xml:"OperatingSystemSection"`
|
||||
Eula *EulaSection `xml:"EulaSection"`
|
||||
VirtualHardware *VirtualHardwareSection `xml:"VirtualHardwareSection"`
|
||||
ResourceAllocation *ResourceAllocationSection `xml:"ResourceAllocationSection"`
|
||||
DeploymentOption *DeploymentOptionSection `xml:"DeploymentOptionSection"`
|
||||
|
||||
// Content: A VirtualSystem or a VirtualSystemCollection
|
||||
VirtualSystem *VirtualSystem `xml:"VirtualSystem"`
|
||||
}
|
||||
|
||||
type VirtualSystem struct {
|
||||
Content
|
||||
|
||||
Annotation []AnnotationSection `xml:"AnnotationSection"`
|
||||
Product []ProductSection `xml:"ProductSection"`
|
||||
OperatingSystem []OperatingSystemSection `xml:"OperatingSystemSection"`
|
||||
Eula []EulaSection `xml:"EulaSection"`
|
||||
VirtualHardware []VirtualHardwareSection `xml:"VirtualHardwareSection"`
|
||||
}
|
||||
|
||||
type File struct {
|
||||
ID string `xml:"id,attr"`
|
||||
Href string `xml:"href,attr"`
|
||||
Size uint `xml:"size,attr"`
|
||||
Compression *string `xml:"compression,attr"`
|
||||
ChunkSize *int `xml:"chunkSize,attr"`
|
||||
}
|
||||
|
||||
type Content struct {
|
||||
ID string `xml:"id,attr"`
|
||||
Info string `xml:"Info"`
|
||||
Name *string `xml:"Name"`
|
||||
}
|
||||
|
||||
type Section struct {
|
||||
Required *bool `xml:"required,attr"`
|
||||
Info string `xml:"Info"`
|
||||
}
|
||||
|
||||
type AnnotationSection struct {
|
||||
Section
|
||||
|
||||
Annotation string `xml:"Annotation"`
|
||||
}
|
||||
|
||||
type ProductSection struct {
|
||||
Section
|
||||
|
||||
Class *string `xml:"class,attr"`
|
||||
Instance *string `xml:"instance,attr"`
|
||||
|
||||
Product string `xml:"Product"`
|
||||
Vendor string `xml:"Vendor"`
|
||||
Version string `xml:"Version"`
|
||||
FullVersion string `xml:"FullVersion"`
|
||||
ProductURL string `xml:"ProductUrl"`
|
||||
VendorURL string `xml:"VendorUrl"`
|
||||
AppURL string `xml:"AppUrl"`
|
||||
Property []Property `xml:"Property"`
|
||||
}
|
||||
|
||||
type Property struct {
|
||||
Key string `xml:"key,attr"`
|
||||
Type string `xml:"type,attr"`
|
||||
Qualifiers *string `xml:"qualifiers,attr"`
|
||||
UserConfigurable *bool `xml:"userConfigurable,attr"`
|
||||
Default *string `xml:"value,attr"`
|
||||
Password *bool `xml:"password,attr"`
|
||||
|
||||
Label *string `xml:"Label"`
|
||||
Description *string `xml:"Description"`
|
||||
|
||||
Values []PropertyConfigurationValue `xml:"Value"`
|
||||
}
|
||||
|
||||
type PropertyConfigurationValue struct {
|
||||
Value string `xml:"value,attr"`
|
||||
Configuration *string `xml:"configuration,attr"`
|
||||
}
|
||||
|
||||
type NetworkSection struct {
|
||||
Section
|
||||
|
||||
Networks []Network `xml:"Network"`
|
||||
}
|
||||
|
||||
type Network struct {
|
||||
Name string `xml:"name,attr"`
|
||||
|
||||
Description string `xml:"Description"`
|
||||
}
|
||||
|
||||
type DiskSection struct {
|
||||
Section
|
||||
|
||||
Disks []VirtualDiskDesc `xml:"Disk"`
|
||||
}
|
||||
|
||||
type VirtualDiskDesc struct {
|
||||
DiskID string `xml:"diskId,attr"`
|
||||
FileRef *string `xml:"fileRef,attr"`
|
||||
Capacity string `xml:"capacity,attr"`
|
||||
CapacityAllocationUnits *string `xml:"capacityAllocationUnits,attr"`
|
||||
Format *string `xml:"format,attr"`
|
||||
PopulatedSize *int `xml:"populatedSize,attr"`
|
||||
ParentRef *string `xml:"parentRef,attr"`
|
||||
}
|
||||
|
||||
type OperatingSystemSection struct {
|
||||
Section
|
||||
|
||||
ID int16 `xml:"id,attr"`
|
||||
Version *string `xml:"version,attr"`
|
||||
OSType *string `xml:"osType,attr"`
|
||||
|
||||
Description *string `xml:"Description"`
|
||||
}
|
||||
|
||||
type EulaSection struct {
|
||||
Section
|
||||
|
||||
License string `xml:"License"`
|
||||
}
|
||||
|
||||
type VirtualHardwareSection struct {
|
||||
Section
|
||||
|
||||
ID *string `xml:"id,attr"`
|
||||
Transport *string `xml:"transport,attr"`
|
||||
|
||||
System *VirtualSystemSettingData `xml:"System"`
|
||||
Item []ResourceAllocationSettingData `xml:"Item"`
|
||||
}
|
||||
|
||||
type VirtualSystemSettingData struct {
|
||||
CIMVirtualSystemSettingData
|
||||
}
|
||||
|
||||
type ResourceAllocationSettingData struct {
|
||||
CIMResourceAllocationSettingData
|
||||
|
||||
Required *bool `xml:"required,attr"`
|
||||
Configuration *string `xml:"configuration,attr"`
|
||||
Bound *string `xml:"bound,attr"`
|
||||
}
|
||||
|
||||
type ResourceAllocationSection struct {
|
||||
Section
|
||||
|
||||
Item []ResourceAllocationSettingData `xml:"Item"`
|
||||
}
|
||||
|
||||
type DeploymentOptionSection struct {
|
||||
Section
|
||||
|
||||
Configuration []DeploymentOptionConfiguration `xml:"Configuration"`
|
||||
}
|
||||
|
||||
type DeploymentOptionConfiguration struct {
|
||||
ID string `xml:"id,attr"`
|
||||
Default *bool `xml:"default,attr"`
|
||||
|
||||
Label string `xml:"Label"`
|
||||
Description string `xml:"Description"`
|
||||
}
|
|
@ -0,0 +1,103 @@
|
|||
/*
|
||||
Copyright (c) 2015-2017 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package ovf
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/vmware/govmomi/vim25"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type Manager struct {
|
||||
types.ManagedObjectReference
|
||||
|
||||
c *vim25.Client
|
||||
}
|
||||
|
||||
func NewManager(c *vim25.Client) *Manager {
|
||||
return &Manager{*c.ServiceContent.OvfManager, c}
|
||||
}
|
||||
|
||||
// CreateDescriptor wraps methods.CreateDescriptor
|
||||
func (m *Manager) CreateDescriptor(ctx context.Context, obj mo.Reference, cdp types.OvfCreateDescriptorParams) (*types.OvfCreateDescriptorResult, error) {
|
||||
req := types.CreateDescriptor{
|
||||
This: m.Reference(),
|
||||
Obj: obj.Reference(),
|
||||
Cdp: cdp,
|
||||
}
|
||||
|
||||
res, err := methods.CreateDescriptor(ctx, m.c, &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &res.Returnval, nil
|
||||
}
|
||||
|
||||
// CreateImportSpec wraps methods.CreateImportSpec
|
||||
func (m *Manager) CreateImportSpec(ctx context.Context, ovfDescriptor string, resourcePool mo.Reference, datastore mo.Reference, cisp types.OvfCreateImportSpecParams) (*types.OvfCreateImportSpecResult, error) {
|
||||
req := types.CreateImportSpec{
|
||||
This: m.Reference(),
|
||||
OvfDescriptor: ovfDescriptor,
|
||||
ResourcePool: resourcePool.Reference(),
|
||||
Datastore: datastore.Reference(),
|
||||
Cisp: cisp,
|
||||
}
|
||||
|
||||
res, err := methods.CreateImportSpec(ctx, m.c, &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &res.Returnval, nil
|
||||
}
|
||||
|
||||
// ParseDescriptor wraps methods.ParseDescriptor
|
||||
func (m *Manager) ParseDescriptor(ctx context.Context, ovfDescriptor string, pdp types.OvfParseDescriptorParams) (*types.OvfParseDescriptorResult, error) {
|
||||
req := types.ParseDescriptor{
|
||||
This: m.Reference(),
|
||||
OvfDescriptor: ovfDescriptor,
|
||||
Pdp: pdp,
|
||||
}
|
||||
|
||||
res, err := methods.ParseDescriptor(ctx, m.c, &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &res.Returnval, nil
|
||||
}
|
||||
|
||||
// ValidateHost wraps methods.ValidateHost
|
||||
func (m *Manager) ValidateHost(ctx context.Context, ovfDescriptor string, host mo.Reference, vhp types.OvfValidateHostParams) (*types.OvfValidateHostResult, error) {
|
||||
req := types.ValidateHost{
|
||||
This: m.Reference(),
|
||||
OvfDescriptor: ovfDescriptor,
|
||||
Host: host.Reference(),
|
||||
Vhp: vhp,
|
||||
}
|
||||
|
||||
res, err := methods.ValidateHost(ctx, m.c, &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &res.Returnval, nil
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
Copyright (c) 2015 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package ovf
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"github.com/vmware/govmomi/vim25/xml"
|
||||
)
|
||||
|
||||
func Unmarshal(r io.Reader) (*Envelope, error) {
|
||||
var e Envelope
|
||||
|
||||
dec := xml.NewDecoder(r)
|
||||
err := dec.Decode(&e)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &e, nil
|
||||
}
|
|
@ -572,6 +572,7 @@ github.com/vmware/govmomi/find
|
|||
github.com/vmware/govmomi/list
|
||||
github.com/vmware/govmomi/nfc
|
||||
github.com/vmware/govmomi/object
|
||||
github.com/vmware/govmomi/ovf
|
||||
github.com/vmware/govmomi/property
|
||||
github.com/vmware/govmomi/session
|
||||
github.com/vmware/govmomi/task
|
||||
|
|
|
@ -82,6 +82,17 @@ necessary for this build to succeed and can be found further down the page.
|
|||
|
||||
<%= partial "partials/helper/communicator/WinRM-not-required" %>
|
||||
|
||||
### Export Configuration
|
||||
<%= partial "partials/builder/vsphere/common/ExportConfig" %>
|
||||
|
||||
### Optional:
|
||||
|
||||
<%= partial "partials/builder/vsphere/common/ExportConfig-not-required" %>
|
||||
|
||||
#### Output Configuration:
|
||||
|
||||
<%= partial "partials/builder/vsphere/common/OutputConfig-not-required" %>
|
||||
|
||||
## Working with Clusters
|
||||
#### Standalone Hosts
|
||||
Only use the `host` option. Optionally specify a `resource_pool`:
|
||||
|
|
|
@ -106,6 +106,17 @@ from the datastore. Example:
|
|||
### Floppy Configuration
|
||||
<%= partial "partials/builder/vsphere/iso/FloppyConfig-not-required" %>
|
||||
|
||||
### Export Configuration
|
||||
<%= partial "partials/builder/vsphere/common/ExportConfig" %>
|
||||
|
||||
### Optional:
|
||||
|
||||
<%= partial "partials/builder/vsphere/common/ExportConfig-not-required" %>
|
||||
|
||||
#### Output Configuration:
|
||||
|
||||
<%= partial "partials/builder/vsphere/common/OutputConfig-not-required" %>
|
||||
|
||||
### Extra Configuration Parameters
|
||||
<%= partial "partials/builder/vsphere/common/ConfigParamsConfig-not-required" %>
|
||||
|
||||
|
|
|
@ -5,3 +5,4 @@
|
|||
|
||||
- `convert_to_template` (bool) - Convert VM to a template. Defaults to `false`.
|
||||
|
||||
- `export` (\*common.ExportConfig) - Export
|
|
@ -0,0 +1,17 @@
|
|||
<!-- Code generated from the comments of the ExportConfig struct in builder/vsphere/common/step_export.go; DO NOT EDIT MANUALLY -->
|
||||
|
||||
- `name` (string) - name of the ovf. defaults to the name of the VM
|
||||
|
||||
- `force` (bool) - overwrite ovf if it exists
|
||||
|
||||
- `images` (bool) - include iso and img image files that are attached to the VM
|
||||
|
||||
- `manifest` (string) - generate manifest using sha1, sha256, sha512. Defaults to 'sha256'. Use 'none' for no manifest.
|
||||
|
||||
- `options` ([]string) - ```json
|
||||
...
|
||||
"export": {
|
||||
"options": ["mac"]
|
||||
},
|
||||
```
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
<!-- Code generated from the comments of the ExportConfig struct in builder/vsphere/common/step_export.go; DO NOT EDIT MANUALLY -->
|
||||
You may optionally export an ovf from VSphere to the instance running Packer.
|
||||
|
||||
Example usage:
|
||||
|
||||
```json
|
||||
...
|
||||
"vm_name": "example-ubuntu",
|
||||
...
|
||||
"export": {
|
||||
"force": true,
|
||||
"output_directory": "./output_vsphere"
|
||||
},
|
||||
```
|
||||
The above configuration would create the following files:
|
||||
|
||||
```
|
||||
./output_vsphere/example-ubuntu-disk-0.vmdk
|
||||
./output_vsphere/example-ubuntu.mf
|
||||
./output_vsphere/example-ubuntu.ovf
|
||||
```
|
|
@ -0,0 +1,10 @@
|
|||
<!-- Code generated from the comments of the OutputConfig struct in builder/vsphere/common/output_config.go; DO NOT EDIT MANUALLY -->
|
||||
|
||||
- `output_directory` (string) - This setting specifies the directory that
|
||||
artifacts from the build, such as the virtual machine files and disks,
|
||||
will be output to. The path to the directory may be relative or
|
||||
absolute. If relative, the path is relative to the working directory
|
||||
packer is executed from. This directory must not exist or, if
|
||||
created, must be empty prior to running the builder. By default this is
|
||||
"output-BUILDNAME" where "BUILDNAME" is the name of the build.
|
||||
|
|
@ -5,3 +5,6 @@
|
|||
|
||||
- `convert_to_template` (bool) - Convert VM to a template. Defaults to `false`.
|
||||
|
||||
- `export` (\*common.ExportConfig) - Configuration for exporting VM to an ovf file.
|
||||
The VM will not be exported if no [Export Configuration](#export-configuration) is specified.
|
||||
|
Loading…
Reference in New Issue