tests: upload & test in vCenter. Closes #338
This commit is contained in:
parent
02346faff8
commit
9cce43d384
255 changed files with 127290 additions and 3 deletions
187
vendor/github.com/vmware/govmomi/govc/importx/archive.go
generated
vendored
Normal file
187
vendor/github.com/vmware/govmomi/govc/importx/archive.go
generated
vendored
Normal file
|
|
@ -0,0 +1,187 @@
|
|||
/*
|
||||
Copyright (c) 2014-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 importx
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"net/url"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/vmware/govmomi/ovf"
|
||||
"github.com/vmware/govmomi/vim25"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
)
|
||||
|
||||
// ArchiveFlag doesn't register any flags;
|
||||
// only encapsulates some common archive related functionality.
|
||||
type ArchiveFlag struct {
|
||||
Archive
|
||||
}
|
||||
|
||||
func newArchiveFlag(ctx context.Context) (*ArchiveFlag, context.Context) {
|
||||
return &ArchiveFlag{}, ctx
|
||||
}
|
||||
|
||||
func (f *ArchiveFlag) Register(ctx context.Context, fs *flag.FlagSet) {
|
||||
}
|
||||
|
||||
func (f *ArchiveFlag) Process(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (f *ArchiveFlag) ReadOvf(fpath string) ([]byte, error) {
|
||||
r, _, err := f.Open(fpath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer r.Close()
|
||||
|
||||
return ioutil.ReadAll(r)
|
||||
}
|
||||
|
||||
func (f *ArchiveFlag) ReadEnvelope(data []byte) (*ovf.Envelope, error) {
|
||||
e, err := ovf.Unmarshal(bytes.NewReader(data))
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse ovf: %s", err)
|
||||
}
|
||||
|
||||
return e, nil
|
||||
}
|
||||
|
||||
type Archive interface {
|
||||
Open(string) (io.ReadCloser, int64, error)
|
||||
}
|
||||
|
||||
type TapeArchive struct {
|
||||
Path string
|
||||
Opener
|
||||
}
|
||||
|
||||
type TapeArchiveEntry struct {
|
||||
io.Reader
|
||||
f io.Closer
|
||||
|
||||
Name string
|
||||
}
|
||||
|
||||
func (t *TapeArchiveEntry) Close() error {
|
||||
return t.f.Close()
|
||||
}
|
||||
|
||||
func (t *TapeArchive) Open(name string) (io.ReadCloser, int64, error) {
|
||||
f, _, err := t.OpenFile(t.Path)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
r := tar.NewReader(f)
|
||||
|
||||
for {
|
||||
h, err := r.Next()
|
||||
if err == io.EOF {
|
||||
break
|
||||
}
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
matched, err := path.Match(name, path.Base(h.Name))
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if matched {
|
||||
return &TapeArchiveEntry{r, f, h.Name}, h.Size, nil
|
||||
}
|
||||
}
|
||||
|
||||
_ = f.Close()
|
||||
|
||||
return nil, 0, os.ErrNotExist
|
||||
}
|
||||
|
||||
type FileArchive struct {
|
||||
Path string
|
||||
Opener
|
||||
}
|
||||
|
||||
func (t *FileArchive) Open(name string) (io.ReadCloser, int64, error) {
|
||||
fpath := name
|
||||
if name != t.Path {
|
||||
index := strings.LastIndex(t.Path, "/")
|
||||
if index != -1 {
|
||||
fpath = t.Path[:index] + "/" + name
|
||||
}
|
||||
}
|
||||
|
||||
return t.OpenFile(fpath)
|
||||
}
|
||||
|
||||
type Opener struct {
|
||||
*vim25.Client
|
||||
}
|
||||
|
||||
func isRemotePath(path string) bool {
|
||||
if strings.HasPrefix(path, "http://") || strings.HasPrefix(path, "https://") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (o Opener) OpenLocal(path string) (io.ReadCloser, int64, error) {
|
||||
f, err := os.Open(filepath.Clean(path))
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
s, err := f.Stat()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return f, s.Size(), nil
|
||||
}
|
||||
|
||||
func (o Opener) OpenFile(path string) (io.ReadCloser, int64, error) {
|
||||
if isRemotePath(path) {
|
||||
return o.OpenRemote(path)
|
||||
}
|
||||
return o.OpenLocal(path)
|
||||
}
|
||||
|
||||
func (o Opener) OpenRemote(link string) (io.ReadCloser, int64, error) {
|
||||
if o.Client == nil {
|
||||
return nil, 0, errors.New("remote path not supported")
|
||||
}
|
||||
|
||||
u, err := url.Parse(link)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return o.Download(context.Background(), u, &soap.DefaultDownload)
|
||||
}
|
||||
59
vendor/github.com/vmware/govmomi/govc/importx/importable.go
generated
vendored
Normal file
59
vendor/github.com/vmware/govmomi/govc/importx/importable.go
generated
vendored
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
Copyright (c) 2014 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 importx
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path"
|
||||
)
|
||||
|
||||
type importable struct {
|
||||
localPath string
|
||||
remotePath string
|
||||
}
|
||||
|
||||
func (i importable) Ext() string {
|
||||
return path.Ext(i.localPath)
|
||||
}
|
||||
|
||||
func (i importable) Base() string {
|
||||
return path.Base(i.localPath)
|
||||
}
|
||||
|
||||
func (i importable) BaseClean() string {
|
||||
b := i.Base()
|
||||
e := i.Ext()
|
||||
return b[:len(b)-len(e)]
|
||||
}
|
||||
|
||||
func (i importable) RemoteSrcVMDK() string {
|
||||
file := fmt.Sprintf("%s-src.vmdk", i.BaseClean())
|
||||
return i.toRemotePath(file)
|
||||
}
|
||||
|
||||
func (i importable) RemoteDstVMDK() string {
|
||||
file := fmt.Sprintf("%s.vmdk", i.BaseClean())
|
||||
return i.toRemotePath(file)
|
||||
}
|
||||
|
||||
func (i importable) toRemotePath(p string) string {
|
||||
if i.remotePath == "" {
|
||||
return p
|
||||
}
|
||||
|
||||
return path.Join(i.remotePath, p)
|
||||
}
|
||||
205
vendor/github.com/vmware/govmomi/govc/importx/options.go
generated
vendored
Normal file
205
vendor/github.com/vmware/govmomi/govc/importx/options.go
generated
vendored
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
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 importx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/vmware/govmomi/govc/flags"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/ovf"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type Property struct {
|
||||
types.KeyValue
|
||||
Spec *ovf.Property `json:",omitempty"`
|
||||
}
|
||||
|
||||
type Network struct {
|
||||
Name string
|
||||
Network string
|
||||
}
|
||||
|
||||
type Options struct {
|
||||
AllDeploymentOptions []string `json:",omitempty"`
|
||||
Deployment string `json:",omitempty"`
|
||||
|
||||
AllDiskProvisioningOptions []string `json:",omitempty"`
|
||||
DiskProvisioning string
|
||||
|
||||
AllIPAllocationPolicyOptions []string `json:",omitempty"`
|
||||
IPAllocationPolicy string
|
||||
|
||||
AllIPProtocolOptions []string `json:",omitempty"`
|
||||
IPProtocol string
|
||||
|
||||
PropertyMapping []Property `json:",omitempty"`
|
||||
|
||||
NetworkMapping []Network `json:",omitempty"`
|
||||
|
||||
Annotation string `json:",omitempty"`
|
||||
|
||||
MarkAsTemplate bool
|
||||
PowerOn bool
|
||||
InjectOvfEnv bool
|
||||
WaitForIP bool
|
||||
Name *string
|
||||
}
|
||||
|
||||
type OptionsFlag struct {
|
||||
Options Options
|
||||
|
||||
path string
|
||||
}
|
||||
|
||||
func newOptionsFlag(ctx context.Context) (*OptionsFlag, context.Context) {
|
||||
return &OptionsFlag{}, ctx
|
||||
}
|
||||
|
||||
func (flag *OptionsFlag) Register(ctx context.Context, f *flag.FlagSet) {
|
||||
f.StringVar(&flag.path, "options", "", "Options spec file path for VM deployment")
|
||||
}
|
||||
|
||||
func (flag *OptionsFlag) Process(ctx context.Context) error {
|
||||
if len(flag.path) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
var err error
|
||||
in := os.Stdin
|
||||
|
||||
if flag.path != "-" {
|
||||
in, err = os.Open(flag.path)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer in.Close()
|
||||
}
|
||||
|
||||
return json.NewDecoder(in).Decode(&flag.Options)
|
||||
}
|
||||
|
||||
func (flag *OptionsFlag) powerOn(vm *object.VirtualMachine, out *flags.OutputFlag) error {
|
||||
if !flag.Options.PowerOn || flag.Options.MarkAsTemplate {
|
||||
return nil
|
||||
}
|
||||
|
||||
out.Log("Powering on VM...\n")
|
||||
|
||||
task, err := vm.PowerOn(context.Background())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return task.Wait(context.Background())
|
||||
}
|
||||
|
||||
func (flag *OptionsFlag) markAsTemplate(vm *object.VirtualMachine, out *flags.OutputFlag) error {
|
||||
if !flag.Options.MarkAsTemplate {
|
||||
return nil
|
||||
}
|
||||
|
||||
out.Log("Marking VM as template...\n")
|
||||
|
||||
return vm.MarkAsTemplate(context.Background())
|
||||
}
|
||||
|
||||
func (flag *OptionsFlag) injectOvfEnv(vm *object.VirtualMachine, out *flags.OutputFlag) error {
|
||||
if !flag.Options.InjectOvfEnv {
|
||||
return nil
|
||||
}
|
||||
|
||||
out.Log("Injecting OVF environment...\n")
|
||||
|
||||
var opts []types.BaseOptionValue
|
||||
|
||||
a := vm.Client().ServiceContent.About
|
||||
|
||||
// build up Environment in order to marshal to xml
|
||||
var props []ovf.EnvProperty
|
||||
for _, p := range flag.Options.PropertyMapping {
|
||||
props = append(props, ovf.EnvProperty{
|
||||
Key: p.Key,
|
||||
Value: p.Value,
|
||||
})
|
||||
}
|
||||
|
||||
env := ovf.Env{
|
||||
EsxID: vm.Reference().Value,
|
||||
Platform: &ovf.PlatformSection{
|
||||
Kind: a.Name,
|
||||
Version: a.Version,
|
||||
Vendor: a.Vendor,
|
||||
Locale: "US",
|
||||
},
|
||||
Property: &ovf.PropertySection{
|
||||
Properties: props,
|
||||
},
|
||||
}
|
||||
|
||||
opts = append(opts, &types.OptionValue{
|
||||
Key: "guestinfo.ovfEnv",
|
||||
Value: env.MarshalManual(),
|
||||
})
|
||||
|
||||
task, err := vm.Reconfigure(context.Background(), types.VirtualMachineConfigSpec{
|
||||
ExtraConfig: opts,
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return task.Wait(context.Background())
|
||||
}
|
||||
|
||||
func (flag *OptionsFlag) waitForIP(vm *object.VirtualMachine, out *flags.OutputFlag) error {
|
||||
if !flag.Options.PowerOn || !flag.Options.WaitForIP || flag.Options.MarkAsTemplate {
|
||||
return nil
|
||||
}
|
||||
|
||||
out.Log("Waiting for IP address...\n")
|
||||
ip, err := vm.WaitForIP(context.Background())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
out.Log(fmt.Sprintf("Received IP address: %s\n", ip))
|
||||
return nil
|
||||
}
|
||||
|
||||
func (flag *OptionsFlag) Deploy(vm *object.VirtualMachine, out *flags.OutputFlag) error {
|
||||
deploy := []func(*object.VirtualMachine, *flags.OutputFlag) error{
|
||||
flag.injectOvfEnv,
|
||||
flag.markAsTemplate,
|
||||
flag.powerOn,
|
||||
flag.waitForIP,
|
||||
}
|
||||
|
||||
for _, step := range deploy {
|
||||
if err := step(vm, out); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
63
vendor/github.com/vmware/govmomi/govc/importx/ova.go
generated
vendored
Normal file
63
vendor/github.com/vmware/govmomi/govc/importx/ova.go
generated
vendored
Normal file
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
Copyright (c) 2014-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 importx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
|
||||
"github.com/vmware/govmomi/govc/cli"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type ova struct {
|
||||
*ovfx
|
||||
}
|
||||
|
||||
func init() {
|
||||
cli.Register("import.ova", &ova{&ovfx{}})
|
||||
}
|
||||
|
||||
func (cmd *ova) Usage() string {
|
||||
return "PATH_TO_OVA"
|
||||
}
|
||||
|
||||
func (cmd *ova) Run(ctx context.Context, f *flag.FlagSet) error {
|
||||
fpath, err := cmd.Prepare(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
archive := &TapeArchive{Path: fpath}
|
||||
archive.Client = cmd.Client
|
||||
|
||||
cmd.Archive = archive
|
||||
|
||||
moref, err := cmd.Import(fpath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vm := object.NewVirtualMachine(cmd.Client, *moref)
|
||||
return cmd.Deploy(vm, cmd.OutputFlag)
|
||||
}
|
||||
|
||||
func (cmd *ova) Import(fpath string) (*types.ManagedObjectReference, error) {
|
||||
ovf := "*.ovf"
|
||||
return cmd.ovfx.Import(ovf)
|
||||
}
|
||||
343
vendor/github.com/vmware/govmomi/govc/importx/ovf.go
generated
vendored
Normal file
343
vendor/github.com/vmware/govmomi/govc/importx/ovf.go
generated
vendored
Normal file
|
|
@ -0,0 +1,343 @@
|
|||
/*
|
||||
Copyright (c) 2014-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 importx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"path"
|
||||
|
||||
"github.com/vmware/govmomi/find"
|
||||
"github.com/vmware/govmomi/govc/cli"
|
||||
"github.com/vmware/govmomi/govc/flags"
|
||||
"github.com/vmware/govmomi/nfc"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/ovf"
|
||||
"github.com/vmware/govmomi/vim25"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type ovfx struct {
|
||||
*flags.DatastoreFlag
|
||||
*flags.HostSystemFlag
|
||||
*flags.OutputFlag
|
||||
*flags.ResourcePoolFlag
|
||||
*flags.FolderFlag
|
||||
|
||||
*ArchiveFlag
|
||||
*OptionsFlag
|
||||
|
||||
Name string
|
||||
|
||||
Client *vim25.Client
|
||||
Datacenter *object.Datacenter
|
||||
Datastore *object.Datastore
|
||||
ResourcePool *object.ResourcePool
|
||||
}
|
||||
|
||||
func init() {
|
||||
cli.Register("import.ovf", &ovfx{})
|
||||
}
|
||||
|
||||
func (cmd *ovfx) Register(ctx context.Context, f *flag.FlagSet) {
|
||||
cmd.DatastoreFlag, ctx = flags.NewDatastoreFlag(ctx)
|
||||
cmd.DatastoreFlag.Register(ctx, f)
|
||||
cmd.HostSystemFlag, ctx = flags.NewHostSystemFlag(ctx)
|
||||
cmd.HostSystemFlag.Register(ctx, f)
|
||||
cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx)
|
||||
cmd.OutputFlag.Register(ctx, f)
|
||||
cmd.ResourcePoolFlag, ctx = flags.NewResourcePoolFlag(ctx)
|
||||
cmd.ResourcePoolFlag.Register(ctx, f)
|
||||
cmd.FolderFlag, ctx = flags.NewFolderFlag(ctx)
|
||||
cmd.FolderFlag.Register(ctx, f)
|
||||
|
||||
cmd.ArchiveFlag, ctx = newArchiveFlag(ctx)
|
||||
cmd.ArchiveFlag.Register(ctx, f)
|
||||
cmd.OptionsFlag, ctx = newOptionsFlag(ctx)
|
||||
cmd.OptionsFlag.Register(ctx, f)
|
||||
|
||||
f.StringVar(&cmd.Name, "name", "", "Name to use for new entity")
|
||||
}
|
||||
|
||||
func (cmd *ovfx) Process(ctx context.Context) error {
|
||||
if err := cmd.DatastoreFlag.Process(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cmd.HostSystemFlag.Process(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cmd.OutputFlag.Process(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cmd.ResourcePoolFlag.Process(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cmd.ArchiveFlag.Process(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cmd.OptionsFlag.Process(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cmd.FolderFlag.Process(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cmd *ovfx) Usage() string {
|
||||
return "PATH_TO_OVF"
|
||||
}
|
||||
|
||||
func (cmd *ovfx) Run(ctx context.Context, f *flag.FlagSet) error {
|
||||
fpath, err := cmd.Prepare(f)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
archive := &FileArchive{Path: fpath}
|
||||
archive.Client = cmd.Client
|
||||
|
||||
cmd.Archive = archive
|
||||
|
||||
moref, err := cmd.Import(fpath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vm := object.NewVirtualMachine(cmd.Client, *moref)
|
||||
return cmd.Deploy(vm, cmd.OutputFlag)
|
||||
}
|
||||
|
||||
func (cmd *ovfx) Prepare(f *flag.FlagSet) (string, error) {
|
||||
var err error
|
||||
|
||||
args := f.Args()
|
||||
if len(args) != 1 {
|
||||
return "", errors.New("no file specified")
|
||||
}
|
||||
|
||||
cmd.Client, err = cmd.DatastoreFlag.Client()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
cmd.Datacenter, err = cmd.DatastoreFlag.Datacenter()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
cmd.Datastore, err = cmd.DatastoreFlag.Datastore()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
cmd.ResourcePool, err = cmd.ResourcePoolFlag.ResourcePoolIfSpecified()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return f.Arg(0), nil
|
||||
}
|
||||
|
||||
func (cmd *ovfx) Map(op []Property) (p []types.KeyValue) {
|
||||
for _, v := range op {
|
||||
p = append(p, v.KeyValue)
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (cmd *ovfx) NetworkMap(e *ovf.Envelope) ([]types.OvfNetworkMapping, error) {
|
||||
ctx := context.TODO()
|
||||
finder, err := cmd.DatastoreFlag.Finder()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var nmap []types.OvfNetworkMapping
|
||||
for _, m := range cmd.Options.NetworkMapping {
|
||||
if m.Network == "" {
|
||||
continue // Not set, let vSphere choose the default network
|
||||
}
|
||||
|
||||
var ref types.ManagedObjectReference
|
||||
|
||||
net, err := finder.Network(ctx, m.Network)
|
||||
if err != nil {
|
||||
switch err.(type) {
|
||||
case *find.NotFoundError:
|
||||
if !ref.FromString(m.Network) {
|
||||
return nil, err
|
||||
} // else this is a raw MO ref
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
} else {
|
||||
ref = net.Reference()
|
||||
}
|
||||
|
||||
nmap = append(nmap, types.OvfNetworkMapping{
|
||||
Name: m.Name,
|
||||
Network: ref,
|
||||
})
|
||||
}
|
||||
|
||||
return nmap, err
|
||||
}
|
||||
|
||||
func (cmd *ovfx) Import(fpath string) (*types.ManagedObjectReference, error) {
|
||||
ctx := context.TODO()
|
||||
|
||||
o, err := cmd.ReadOvf(fpath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
e, err := cmd.ReadEnvelope(o)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse ovf: %s", err)
|
||||
}
|
||||
|
||||
name := "Govc Virtual Appliance"
|
||||
if e.VirtualSystem != nil {
|
||||
name = e.VirtualSystem.ID
|
||||
if e.VirtualSystem.Name != nil {
|
||||
name = *e.VirtualSystem.Name
|
||||
}
|
||||
}
|
||||
|
||||
// Override name from options if specified
|
||||
if cmd.Options.Name != nil {
|
||||
name = *cmd.Options.Name
|
||||
}
|
||||
|
||||
// Override name from arguments if specified
|
||||
if cmd.Name != "" {
|
||||
name = cmd.Name
|
||||
}
|
||||
|
||||
nmap, err := cmd.NetworkMap(e)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cisp := types.OvfCreateImportSpecParams{
|
||||
DiskProvisioning: cmd.Options.DiskProvisioning,
|
||||
EntityName: name,
|
||||
IpAllocationPolicy: cmd.Options.IPAllocationPolicy,
|
||||
IpProtocol: cmd.Options.IPProtocol,
|
||||
OvfManagerCommonParams: types.OvfManagerCommonParams{
|
||||
DeploymentOption: cmd.Options.Deployment,
|
||||
Locale: "US"},
|
||||
PropertyMapping: cmd.Map(cmd.Options.PropertyMapping),
|
||||
NetworkMapping: nmap,
|
||||
}
|
||||
|
||||
host, err := cmd.HostSystemIfSpecified()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if cmd.ResourcePool == nil {
|
||||
if host == nil {
|
||||
cmd.ResourcePool, err = cmd.ResourcePoolFlag.ResourcePool()
|
||||
} else {
|
||||
cmd.ResourcePool, err = host.ResourcePool(ctx)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
m := ovf.NewManager(cmd.Client)
|
||||
spec, err := m.CreateImportSpec(ctx, string(o), cmd.ResourcePool, cmd.Datastore, cisp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if spec.Error != nil {
|
||||
return nil, errors.New(spec.Error[0].LocalizedMessage)
|
||||
}
|
||||
if spec.Warning != nil {
|
||||
for _, w := range spec.Warning {
|
||||
_, _ = cmd.Log(fmt.Sprintf("Warning: %s\n", w.LocalizedMessage))
|
||||
}
|
||||
}
|
||||
|
||||
if cmd.Options.Annotation != "" {
|
||||
switch s := spec.ImportSpec.(type) {
|
||||
case *types.VirtualMachineImportSpec:
|
||||
s.ConfigSpec.Annotation = cmd.Options.Annotation
|
||||
case *types.VirtualAppImportSpec:
|
||||
s.VAppConfigSpec.Annotation = cmd.Options.Annotation
|
||||
}
|
||||
}
|
||||
|
||||
var folder *object.Folder
|
||||
// The folder argument must not be set on a VM in a vApp, otherwise causes
|
||||
// InvalidArgument fault: A specified parameter was not correct: pool
|
||||
if cmd.ResourcePool.Reference().Type != "VirtualApp" {
|
||||
folder, err = cmd.FolderOrDefault("vm")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
lease, err := cmd.ResourcePool.ImportVApp(ctx, spec.ImportSpec, folder, host)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info, err := lease.Wait(ctx, spec.FileItem)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
u := lease.StartUpdater(ctx, info)
|
||||
defer u.Done()
|
||||
|
||||
for _, i := range info.Items {
|
||||
err = cmd.Upload(ctx, lease, i)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &info.Entity, lease.Complete(ctx)
|
||||
}
|
||||
|
||||
func (cmd *ovfx) Upload(ctx context.Context, lease *nfc.Lease, item nfc.FileItem) error {
|
||||
file := item.Path
|
||||
|
||||
f, size, err := cmd.Open(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
logger := cmd.ProgressLogger(fmt.Sprintf("Uploading %s... ", path.Base(file)))
|
||||
defer logger.Wait()
|
||||
|
||||
opts := soap.Upload{
|
||||
ContentLength: size,
|
||||
Progress: logger,
|
||||
}
|
||||
|
||||
return lease.Upload(ctx, item, f, opts)
|
||||
}
|
||||
256
vendor/github.com/vmware/govmomi/govc/importx/spec.go
generated
vendored
Normal file
256
vendor/github.com/vmware/govmomi/govc/importx/spec.go
generated
vendored
Normal file
|
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
Copyright (c) 2015-2016 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 importx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/vmware/govmomi/govc/cli"
|
||||
"github.com/vmware/govmomi/govc/flags"
|
||||
"github.com/vmware/govmomi/ovf"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
var (
|
||||
allDiskProvisioningOptions = []string{
|
||||
string(types.OvfCreateImportSpecParamsDiskProvisioningTypeFlat),
|
||||
string(types.OvfCreateImportSpecParamsDiskProvisioningTypeMonolithicSparse),
|
||||
string(types.OvfCreateImportSpecParamsDiskProvisioningTypeMonolithicFlat),
|
||||
string(types.OvfCreateImportSpecParamsDiskProvisioningTypeTwoGbMaxExtentSparse),
|
||||
string(types.OvfCreateImportSpecParamsDiskProvisioningTypeTwoGbMaxExtentFlat),
|
||||
string(types.OvfCreateImportSpecParamsDiskProvisioningTypeThin),
|
||||
string(types.OvfCreateImportSpecParamsDiskProvisioningTypeThick),
|
||||
string(types.OvfCreateImportSpecParamsDiskProvisioningTypeSeSparse),
|
||||
string(types.OvfCreateImportSpecParamsDiskProvisioningTypeEagerZeroedThick),
|
||||
string(types.OvfCreateImportSpecParamsDiskProvisioningTypeSparse),
|
||||
}
|
||||
allIPAllocationPolicyOptions = []string{
|
||||
string(types.VAppIPAssignmentInfoIpAllocationPolicyDhcpPolicy),
|
||||
string(types.VAppIPAssignmentInfoIpAllocationPolicyTransientPolicy),
|
||||
string(types.VAppIPAssignmentInfoIpAllocationPolicyFixedPolicy),
|
||||
string(types.VAppIPAssignmentInfoIpAllocationPolicyFixedAllocatedPolicy),
|
||||
}
|
||||
allIPProtocolOptions = []string{
|
||||
string(types.VAppIPAssignmentInfoProtocolsIPv4),
|
||||
string(types.VAppIPAssignmentInfoProtocolsIPv6),
|
||||
}
|
||||
)
|
||||
|
||||
type spec struct {
|
||||
*ArchiveFlag
|
||||
*flags.ClientFlag
|
||||
*flags.OutputFlag
|
||||
|
||||
verbose bool
|
||||
}
|
||||
|
||||
func init() {
|
||||
cli.Register("import.spec", &spec{})
|
||||
}
|
||||
|
||||
func (cmd *spec) Register(ctx context.Context, f *flag.FlagSet) {
|
||||
cmd.ArchiveFlag, ctx = newArchiveFlag(ctx)
|
||||
cmd.ArchiveFlag.Register(ctx, f)
|
||||
cmd.ClientFlag, ctx = flags.NewClientFlag(ctx)
|
||||
cmd.ClientFlag.Register(ctx, f)
|
||||
|
||||
cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx)
|
||||
cmd.OutputFlag.Register(ctx, f)
|
||||
|
||||
f.BoolVar(&cmd.verbose, "verbose", false, "Verbose spec output")
|
||||
}
|
||||
|
||||
func (cmd *spec) Process(ctx context.Context) error {
|
||||
if err := cmd.ArchiveFlag.Process(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cmd.ClientFlag.Process(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return cmd.OutputFlag.Process(ctx)
|
||||
}
|
||||
|
||||
func (cmd *spec) Usage() string {
|
||||
return "PATH_TO_OVF_OR_OVA"
|
||||
}
|
||||
|
||||
func (cmd *spec) Run(ctx context.Context, f *flag.FlagSet) error {
|
||||
fpath := ""
|
||||
args := f.Args()
|
||||
if len(args) == 1 {
|
||||
fpath = f.Arg(0)
|
||||
}
|
||||
|
||||
if len(fpath) > 0 {
|
||||
switch path.Ext(fpath) {
|
||||
case ".ovf":
|
||||
cmd.Archive = &FileArchive{Path: fpath}
|
||||
case "", ".ova":
|
||||
cmd.Archive = &TapeArchive{Path: fpath}
|
||||
fpath = "*.ovf"
|
||||
default:
|
||||
return fmt.Errorf("invalid file extension %s", path.Ext(fpath))
|
||||
}
|
||||
|
||||
if isRemotePath(fpath) {
|
||||
client, err := cmd.Client()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch archive := cmd.Archive.(type) {
|
||||
case *FileArchive:
|
||||
archive.Client = client
|
||||
case *TapeArchive:
|
||||
archive.Client = client
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
env, err := cmd.Spec(fpath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !cmd.All() {
|
||||
cmd.JSON = true
|
||||
}
|
||||
return cmd.WriteResult(&specResult{env})
|
||||
}
|
||||
|
||||
type specResult struct {
|
||||
*Options
|
||||
}
|
||||
|
||||
func (*specResult) Write(w io.Writer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cmd *spec) Map(e *ovf.Envelope) (res []Property) {
|
||||
if e == nil || e.VirtualSystem == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
for _, p := range e.VirtualSystem.Product {
|
||||
for i, v := range p.Property {
|
||||
if v.UserConfigurable == nil || !*v.UserConfigurable {
|
||||
continue
|
||||
}
|
||||
|
||||
d := ""
|
||||
if v.Default != nil {
|
||||
d = *v.Default
|
||||
}
|
||||
|
||||
// vSphere only accept True/False as boolean values for some reason
|
||||
if v.Type == "boolean" {
|
||||
d = strings.Title(d)
|
||||
}
|
||||
|
||||
// From OVF spec, section 9.5.1:
|
||||
// key-value-env = [class-value "."] key-value-prod ["." instance-value]
|
||||
k := v.Key
|
||||
if p.Class != nil {
|
||||
k = fmt.Sprintf("%s.%s", *p.Class, k)
|
||||
}
|
||||
if p.Instance != nil {
|
||||
k = fmt.Sprintf("%s.%s", k, *p.Instance)
|
||||
}
|
||||
|
||||
np := Property{KeyValue: types.KeyValue{Key: k, Value: d}}
|
||||
if cmd.verbose {
|
||||
np.Spec = &p.Property[i]
|
||||
}
|
||||
|
||||
res = append(res, np)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (cmd *spec) Spec(fpath string) (*Options, error) {
|
||||
e := &ovf.Envelope{}
|
||||
if fpath != "" {
|
||||
d, err := cmd.ReadOvf(fpath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if e, err = cmd.ReadEnvelope(d); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
var deploymentOptions []string
|
||||
if e.DeploymentOption != nil && e.DeploymentOption.Configuration != nil {
|
||||
// add default first
|
||||
for _, c := range e.DeploymentOption.Configuration {
|
||||
if c.Default != nil && *c.Default {
|
||||
deploymentOptions = append(deploymentOptions, c.ID)
|
||||
}
|
||||
}
|
||||
|
||||
for _, c := range e.DeploymentOption.Configuration {
|
||||
if c.Default == nil || !*c.Default {
|
||||
deploymentOptions = append(deploymentOptions, c.ID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
o := Options{
|
||||
DiskProvisioning: allDiskProvisioningOptions[0],
|
||||
IPAllocationPolicy: allIPAllocationPolicyOptions[0],
|
||||
IPProtocol: allIPProtocolOptions[0],
|
||||
MarkAsTemplate: false,
|
||||
PowerOn: false,
|
||||
WaitForIP: false,
|
||||
InjectOvfEnv: false,
|
||||
PropertyMapping: cmd.Map(e),
|
||||
}
|
||||
|
||||
if deploymentOptions != nil {
|
||||
o.Deployment = deploymentOptions[0]
|
||||
}
|
||||
|
||||
if e.VirtualSystem != nil && e.VirtualSystem.Annotation != nil {
|
||||
for _, a := range e.VirtualSystem.Annotation {
|
||||
o.Annotation += a.Annotation
|
||||
}
|
||||
}
|
||||
|
||||
if e.Network != nil {
|
||||
for _, net := range e.Network.Networks {
|
||||
o.NetworkMapping = append(o.NetworkMapping, Network{net.Name, ""})
|
||||
}
|
||||
}
|
||||
|
||||
if cmd.verbose {
|
||||
if deploymentOptions != nil {
|
||||
o.AllDeploymentOptions = deploymentOptions
|
||||
}
|
||||
o.AllDiskProvisioningOptions = allDiskProvisioningOptions
|
||||
o.AllIPAllocationPolicyOptions = allIPAllocationPolicyOptions
|
||||
o.AllIPProtocolOptions = allIPProtocolOptions
|
||||
}
|
||||
|
||||
return &o, nil
|
||||
}
|
||||
132
vendor/github.com/vmware/govmomi/govc/importx/vmdk.go
generated
vendored
Normal file
132
vendor/github.com/vmware/govmomi/govc/importx/vmdk.go
generated
vendored
Normal file
|
|
@ -0,0 +1,132 @@
|
|||
/*
|
||||
Copyright (c) 2014-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 importx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"path"
|
||||
|
||||
"github.com/vmware/govmomi/govc/cli"
|
||||
"github.com/vmware/govmomi/govc/flags"
|
||||
"github.com/vmware/govmomi/vmdk"
|
||||
)
|
||||
|
||||
type disk struct {
|
||||
*flags.DatastoreFlag
|
||||
*flags.ResourcePoolFlag
|
||||
*flags.FolderFlag
|
||||
*flags.OutputFlag
|
||||
|
||||
force bool
|
||||
}
|
||||
|
||||
func init() {
|
||||
cli.Register("import.vmdk", &disk{})
|
||||
}
|
||||
|
||||
func (cmd *disk) Register(ctx context.Context, f *flag.FlagSet) {
|
||||
cmd.DatastoreFlag, ctx = flags.NewDatastoreFlag(ctx)
|
||||
cmd.DatastoreFlag.Register(ctx, f)
|
||||
cmd.ResourcePoolFlag, ctx = flags.NewResourcePoolFlag(ctx)
|
||||
cmd.ResourcePoolFlag.Register(ctx, f)
|
||||
cmd.FolderFlag, ctx = flags.NewFolderFlag(ctx)
|
||||
cmd.FolderFlag.Register(ctx, f)
|
||||
cmd.OutputFlag, ctx = flags.NewOutputFlag(ctx)
|
||||
cmd.OutputFlag.Register(ctx, f)
|
||||
|
||||
f.BoolVar(&cmd.force, "force", false, "Overwrite existing disk")
|
||||
}
|
||||
|
||||
func (cmd *disk) Process(ctx context.Context) error {
|
||||
if err := cmd.DatastoreFlag.Process(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cmd.ResourcePoolFlag.Process(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cmd.FolderFlag.Process(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cmd.OutputFlag.Process(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cmd *disk) Usage() string {
|
||||
return "PATH_TO_VMDK [REMOTE_DIRECTORY]"
|
||||
}
|
||||
|
||||
func (cmd *disk) Run(ctx context.Context, f *flag.FlagSet) error {
|
||||
args := f.Args()
|
||||
if len(args) < 1 {
|
||||
return errors.New("no file to import")
|
||||
}
|
||||
|
||||
src := f.Arg(0)
|
||||
|
||||
c, err := cmd.DatastoreFlag.Client()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dc, err := cmd.DatastoreFlag.Datacenter()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
ds, err := cmd.DatastoreFlag.Datastore()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
pool, err := cmd.ResourcePoolFlag.ResourcePool()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
folder, err := cmd.FolderOrDefault("vm")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger := cmd.ProgressLogger(fmt.Sprintf("Uploading %s... ", path.Base(src)))
|
||||
defer logger.Wait()
|
||||
|
||||
p := vmdk.ImportParams{
|
||||
Path: f.Arg(1),
|
||||
Logger: logger,
|
||||
Type: "", // TODO: flag
|
||||
Force: cmd.force,
|
||||
Datacenter: dc,
|
||||
Pool: pool,
|
||||
Folder: folder,
|
||||
}
|
||||
|
||||
err = vmdk.Import(ctx, c, src, ds, p)
|
||||
if err != nil && err == vmdk.ErrInvalidFormat {
|
||||
return fmt.Errorf(`%s
|
||||
The vmdk can be converted using one of:
|
||||
vmware-vdiskmanager -t 5 -r '%s' new.vmdk
|
||||
qemu-img convert -O vmdk -o subformat=streamOptimized '%s' new.vmdk`, err, src, src)
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue