build(deps): bump the go-deps group across 1 directory with 8 updates
Bumps the go-deps group with 7 updates in the / directory: | Package | From | To | | --- | --- | --- | | [cloud.google.com/go/compute](https://github.com/googleapis/google-cloud-go) | `1.27.3` | `1.27.4` | | [github.com/Azure/azure-sdk-for-go/sdk/storage/azblob](https://github.com/Azure/azure-sdk-for-go) | `1.3.2` | `1.4.0` | | [github.com/aws/aws-sdk-go](https://github.com/aws/aws-sdk-go) | `1.54.18` | `1.55.2` | | [github.com/gophercloud/gophercloud](https://github.com/gophercloud/gophercloud) | `1.13.0` | `1.14.0` | | [github.com/openshift-online/ocm-sdk-go](https://github.com/openshift-online/ocm-sdk-go) | `0.1.429` | `0.1.432` | | [github.com/osbuild/images](https://github.com/osbuild/images) | `0.70.0` | `0.72.0` | | [github.com/vmware/govmomi](https://github.com/vmware/govmomi) | `0.38.0` | `0.39.0` | Updates `cloud.google.com/go/compute` from 1.27.3 to 1.27.4 - [Release notes](https://github.com/googleapis/google-cloud-go/releases) - [Changelog](https://github.com/googleapis/google-cloud-go/blob/main/CHANGES.md) - [Commits](https://github.com/googleapis/google-cloud-go/compare/compute/v1.27.3...compute/v1.27.4) Updates `github.com/Azure/azure-sdk-for-go/sdk/storage/azblob` from 1.3.2 to 1.4.0 - [Release notes](https://github.com/Azure/azure-sdk-for-go/releases) - [Changelog](https://github.com/Azure/azure-sdk-for-go/blob/main/documentation/release.md) - [Commits](https://github.com/Azure/azure-sdk-for-go/compare/sdk/storage/azblob/v1.3.2...sdk/azcore/v1.4.0) Updates `github.com/aws/aws-sdk-go` from 1.54.18 to 1.55.2 - [Release notes](https://github.com/aws/aws-sdk-go/releases) - [Commits](https://github.com/aws/aws-sdk-go/compare/v1.54.18...v1.55.2) Updates `github.com/gophercloud/gophercloud` from 1.13.0 to 1.14.0 - [Release notes](https://github.com/gophercloud/gophercloud/releases) - [Changelog](https://github.com/gophercloud/gophercloud/blob/v1.14.0/CHANGELOG.md) - [Commits](https://github.com/gophercloud/gophercloud/compare/v1.13.0...v1.14.0) Updates `github.com/openshift-online/ocm-sdk-go` from 0.1.429 to 0.1.432 - [Release notes](https://github.com/openshift-online/ocm-sdk-go/releases) - [Changelog](https://github.com/openshift-online/ocm-sdk-go/blob/main/CHANGES.md) - [Commits](https://github.com/openshift-online/ocm-sdk-go/compare/v0.1.429...v0.1.432) Updates `github.com/osbuild/images` from 0.70.0 to 0.72.0 - [Release notes](https://github.com/osbuild/images/releases) - [Commits](https://github.com/osbuild/images/compare/v0.70.0...v0.72.0) Updates `github.com/vmware/govmomi` from 0.38.0 to 0.39.0 - [Release notes](https://github.com/vmware/govmomi/releases) - [Changelog](https://github.com/vmware/govmomi/blob/main/CHANGELOG.md) - [Commits](https://github.com/vmware/govmomi/compare/v0.38.0...v0.39.0) Updates `google.golang.org/api` from 0.188.0 to 0.189.0 - [Release notes](https://github.com/googleapis/google-api-go-client/releases) - [Changelog](https://github.com/googleapis/google-api-go-client/blob/main/CHANGES.md) - [Commits](https://github.com/googleapis/google-api-go-client/compare/v0.188.0...v0.189.0) --- updated-dependencies: - dependency-name: cloud.google.com/go/compute dependency-type: direct:production update-type: version-update:semver-patch dependency-group: go-deps - dependency-name: github.com/Azure/azure-sdk-for-go/sdk/storage/azblob dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-deps - dependency-name: github.com/aws/aws-sdk-go dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-deps - dependency-name: github.com/gophercloud/gophercloud dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-deps - dependency-name: github.com/openshift-online/ocm-sdk-go dependency-type: direct:production update-type: version-update:semver-patch dependency-group: go-deps - dependency-name: github.com/osbuild/images dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-deps - dependency-name: github.com/vmware/govmomi dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-deps - dependency-name: google.golang.org/api dependency-type: direct:production update-type: version-update:semver-minor dependency-group: go-deps ... Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
parent
fd71c9cefa
commit
ca2c2dfa4f
104 changed files with 4713 additions and 2477 deletions
142
vendor/github.com/vmware/govmomi/govc/flags/output.go
generated
vendored
142
vendor/github.com/vmware/govmomi/govc/flags/output.go
generated
vendored
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved.
|
||||
Copyright (c) 2014-2024 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
|
||||
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,
|
||||
|
|
@ -26,11 +26,11 @@ import (
|
|||
"os"
|
||||
"reflect"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/dougm/pretty"
|
||||
|
||||
"github.com/vmware/govmomi/govc/cli"
|
||||
"github.com/vmware/govmomi/task"
|
||||
"github.com/vmware/govmomi/vim25/progress"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
|
|
@ -50,6 +50,7 @@ type OutputFlag struct {
|
|||
TTY bool
|
||||
Dump bool
|
||||
Out io.Writer
|
||||
Spec bool
|
||||
|
||||
formatError bool
|
||||
formatIndent bool
|
||||
|
|
@ -72,6 +73,9 @@ func (flag *OutputFlag) Register(ctx context.Context, f *flag.FlagSet) {
|
|||
f.BoolVar(&flag.JSON, "json", false, "Enable JSON output")
|
||||
f.BoolVar(&flag.XML, "xml", false, "Enable XML output")
|
||||
f.BoolVar(&flag.Dump, "dump", false, "Enable Go output")
|
||||
if cli.ShowUnreleased() {
|
||||
f.BoolVar(&flag.Spec, "spec", false, "Output spec without sending request")
|
||||
}
|
||||
// Avoid adding more flags for now..
|
||||
flag.formatIndent = os.Getenv("GOVC_INDENT") != "false" // Default to indented output
|
||||
flag.formatError = os.Getenv("GOVC_FORMAT_ERROR") != "false" // Default to formatted errors
|
||||
|
|
@ -159,6 +163,25 @@ func dumpValue(val interface{}) interface{} {
|
|||
return val
|
||||
}
|
||||
|
||||
type outputAny struct {
|
||||
Value any
|
||||
}
|
||||
|
||||
func (*outputAny) Write(io.Writer) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *outputAny) Dump() interface{} {
|
||||
return a.Value
|
||||
}
|
||||
|
||||
func (flag *OutputFlag) WriteAny(val any) error {
|
||||
if !flag.All() {
|
||||
flag.XML = true
|
||||
}
|
||||
return flag.WriteResult(&outputAny{val})
|
||||
}
|
||||
|
||||
func (flag *OutputFlag) WriteResult(result OutputWriter) error {
|
||||
var err error
|
||||
|
||||
|
|
@ -204,7 +227,7 @@ type errorOutput struct {
|
|||
}
|
||||
|
||||
func (e errorOutput) Write(w io.Writer) error {
|
||||
reason := e.error.Error()
|
||||
reason := e.Error()
|
||||
var messages []string
|
||||
var faults []types.LocalizableMessage
|
||||
|
||||
|
|
@ -261,15 +284,15 @@ func (e errorOutput) canEncode() bool {
|
|||
return soap.IsSoapFault(e.error) || soap.IsVimFault(e.error)
|
||||
}
|
||||
|
||||
// cannotEncode causes cli.Run to output err.Error() as it would without an error format specified
|
||||
var cannotEncode = errors.New("cannot encode error")
|
||||
// errCannotEncode causes cli.Run to output err.Error() as it would without an error format specified
|
||||
var errCannotEncode = errors.New("cannot encode error")
|
||||
|
||||
func (e errorOutput) MarshalJSON() ([]byte, error) {
|
||||
_, ok := e.error.(json.Marshaler)
|
||||
if ok || e.canEncode() {
|
||||
return json.Marshal(e.error)
|
||||
}
|
||||
return nil, cannotEncode
|
||||
return nil, errCannotEncode
|
||||
}
|
||||
|
||||
func (e errorOutput) MarshalXML(encoder *xml.Encoder, start xml.StartElement) error {
|
||||
|
|
@ -277,108 +300,9 @@ func (e errorOutput) MarshalXML(encoder *xml.Encoder, start xml.StartElement) er
|
|||
if ok || e.canEncode() {
|
||||
return encoder.Encode(e.error)
|
||||
}
|
||||
return cannotEncode
|
||||
return errCannotEncode
|
||||
}
|
||||
|
||||
type progressLogger struct {
|
||||
flag *OutputFlag
|
||||
prefix string
|
||||
|
||||
wg sync.WaitGroup
|
||||
|
||||
sink chan chan progress.Report
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
func newProgressLogger(flag *OutputFlag, prefix string) *progressLogger {
|
||||
p := &progressLogger{
|
||||
flag: flag,
|
||||
prefix: prefix,
|
||||
|
||||
sink: make(chan chan progress.Report),
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
|
||||
p.wg.Add(1)
|
||||
|
||||
go p.loopA()
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// loopA runs before Sink() has been called.
|
||||
func (p *progressLogger) loopA() {
|
||||
var err error
|
||||
|
||||
defer p.wg.Done()
|
||||
|
||||
tick := time.NewTicker(100 * time.Millisecond)
|
||||
defer tick.Stop()
|
||||
|
||||
called := false
|
||||
|
||||
for stop := false; !stop; {
|
||||
select {
|
||||
case ch := <-p.sink:
|
||||
err = p.loopB(tick, ch)
|
||||
stop = true
|
||||
called = true
|
||||
case <-p.done:
|
||||
stop = true
|
||||
case <-tick.C:
|
||||
line := fmt.Sprintf("\r%s", p.prefix)
|
||||
p.flag.Log(line)
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil && err != io.EOF {
|
||||
p.flag.Log(fmt.Sprintf("\r%sError: %s\n", p.prefix, err))
|
||||
} else if called {
|
||||
p.flag.Log(fmt.Sprintf("\r%sOK\n", p.prefix))
|
||||
}
|
||||
}
|
||||
|
||||
// loopA runs after Sink() has been called.
|
||||
func (p *progressLogger) loopB(tick *time.Ticker, ch <-chan progress.Report) error {
|
||||
var r progress.Report
|
||||
var ok bool
|
||||
var err error
|
||||
|
||||
for ok = true; ok; {
|
||||
select {
|
||||
case r, ok = <-ch:
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
err = r.Error()
|
||||
case <-tick.C:
|
||||
line := fmt.Sprintf("\r%s", p.prefix)
|
||||
if r != nil {
|
||||
line += fmt.Sprintf("(%.0f%%", r.Percentage())
|
||||
detail := r.Detail()
|
||||
if detail != "" {
|
||||
line += fmt.Sprintf(", %s", detail)
|
||||
}
|
||||
line += ")"
|
||||
}
|
||||
p.flag.Log(line)
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *progressLogger) Sink() chan<- progress.Report {
|
||||
ch := make(chan progress.Report)
|
||||
p.sink <- ch
|
||||
return ch
|
||||
}
|
||||
|
||||
func (p *progressLogger) Wait() {
|
||||
close(p.done)
|
||||
p.wg.Wait()
|
||||
}
|
||||
|
||||
func (flag *OutputFlag) ProgressLogger(prefix string) *progressLogger {
|
||||
return newProgressLogger(flag, prefix)
|
||||
func (flag *OutputFlag) ProgressLogger(prefix string) *progress.ProgressLogger {
|
||||
return progress.NewProgressLogger(flag.Log, prefix)
|
||||
}
|
||||
|
|
|
|||
74
vendor/github.com/vmware/govmomi/govc/importx/options.go
generated
vendored
74
vendor/github.com/vmware/govmomi/govc/importx/options.go
generated
vendored
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
Copyright (c) 2015-2023 VMware, Inc. All Rights Reserved.
|
||||
Copyright (c) 2015-2024 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
|
||||
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,
|
||||
|
|
@ -26,78 +26,12 @@ import (
|
|||
"github.com/vmware/govmomi/govc/flags"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/ovf"
|
||||
"github.com/vmware/govmomi/ovf/importer"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type KeyValue struct {
|
||||
Key string
|
||||
Value string
|
||||
}
|
||||
|
||||
// case insensitive for Key + Value
|
||||
func (kv *KeyValue) UnmarshalJSON(b []byte) error {
|
||||
e := struct {
|
||||
types.KeyValue
|
||||
Key *string
|
||||
Value *string
|
||||
}{
|
||||
types.KeyValue{}, &kv.Key, &kv.Value,
|
||||
}
|
||||
|
||||
err := json.Unmarshal(b, &e)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if kv.Key == "" {
|
||||
kv.Key = e.KeyValue.Key // "key"
|
||||
}
|
||||
|
||||
if kv.Value == "" {
|
||||
kv.Value = e.KeyValue.Value // "value"
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type Property struct {
|
||||
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
|
||||
Options importer.Options
|
||||
|
||||
path string
|
||||
}
|
||||
|
|
|
|||
15
vendor/github.com/vmware/govmomi/govc/importx/ova.go
generated
vendored
15
vendor/github.com/vmware/govmomi/govc/importx/ova.go
generated
vendored
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved.
|
||||
Copyright (c) 2014-2024 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
|
||||
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,
|
||||
|
|
@ -22,6 +22,7 @@ import (
|
|||
|
||||
"github.com/vmware/govmomi/govc/cli"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/ovf/importer"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
|
|
@ -43,21 +44,21 @@ func (cmd *ova) Run(ctx context.Context, f *flag.FlagSet) error {
|
|||
return err
|
||||
}
|
||||
|
||||
archive := &TapeArchive{Path: fpath}
|
||||
archive.Client = cmd.Client
|
||||
archive := &importer.TapeArchive{Path: fpath}
|
||||
archive.Client = cmd.Importer.Client
|
||||
|
||||
cmd.Archive = archive
|
||||
cmd.Importer.Archive = archive
|
||||
|
||||
moref, err := cmd.Import(fpath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vm := object.NewVirtualMachine(cmd.Client, *moref)
|
||||
vm := object.NewVirtualMachine(cmd.Importer.Client, *moref)
|
||||
return cmd.Deploy(vm, cmd.OutputFlag)
|
||||
}
|
||||
|
||||
func (cmd *ova) Import(fpath string) (*types.ManagedObjectReference, error) {
|
||||
ovf := "*.ovf"
|
||||
return cmd.ovfx.Import(ovf)
|
||||
return cmd.Importer.Import(context.TODO(), ovf, cmd.Options)
|
||||
}
|
||||
|
|
|
|||
337
vendor/github.com/vmware/govmomi/govc/importx/ovf.go
generated
vendored
337
vendor/github.com/vmware/govmomi/govc/importx/ovf.go
generated
vendored
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
Copyright (c) 2014-2023 VMware, Inc. All Rights Reserved.
|
||||
Copyright (c) 2014-2024 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.
|
||||
|
|
@ -17,23 +17,14 @@ limitations under the License.
|
|||
package importx
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"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"
|
||||
"github.com/vmware/govmomi/ovf/importer"
|
||||
)
|
||||
|
||||
type ovfx struct {
|
||||
|
|
@ -43,17 +34,9 @@ type ovfx struct {
|
|||
*flags.ResourcePoolFlag
|
||||
*flags.FolderFlag
|
||||
|
||||
*ArchiveFlag
|
||||
*OptionsFlag
|
||||
|
||||
Name string
|
||||
VerifyManifest bool
|
||||
Hidden bool
|
||||
|
||||
Client *vim25.Client
|
||||
Datacenter *object.Datacenter
|
||||
Datastore *object.Datastore
|
||||
ResourcePool *object.ResourcePool
|
||||
Importer importer.Importer
|
||||
}
|
||||
|
||||
func init() {
|
||||
|
|
@ -72,14 +55,12 @@ func (cmd *ovfx) Register(ctx context.Context, f *flag.FlagSet) {
|
|||
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")
|
||||
f.BoolVar(&cmd.VerifyManifest, "m", false, "Verify checksum of uploaded files against manifest (.mf)")
|
||||
f.BoolVar(&cmd.Hidden, "hidden", false, "Enable hidden properties")
|
||||
f.StringVar(&cmd.Importer.Name, "name", "", "Name to use for new entity")
|
||||
f.BoolVar(&cmd.Importer.VerifyManifest, "m", false, "Verify checksum of uploaded files against manifest (.mf)")
|
||||
f.BoolVar(&cmd.Importer.Hidden, "hidden", false, "Enable hidden properties")
|
||||
}
|
||||
|
||||
func (cmd *ovfx) Process(ctx context.Context) error {
|
||||
|
|
@ -95,9 +76,6 @@ func (cmd *ovfx) Process(ctx context.Context) error {
|
|||
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
|
||||
}
|
||||
|
|
@ -117,17 +95,17 @@ func (cmd *ovfx) Run(ctx context.Context, f *flag.FlagSet) error {
|
|||
return err
|
||||
}
|
||||
|
||||
archive := &FileArchive{Path: fpath}
|
||||
archive.Client = cmd.Client
|
||||
archive := &importer.FileArchive{Path: fpath}
|
||||
archive.Client = cmd.Importer.Client
|
||||
|
||||
cmd.Archive = archive
|
||||
cmd.Importer.Archive = archive
|
||||
|
||||
moref, err := cmd.Import(fpath)
|
||||
moref, err := cmd.Importer.Import(context.TODO(), fpath, cmd.Options)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
vm := object.NewVirtualMachine(cmd.Client, *moref)
|
||||
vm := object.NewVirtualMachine(cmd.Importer.Client, *moref)
|
||||
return cmd.Deploy(vm, cmd.OutputFlag)
|
||||
}
|
||||
|
||||
|
|
@ -139,313 +117,70 @@ func (cmd *ovfx) Prepare(f *flag.FlagSet) (string, error) {
|
|||
return "", errors.New("no file specified")
|
||||
}
|
||||
|
||||
cmd.Client, err = cmd.DatastoreFlag.Client()
|
||||
cmd.Importer.Log = cmd.OutputFlag.Log
|
||||
cmd.Importer.Client, err = cmd.DatastoreFlag.Client()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
cmd.Datacenter, err = cmd.DatastoreFlag.Datacenter()
|
||||
cmd.Importer.Datacenter, err = cmd.DatastoreFlag.Datacenter()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
cmd.Datastore, err = cmd.DatastoreFlag.Datastore()
|
||||
cmd.Importer.Datastore, err = cmd.DatastoreFlag.Datastore()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
cmd.ResourcePool, err = cmd.ResourcePoolFlag.ResourcePoolIfSpecified()
|
||||
cmd.Importer.ResourcePool, err = cmd.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, types.KeyValue{
|
||||
Key: v.Key,
|
||||
Value: v.Value,
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func (cmd *ovfx) validateNetwork(e *ovf.Envelope, net Network) {
|
||||
var names []string
|
||||
|
||||
if e.Network != nil {
|
||||
for _, n := range e.Network.Networks {
|
||||
if n.Name == net.Name {
|
||||
return
|
||||
}
|
||||
names = append(names, n.Name)
|
||||
}
|
||||
}
|
||||
|
||||
_, _ = cmd.Log(fmt.Sprintf("Warning: invalid NetworkMapping.Name=%q, valid names=%s\n", net.Name, names))
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
cmd.validateNetwork(e, m)
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
if cmd.Hidden {
|
||||
// TODO: userConfigurable is optional and defaults to false, so we should *add* userConfigurable=true
|
||||
// if not set for a Property. But, there'd be a bunch more work involved to preserve other data in doing
|
||||
// a complete xml.Marshal of the .ovf
|
||||
o = bytes.ReplaceAll(o, []byte(`userConfigurable="false"`), []byte(`userConfigurable="true"`))
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
return "", err
|
||||
}
|
||||
|
||||
if cmd.ResourcePool == nil {
|
||||
if cmd.Importer.ResourcePool == nil {
|
||||
if host == nil {
|
||||
cmd.ResourcePool, err = cmd.ResourcePoolFlag.ResourcePool()
|
||||
cmd.Importer.ResourcePool, err = cmd.ResourcePoolFlag.ResourcePool()
|
||||
} else {
|
||||
cmd.ResourcePool, err = host.ResourcePool(ctx)
|
||||
cmd.Importer.ResourcePool, err = host.ResourcePool(context.TODO())
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
m := ovf.NewManager(cmd.Client)
|
||||
spec, err := m.CreateImportSpec(ctx, string(o), cmd.ResourcePool, cmd.Datastore, cisp)
|
||||
cmd.Importer.Finder, err = cmd.DatastoreFlag.Finder()
|
||||
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))
|
||||
}
|
||||
return "", err
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
cmd.Importer.Host, err = cmd.HostSystemIfSpecified()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
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 cmd.Importer.ResourcePool.Reference().Type != "VirtualApp" {
|
||||
cmd.Importer.Folder, err = cmd.FolderOrDefault("vm")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return "", err
|
||||
}
|
||||
}
|
||||
|
||||
if cmd.VerifyManifest {
|
||||
err = cmd.readManifest(fpath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
if cmd.Importer.Name == "" {
|
||||
// Override name from options if specified
|
||||
if cmd.Options.Name != nil {
|
||||
cmd.Importer.Name = *cmd.Options.Name
|
||||
}
|
||||
} else {
|
||||
cmd.Options.Name = &cmd.Importer.Name
|
||||
}
|
||||
|
||||
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,
|
||||
}
|
||||
|
||||
err = lease.Upload(ctx, item, f, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if cmd.VerifyManifest {
|
||||
mapImportKeyToKey := func(urls []types.HttpNfcLeaseDeviceUrl, importKey string) string {
|
||||
for _, url := range urls {
|
||||
if url.ImportKey == importKey {
|
||||
return url.Key
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
leaseInfo, err := lease.Wait(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return cmd.validateChecksum(ctx, lease, file, mapImportKeyToKey(leaseInfo.DeviceUrl, item.DeviceId))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cmd *ovfx) validateChecksum(ctx context.Context, lease *nfc.Lease, file string, key string) error {
|
||||
sum, found := cmd.manifest[file]
|
||||
if !found {
|
||||
msg := fmt.Sprintf("missing checksum for %v in manifest file", file)
|
||||
return errors.New(msg)
|
||||
}
|
||||
// Perform the checksum match eagerly, after each file upload, instead
|
||||
// of after uploading all the files, to provide fail-fast behavior.
|
||||
// (Trade-off here is multiple GetManifest() API calls to the server.)
|
||||
manifests, err := lease.GetManifest(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, m := range manifests {
|
||||
if m.Key == key {
|
||||
// Compare server-side computed checksum of uploaded file
|
||||
// against the client's manifest entry (assuming client's
|
||||
// manifest has correct checksums - client doesn't compute
|
||||
// checksum of the file before uploading).
|
||||
|
||||
// Try matching sha1 first (newer versions have moved to sha256).
|
||||
if strings.ToUpper(sum.Algorithm) == "SHA1" {
|
||||
if sum.Checksum != m.Sha1 {
|
||||
msg := fmt.Sprintf("manifest checksum %v mismatch with uploaded checksum %v for file %v",
|
||||
sum.Checksum, m.Sha1, file)
|
||||
return errors.New(msg)
|
||||
}
|
||||
// Uploaded file checksum computed by server matches with local manifest entry.
|
||||
return nil
|
||||
}
|
||||
// If not sha1, check for other types (in a separate field).
|
||||
if !strings.EqualFold(sum.Algorithm, m.ChecksumType) {
|
||||
msg := fmt.Sprintf("manifest checksum type %v mismatch with uploaded checksum type %v for file %v",
|
||||
sum.Algorithm, m.ChecksumType, file)
|
||||
return errors.New(msg)
|
||||
}
|
||||
if !strings.EqualFold(sum.Checksum, m.Checksum) {
|
||||
msg := fmt.Sprintf("manifest checksum %v mismatch with uploaded checksum %v for file %v",
|
||||
sum.Checksum, m.Checksum, file)
|
||||
return errors.New(msg)
|
||||
}
|
||||
// Uploaded file checksum computed by server matches with local manifest entry.
|
||||
return nil
|
||||
}
|
||||
}
|
||||
msg := fmt.Sprintf("missing manifest entry on server for uploaded file %v (key %v), manifests=%#v", file, key, manifests)
|
||||
return errors.New(msg)
|
||||
return f.Arg(0), nil
|
||||
}
|
||||
|
|
|
|||
139
vendor/github.com/vmware/govmomi/govc/importx/spec.go
generated
vendored
139
vendor/github.com/vmware/govmomi/govc/importx/spec.go
generated
vendored
|
|
@ -22,27 +22,18 @@ import (
|
|||
"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 = types.OvfCreateImportSpecParamsDiskProvisioningType("").Strings()
|
||||
|
||||
allIPAllocationPolicyOptions = types.VAppIPAssignmentInfoIpAllocationPolicy("").Strings()
|
||||
|
||||
allIPProtocolOptions = types.VAppIPAssignmentInfoProtocols("").Strings()
|
||||
"github.com/vmware/govmomi/ovf/importer"
|
||||
)
|
||||
|
||||
type spec struct {
|
||||
*ArchiveFlag
|
||||
*flags.ClientFlag
|
||||
*flags.OutputFlag
|
||||
|
||||
Archive importer.Archive
|
||||
|
||||
hidden bool
|
||||
}
|
||||
|
||||
|
|
@ -51,8 +42,6 @@ func init() {
|
|||
}
|
||||
|
||||
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)
|
||||
|
||||
|
|
@ -63,9 +52,6 @@ func (cmd *spec) Register(ctx context.Context, f *flag.FlagSet) {
|
|||
}
|
||||
|
||||
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
|
||||
}
|
||||
|
|
@ -86,29 +72,29 @@ func (cmd *spec) Run(ctx context.Context, f *flag.FlagSet) error {
|
|||
if len(fpath) > 0 {
|
||||
switch path.Ext(fpath) {
|
||||
case ".ovf":
|
||||
cmd.Archive = &FileArchive{Path: fpath}
|
||||
cmd.Archive = &importer.FileArchive{Path: fpath}
|
||||
case "", ".ova":
|
||||
cmd.Archive = &TapeArchive{Path: fpath}
|
||||
cmd.Archive = &importer.TapeArchive{Path: fpath}
|
||||
fpath = "*.ovf"
|
||||
default:
|
||||
return fmt.Errorf("invalid file extension %s", path.Ext(fpath))
|
||||
}
|
||||
|
||||
if isRemotePath(f.Arg(0)) {
|
||||
if importer.IsRemotePath(f.Arg(0)) {
|
||||
client, err := cmd.Client()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
switch archive := cmd.Archive.(type) {
|
||||
case *FileArchive:
|
||||
case *importer.FileArchive:
|
||||
archive.Client = client
|
||||
case *TapeArchive:
|
||||
case *importer.TapeArchive:
|
||||
archive.Client = client
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
env, err := cmd.Spec(fpath)
|
||||
env, err := importer.Spec(fpath, cmd.Archive, cmd.hidden, cmd.Verbose())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -120,114 +106,9 @@ func (cmd *spec) Run(ctx context.Context, f *flag.FlagSet) error {
|
|||
}
|
||||
|
||||
type specResult struct {
|
||||
*Options
|
||||
*importer.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 {
|
||||
continue
|
||||
}
|
||||
if !*v.UserConfigurable && !cmd.hidden {
|
||||
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)
|
||||
}
|
||||
|
||||
np := Property{KeyValue: KeyValue{Key: p.Key(v), 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
|
||||
}
|
||||
|
|
|
|||
11
vendor/github.com/vmware/govmomi/govc/vm/clone.go
generated
vendored
11
vendor/github.com/vmware/govmomi/govc/vm/clone.go
generated
vendored
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
Copyright (c) 2014-2016 VMware, Inc. All Rights Reserved.
|
||||
Copyright (c) 2016-2024 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
|
||||
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,
|
||||
|
|
@ -243,6 +243,9 @@ func (cmd *clone) Run(ctx context.Context, f *flag.FlagSet) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cmd.Spec {
|
||||
return nil
|
||||
}
|
||||
|
||||
if cmd.cpus > 0 || cmd.memory > 0 || cmd.annotation != "" {
|
||||
vmConfigSpec := types.VirtualMachineConfigSpec{}
|
||||
|
|
@ -471,6 +474,10 @@ func (cmd *clone) cloneVM(ctx context.Context) (*object.VirtualMachine, error) {
|
|||
cloneSpec.Customization = &customSpec
|
||||
}
|
||||
|
||||
if cmd.Spec {
|
||||
return nil, cmd.WriteAny(cloneSpec)
|
||||
}
|
||||
|
||||
task, err := cmd.VirtualMachine.Clone(ctx, cmd.Folder, cmd.name, *cloneSpec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
16
vendor/github.com/vmware/govmomi/govc/vm/create.go
generated
vendored
16
vendor/github.com/vmware/govmomi/govc/vm/create.go
generated
vendored
|
|
@ -307,7 +307,7 @@ func (cmd *create) Run(ctx context.Context, f *flag.FlagSet) error {
|
|||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if cmd.place {
|
||||
if cmd.place || cmd.Spec {
|
||||
return nil
|
||||
}
|
||||
info, err := task.WaitForResult(ctx, nil)
|
||||
|
|
@ -490,7 +490,7 @@ func (cmd *create) createVM(ctx context.Context) (*object.Task, error) {
|
|||
return nil, fmt.Errorf("please provide either a cluster, datastore or datastore-cluster")
|
||||
}
|
||||
|
||||
if !cmd.force {
|
||||
if !cmd.force && !cmd.Spec {
|
||||
vmxPath := fmt.Sprintf("%s/%s.vmx", cmd.name, cmd.name)
|
||||
|
||||
_, err := datastore.Stat(ctx, vmxPath)
|
||||
|
|
@ -506,6 +506,10 @@ func (cmd *create) createVM(ctx context.Context) (*object.Task, error) {
|
|||
VmPathName: fmt.Sprintf("[%s]", datastore.Name()),
|
||||
}
|
||||
|
||||
if cmd.Spec {
|
||||
return nil, cmd.WriteAny(spec)
|
||||
}
|
||||
|
||||
return folder.CreateVM(ctx, *spec, cmd.ResourcePool, cmd.HostSystem)
|
||||
}
|
||||
|
||||
|
|
@ -519,6 +523,14 @@ func (cmd *create) addStorage(devices object.VirtualDeviceList) (object.VirtualD
|
|||
|
||||
devices = append(devices, nvme)
|
||||
cmd.controller = devices.Name(nvme)
|
||||
} else if cmd.controller == "sata" {
|
||||
sata, err := devices.CreateSATAController()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
devices = append(devices, sata)
|
||||
cmd.controller = devices.Name(sata)
|
||||
} else {
|
||||
scsi, err := devices.CreateSCSIController(cmd.controller)
|
||||
if err != nil {
|
||||
|
|
|
|||
42
vendor/github.com/vmware/govmomi/govc/vm/migrate.go
generated
vendored
42
vendor/github.com/vmware/govmomi/govc/vm/migrate.go
generated
vendored
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
Copyright (c) 2016-2024 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
|
||||
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,
|
||||
|
|
@ -32,6 +32,7 @@ type migrate struct {
|
|||
*flags.ResourcePoolFlag
|
||||
*flags.HostSystemFlag
|
||||
*flags.DatastoreFlag
|
||||
*flags.NetworkFlag
|
||||
*flags.VirtualMachineFlag
|
||||
|
||||
priority types.VirtualMachineMovePriority
|
||||
|
|
@ -58,6 +59,9 @@ func (cmd *migrate) Register(ctx context.Context, f *flag.FlagSet) {
|
|||
cmd.DatastoreFlag, ctx = flags.NewDatastoreFlag(ctx)
|
||||
cmd.DatastoreFlag.Register(ctx, f)
|
||||
|
||||
cmd.NetworkFlag, ctx = flags.NewNetworkFlag(ctx)
|
||||
cmd.NetworkFlag.Register(ctx, f)
|
||||
|
||||
f.StringVar((*string)(&cmd.priority), "priority", string(types.VirtualMachineMovePriorityDefaultPriority), "The task priority")
|
||||
}
|
||||
|
||||
|
|
@ -77,6 +81,9 @@ func (cmd *migrate) Process(ctx context.Context) error {
|
|||
if err := cmd.DatastoreFlag.Process(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := cmd.NetworkFlag.Process(ctx); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
@ -95,7 +102,36 @@ Examples:
|
|||
}
|
||||
|
||||
func (cmd *migrate) relocate(ctx context.Context, vm *object.VirtualMachine) error {
|
||||
task, err := vm.Relocate(ctx, cmd.spec, cmd.priority)
|
||||
spec := cmd.spec
|
||||
|
||||
if cmd.NetworkFlag.IsSet() {
|
||||
dev, err := cmd.NetworkFlag.Device()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
devices, err := vm.Device(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
net := devices.SelectByType((*types.VirtualEthernetCard)(nil))
|
||||
if len(net) != 1 {
|
||||
return fmt.Errorf("-net specified, but %s has %d nics", vm.Name(), len(net))
|
||||
}
|
||||
cmd.NetworkFlag.Change(net[0], dev)
|
||||
|
||||
spec.DeviceChange = append(spec.DeviceChange, &types.VirtualDeviceConfigSpec{
|
||||
Device: net[0],
|
||||
Operation: types.VirtualDeviceConfigSpecOperationEdit,
|
||||
})
|
||||
}
|
||||
|
||||
if cmd.VirtualMachineFlag.Spec {
|
||||
return cmd.VirtualMachineFlag.WriteAny(spec)
|
||||
}
|
||||
|
||||
task, err := vm.Relocate(ctx, spec, cmd.priority)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
2
vendor/github.com/vmware/govmomi/internal/version/version.go
generated
vendored
2
vendor/github.com/vmware/govmomi/internal/version/version.go
generated
vendored
|
|
@ -21,5 +21,5 @@ const (
|
|||
ClientName = "govmomi"
|
||||
|
||||
// ClientVersion is the version of this SDK
|
||||
ClientVersion = "0.38.0"
|
||||
ClientVersion = "0.39.0"
|
||||
)
|
||||
|
|
|
|||
77
vendor/github.com/vmware/govmomi/object/virtual_device_list.go
generated
vendored
77
vendor/github.com/vmware/govmomi/object/virtual_device_list.go
generated
vendored
|
|
@ -361,6 +361,77 @@ func (l VirtualDeviceList) newNVMEBusNumber() int32 {
|
|||
return -1
|
||||
}
|
||||
|
||||
// FindSATAController will find the named SATA or AHCI controller if given, otherwise will pick an available controller.
|
||||
// An error is returned if the named controller is not found or not a SATA or AHCI controller. Or, if name is not
|
||||
// given and no available controller can be found.
|
||||
func (l VirtualDeviceList) FindSATAController(name string) (types.BaseVirtualController, error) {
|
||||
if name != "" {
|
||||
d := l.Find(name)
|
||||
if d == nil {
|
||||
return nil, fmt.Errorf("device '%s' not found", name)
|
||||
}
|
||||
switch c := d.(type) {
|
||||
case *types.VirtualSATAController:
|
||||
return c, nil
|
||||
case *types.VirtualAHCIController:
|
||||
return c, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("%s is not a SATA or AHCI controller", name)
|
||||
}
|
||||
}
|
||||
|
||||
c := l.PickController((*types.VirtualSATAController)(nil))
|
||||
if c == nil {
|
||||
c = l.PickController((*types.VirtualAHCIController)(nil))
|
||||
}
|
||||
if c == nil {
|
||||
return nil, errors.New("no available SATA or AHCI controller")
|
||||
}
|
||||
|
||||
switch c := c.(type) {
|
||||
case *types.VirtualSATAController:
|
||||
return c, nil
|
||||
case *types.VirtualAHCIController:
|
||||
return c, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("unexpected controller type")
|
||||
}
|
||||
|
||||
// CreateSATAController creates a new SATA controller.
|
||||
func (l VirtualDeviceList) CreateSATAController() (types.BaseVirtualDevice, error) {
|
||||
sata := &types.VirtualAHCIController{}
|
||||
sata.BusNumber = l.newSATABusNumber()
|
||||
sata.Key = l.NewKey()
|
||||
|
||||
return sata, nil
|
||||
}
|
||||
|
||||
var sataBusNumbers = []int{0, 1, 2, 3}
|
||||
|
||||
// newSATABusNumber returns the bus number to use for adding a new SATA bus device.
|
||||
// -1 is returned if there are no bus numbers available.
|
||||
func (l VirtualDeviceList) newSATABusNumber() int32 {
|
||||
var used []int
|
||||
|
||||
for _, d := range l.SelectByType((*types.VirtualSATAController)(nil)) {
|
||||
num := d.(types.BaseVirtualController).GetVirtualController().BusNumber
|
||||
if num >= 0 {
|
||||
used = append(used, int(num))
|
||||
} // else caller is creating a new vm using SATAControllerTypes
|
||||
}
|
||||
|
||||
sort.Ints(used)
|
||||
|
||||
for i, n := range sataBusNumbers {
|
||||
if i == len(used) || n != used[i] {
|
||||
return int32(n)
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
// FindDiskController will find an existing ide or scsi disk controller.
|
||||
func (l VirtualDeviceList) FindDiskController(name string) (types.BaseVirtualController, error) {
|
||||
switch {
|
||||
|
|
@ -370,6 +441,8 @@ func (l VirtualDeviceList) FindDiskController(name string) (types.BaseVirtualCon
|
|||
return l.FindSCSIController("")
|
||||
case name == "nvme":
|
||||
return l.FindNVMEController("")
|
||||
case name == "sata":
|
||||
return l.FindSATAController("")
|
||||
default:
|
||||
if c, ok := l.Find(name).(types.BaseVirtualController); ok {
|
||||
return c, nil
|
||||
|
|
@ -389,6 +462,8 @@ func (l VirtualDeviceList) PickController(kind types.BaseVirtualController) type
|
|||
return num < 15
|
||||
case *types.VirtualIDEController:
|
||||
return num < 2
|
||||
case types.BaseVirtualSATAController:
|
||||
return num < 30
|
||||
case *types.VirtualNVMEController:
|
||||
return num < 8
|
||||
default:
|
||||
|
|
@ -909,8 +984,6 @@ func (l VirtualDeviceList) Type(device types.BaseVirtualDevice) string {
|
|||
return "pvscsi"
|
||||
case *types.VirtualLsiLogicSASController:
|
||||
return "lsilogic-sas"
|
||||
case *types.VirtualNVMEController:
|
||||
return "nvme"
|
||||
case *types.VirtualPrecisionClock:
|
||||
return "clock"
|
||||
default:
|
||||
|
|
|
|||
27
vendor/github.com/vmware/govmomi/object/virtual_disk_manager.go
generated
vendored
27
vendor/github.com/vmware/govmomi/object/virtual_disk_manager.go
generated
vendored
|
|
@ -94,6 +94,33 @@ func (m VirtualDiskManager) CreateVirtualDisk(
|
|||
return NewTask(m.c, res.Returnval), nil
|
||||
}
|
||||
|
||||
// ExtendVirtualDisk extends an existing virtual disk.
|
||||
func (m VirtualDiskManager) ExtendVirtualDisk(
|
||||
ctx context.Context,
|
||||
name string, datacenter *Datacenter,
|
||||
capacityKb int64,
|
||||
eagerZero *bool) (*Task, error) {
|
||||
|
||||
req := types.ExtendVirtualDisk_Task{
|
||||
This: m.Reference(),
|
||||
Name: name,
|
||||
NewCapacityKb: capacityKb,
|
||||
EagerZero: eagerZero,
|
||||
}
|
||||
|
||||
if datacenter != nil {
|
||||
ref := datacenter.Reference()
|
||||
req.Datacenter = &ref
|
||||
}
|
||||
|
||||
res, err := methods.ExtendVirtualDisk_Task(ctx, m.c, &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewTask(m.c, res.Returnval), nil
|
||||
}
|
||||
|
||||
// MoveVirtualDisk moves a virtual disk.
|
||||
func (m VirtualDiskManager) MoveVirtualDisk(
|
||||
ctx context.Context,
|
||||
|
|
|
|||
111
vendor/github.com/vmware/govmomi/object/vm_compatability_checker.go
generated
vendored
Normal file
111
vendor/github.com/vmware/govmomi/object/vm_compatability_checker.go
generated
vendored
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
Copyright (c) 2024-2024 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 object
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/vmware/govmomi/vim25"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
// VmCompatibilityChecker models the CompatibilityChecker, a singleton managed
|
||||
// object that can answer questions about compatibility of a virtual machine
|
||||
// with a host.
|
||||
//
|
||||
// For more information, see:
|
||||
// https://dp-downloads.broadcom.com/api-content/apis/API_VWSA_001/8.0U3/html/ReferenceGuides/vim.vm.check.CompatibilityChecker.html
|
||||
type VmCompatibilityChecker struct {
|
||||
Common
|
||||
}
|
||||
|
||||
func NewVmCompatibilityChecker(c *vim25.Client) *VmCompatibilityChecker {
|
||||
return &VmCompatibilityChecker{
|
||||
Common: NewCommon(c, *c.ServiceContent.VmCompatibilityChecker),
|
||||
}
|
||||
}
|
||||
|
||||
func (c VmCompatibilityChecker) CheckCompatibility(
|
||||
ctx context.Context,
|
||||
vm types.ManagedObjectReference,
|
||||
host *types.ManagedObjectReference,
|
||||
pool *types.ManagedObjectReference,
|
||||
testTypes ...types.CheckTestType) ([]types.CheckResult, error) {
|
||||
|
||||
req := types.CheckCompatibility_Task{
|
||||
This: c.Reference(),
|
||||
Vm: vm,
|
||||
Host: host,
|
||||
Pool: pool,
|
||||
TestType: checkTestTypesToStrings(testTypes),
|
||||
}
|
||||
|
||||
res, err := methods.CheckCompatibility_Task(ctx, c.c, &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ti, err := NewTask(c.c, res.Returnval).WaitForResult(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ti.Result.(types.ArrayOfCheckResult).CheckResult, nil
|
||||
}
|
||||
|
||||
func (c VmCompatibilityChecker) CheckVmConfig(
|
||||
ctx context.Context,
|
||||
spec types.VirtualMachineConfigSpec,
|
||||
vm *types.ManagedObjectReference,
|
||||
host *types.ManagedObjectReference,
|
||||
pool *types.ManagedObjectReference,
|
||||
testTypes ...types.CheckTestType) ([]types.CheckResult, error) {
|
||||
|
||||
req := types.CheckVmConfig_Task{
|
||||
This: c.Reference(),
|
||||
Spec: spec,
|
||||
Vm: vm,
|
||||
Host: host,
|
||||
Pool: pool,
|
||||
TestType: checkTestTypesToStrings(testTypes),
|
||||
}
|
||||
|
||||
res, err := methods.CheckVmConfig_Task(ctx, c.c, &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ti, err := NewTask(c.c, res.Returnval).WaitForResult(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ti.Result.(types.ArrayOfCheckResult).CheckResult, nil
|
||||
}
|
||||
|
||||
func checkTestTypesToStrings(testTypes []types.CheckTestType) []string {
|
||||
if len(testTypes) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
s := make([]string, len(testTypes))
|
||||
for i := range testTypes {
|
||||
s[i] = string(testTypes[i])
|
||||
}
|
||||
return s
|
||||
}
|
||||
67
vendor/github.com/vmware/govmomi/object/vm_provisioning_checker.go
generated
vendored
Normal file
67
vendor/github.com/vmware/govmomi/object/vm_provisioning_checker.go
generated
vendored
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
/*
|
||||
Copyright (c) 2024-2024 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 object
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/vmware/govmomi/vim25"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
// VmProvisioningChecker models the ProvisioningChecker, a singleton managed
|
||||
// object that can answer questions about the feasibility of certain
|
||||
// provisioning operations.
|
||||
//
|
||||
// For more information, see:
|
||||
// https://dp-downloads.broadcom.com/api-content/apis/API_VWSA_001/8.0U3/html/ReferenceGuides/vim.vm.check.ProvisioningChecker.html
|
||||
type VmProvisioningChecker struct {
|
||||
Common
|
||||
}
|
||||
|
||||
func NewVmProvisioningChecker(c *vim25.Client) *VmProvisioningChecker {
|
||||
return &VmProvisioningChecker{
|
||||
Common: NewCommon(c, *c.ServiceContent.VmProvisioningChecker),
|
||||
}
|
||||
}
|
||||
|
||||
func (c VmProvisioningChecker) CheckRelocate(
|
||||
ctx context.Context,
|
||||
vm types.ManagedObjectReference,
|
||||
spec types.VirtualMachineRelocateSpec,
|
||||
testTypes ...types.CheckTestType) ([]types.CheckResult, error) {
|
||||
|
||||
req := types.CheckRelocate_Task{
|
||||
This: c.Reference(),
|
||||
Vm: vm,
|
||||
Spec: spec,
|
||||
TestType: checkTestTypesToStrings(testTypes),
|
||||
}
|
||||
|
||||
res, err := methods.CheckRelocate_Task(ctx, c.c, &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
ti, err := NewTask(c.c, res.Returnval).WaitForResult(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ti.Result.(types.ArrayOfCheckResult).CheckResult, nil
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved.
|
||||
Copyright (c) 2024-2024 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
|
||||
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,
|
||||
|
|
@ -14,14 +14,13 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package importx
|
||||
package importer
|
||||
|
||||
import (
|
||||
"archive/tar"
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
|
|
@ -31,32 +30,12 @@ import (
|
|||
"strings"
|
||||
|
||||
"github.com/vmware/govmomi/ovf"
|
||||
"github.com/vmware/govmomi/vapi/library"
|
||||
"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
|
||||
|
||||
manifest map[string]*library.Checksum
|
||||
}
|
||||
|
||||
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)
|
||||
func ReadOvf(fpath string, a Archive) ([]byte, error) {
|
||||
r, _, err := a.Open(fpath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -65,7 +44,7 @@ func (f *ArchiveFlag) ReadOvf(fpath string) ([]byte, error) {
|
|||
return io.ReadAll(r)
|
||||
}
|
||||
|
||||
func (f *ArchiveFlag) ReadEnvelope(data []byte) (*ovf.Envelope, error) {
|
||||
func 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)
|
||||
|
|
@ -74,22 +53,6 @@ func (f *ArchiveFlag) ReadEnvelope(data []byte) (*ovf.Envelope, error) {
|
|||
return e, nil
|
||||
}
|
||||
|
||||
func (f *ArchiveFlag) readManifest(fpath string) error {
|
||||
base := filepath.Base(fpath)
|
||||
ext := filepath.Ext(base)
|
||||
mfName := strings.Replace(base, ext, ".mf", 1)
|
||||
|
||||
mf, _, err := f.Open(mfName)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("manifest %q: %s", mf, err)
|
||||
fmt.Fprintln(os.Stderr, msg)
|
||||
return errors.New(msg)
|
||||
}
|
||||
f.manifest, err = library.ReadManifest(mf)
|
||||
_ = mf.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
type Archive interface {
|
||||
Open(string) (io.ReadCloser, int64, error)
|
||||
}
|
||||
|
|
@ -163,7 +126,7 @@ type Opener struct {
|
|||
*vim25.Client
|
||||
}
|
||||
|
||||
func isRemotePath(path string) bool {
|
||||
func IsRemotePath(path string) bool {
|
||||
if strings.HasPrefix(path, "http://") || strings.HasPrefix(path, "https://") {
|
||||
return true
|
||||
}
|
||||
|
|
@ -185,7 +148,7 @@ func (o Opener) OpenLocal(path string) (io.ReadCloser, int64, error) {
|
|||
}
|
||||
|
||||
func (o Opener) OpenFile(path string) (io.ReadCloser, int64, error) {
|
||||
if isRemotePath(path) {
|
||||
if IsRemotePath(path) {
|
||||
return o.OpenRemote(path)
|
||||
}
|
||||
return o.OpenLocal(path)
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
/*
|
||||
Copyright (c) 2014 VMware, Inc. All Rights Reserved.
|
||||
Copyright (c) 2024-2024 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
|
||||
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,
|
||||
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
package importx
|
||||
package importer
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
326
vendor/github.com/vmware/govmomi/ovf/importer/importer.go
generated
vendored
Normal file
326
vendor/github.com/vmware/govmomi/ovf/importer/importer.go
generated
vendored
Normal file
|
|
@ -0,0 +1,326 @@
|
|||
/*
|
||||
Copyright (c) 2024-2024 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 importer
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
"github.com/vmware/govmomi/find"
|
||||
"github.com/vmware/govmomi/nfc"
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/ovf"
|
||||
"github.com/vmware/govmomi/vapi/library"
|
||||
"github.com/vmware/govmomi/vim25"
|
||||
"github.com/vmware/govmomi/vim25/progress"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type Importer struct {
|
||||
Log progress.LogFunc
|
||||
|
||||
Name string
|
||||
VerifyManifest bool
|
||||
Hidden bool
|
||||
|
||||
Client *vim25.Client
|
||||
Finder *find.Finder
|
||||
Sinker progress.Sinker
|
||||
|
||||
Datacenter *object.Datacenter
|
||||
Datastore *object.Datastore
|
||||
ResourcePool *object.ResourcePool
|
||||
Host *object.HostSystem
|
||||
Folder *object.Folder
|
||||
|
||||
Archive Archive
|
||||
Manifest map[string]*library.Checksum
|
||||
}
|
||||
|
||||
func (imp *Importer) ReadManifest(fpath string) error {
|
||||
base := filepath.Base(fpath)
|
||||
ext := filepath.Ext(base)
|
||||
mfName := strings.Replace(base, ext, ".mf", 1)
|
||||
|
||||
mf, _, err := imp.Archive.Open(mfName)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("manifest %q: %s", mf, err)
|
||||
fmt.Fprintln(os.Stderr, msg)
|
||||
return errors.New(msg)
|
||||
}
|
||||
imp.Manifest, err = library.ReadManifest(mf)
|
||||
_ = mf.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
func (imp *Importer) Import(ctx context.Context, fpath string, opts Options) (*types.ManagedObjectReference, error) {
|
||||
|
||||
o, err := ReadOvf(fpath, imp.Archive)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
e, err := ReadEnvelope(o)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse ovf: %s", err)
|
||||
}
|
||||
|
||||
if e.VirtualSystem != nil {
|
||||
if e.VirtualSystem != nil {
|
||||
if opts.Name == nil {
|
||||
opts.Name = &e.VirtualSystem.ID
|
||||
if e.VirtualSystem.Name != nil {
|
||||
opts.Name = e.VirtualSystem.Name
|
||||
}
|
||||
}
|
||||
}
|
||||
if imp.Hidden {
|
||||
// TODO: userConfigurable is optional and defaults to false, so we should *add* userConfigurable=true
|
||||
// if not set for a Property. But, there'd be a bunch more work involved to preserve other data in doing
|
||||
// a complete xml.Marshal of the .ovf
|
||||
o = bytes.ReplaceAll(o, []byte(`userConfigurable="false"`), []byte(`userConfigurable="true"`))
|
||||
}
|
||||
}
|
||||
|
||||
name := "Govc Virtual Appliance"
|
||||
if opts.Name != nil {
|
||||
name = *opts.Name
|
||||
}
|
||||
|
||||
nmap, err := imp.NetworkMap(ctx, e, opts.NetworkMapping)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cisp := types.OvfCreateImportSpecParams{
|
||||
DiskProvisioning: opts.DiskProvisioning,
|
||||
EntityName: name,
|
||||
IpAllocationPolicy: opts.IPAllocationPolicy,
|
||||
IpProtocol: opts.IPProtocol,
|
||||
OvfManagerCommonParams: types.OvfManagerCommonParams{
|
||||
DeploymentOption: opts.Deployment,
|
||||
Locale: "US"},
|
||||
PropertyMapping: OVFMap(opts.PropertyMapping),
|
||||
NetworkMapping: nmap,
|
||||
}
|
||||
|
||||
m := ovf.NewManager(imp.Client)
|
||||
spec, err := m.CreateImportSpec(ctx, string(o), imp.ResourcePool, imp.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 {
|
||||
_, _ = imp.Log(fmt.Sprintf("Warning: %s\n", w.LocalizedMessage))
|
||||
}
|
||||
}
|
||||
|
||||
if opts.Annotation != "" {
|
||||
switch s := spec.ImportSpec.(type) {
|
||||
case *types.VirtualMachineImportSpec:
|
||||
s.ConfigSpec.Annotation = opts.Annotation
|
||||
case *types.VirtualAppImportSpec:
|
||||
s.VAppConfigSpec.Annotation = opts.Annotation
|
||||
}
|
||||
}
|
||||
|
||||
if imp.VerifyManifest {
|
||||
if err := imp.ReadManifest(fpath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
lease, err := imp.ResourcePool.ImportVApp(ctx, spec.ImportSpec, imp.Folder, imp.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 {
|
||||
if err := imp.Upload(ctx, lease, i); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
return &info.Entity, lease.Complete(ctx)
|
||||
}
|
||||
|
||||
func (imp *Importer) NetworkMap(ctx context.Context, e *ovf.Envelope, networks []Network) ([]types.OvfNetworkMapping, error) {
|
||||
var nmap []types.OvfNetworkMapping
|
||||
for _, m := range networks {
|
||||
if m.Network == "" {
|
||||
continue // Not set, let vSphere choose the default network
|
||||
}
|
||||
if err := ValidateNetwork(e, m); err != nil && imp.Log != nil {
|
||||
_, _ = imp.Log(err.Error() + "\n")
|
||||
}
|
||||
|
||||
var ref types.ManagedObjectReference
|
||||
|
||||
net, err := imp.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, nil
|
||||
}
|
||||
|
||||
func OVFMap(op []Property) (p []types.KeyValue) {
|
||||
for _, v := range op {
|
||||
p = append(p, types.KeyValue{
|
||||
Key: v.Key,
|
||||
Value: v.Value,
|
||||
})
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func ValidateNetwork(e *ovf.Envelope, net Network) error {
|
||||
var names []string
|
||||
|
||||
if e.Network != nil {
|
||||
for _, n := range e.Network.Networks {
|
||||
if n.Name == net.Name {
|
||||
return nil
|
||||
}
|
||||
names = append(names, n.Name)
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("warning: invalid NetworkMapping.Name=%q, valid names=%s", net.Name, names)
|
||||
}
|
||||
|
||||
func ValidateChecksum(ctx context.Context, lease *nfc.Lease, sum *library.Checksum, file string, key string) error {
|
||||
// Perform the checksum match eagerly, after each file upload, instead
|
||||
// of after uploading all the files, to provide fail-fast behavior.
|
||||
// (Trade-off here is multiple GetManifest() API calls to the server.)
|
||||
manifests, err := lease.GetManifest(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, m := range manifests {
|
||||
if m.Key == key {
|
||||
// Compare server-side computed checksum of uploaded file
|
||||
// against the client's manifest entry (assuming client's
|
||||
// manifest has correct checksums - client doesn't compute
|
||||
// checksum of the file before uploading).
|
||||
|
||||
// Try matching sha1 first (newer versions have moved to sha256).
|
||||
if strings.ToUpper(sum.Algorithm) == "SHA1" {
|
||||
if sum.Checksum != m.Sha1 {
|
||||
msg := fmt.Sprintf("manifest checksum %v mismatch with uploaded checksum %v for file %v",
|
||||
sum.Checksum, m.Sha1, file)
|
||||
return errors.New(msg)
|
||||
}
|
||||
// Uploaded file checksum computed by server matches with local manifest entry.
|
||||
return nil
|
||||
}
|
||||
// If not sha1, check for other types (in a separate field).
|
||||
if !strings.EqualFold(sum.Algorithm, m.ChecksumType) {
|
||||
msg := fmt.Sprintf("manifest checksum type %v mismatch with uploaded checksum type %v for file %v",
|
||||
sum.Algorithm, m.ChecksumType, file)
|
||||
return errors.New(msg)
|
||||
}
|
||||
if !strings.EqualFold(sum.Checksum, m.Checksum) {
|
||||
msg := fmt.Sprintf("manifest checksum %v mismatch with uploaded checksum %v for file %v",
|
||||
sum.Checksum, m.Checksum, file)
|
||||
return errors.New(msg)
|
||||
}
|
||||
// Uploaded file checksum computed by server matches with local manifest entry.
|
||||
return nil
|
||||
}
|
||||
}
|
||||
msg := fmt.Sprintf("missing manifest entry on server for uploaded file %v (key %v), manifests=%#v", file, key, manifests)
|
||||
return errors.New(msg)
|
||||
}
|
||||
|
||||
func (imp *Importer) Upload(ctx context.Context, lease *nfc.Lease, item nfc.FileItem) error {
|
||||
file := item.Path
|
||||
|
||||
f, size, err := imp.Archive.Open(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
logger := progress.NewProgressLogger(imp.Log, fmt.Sprintf("Uploading %s... ", path.Base(file)))
|
||||
defer logger.Wait()
|
||||
|
||||
opts := soap.Upload{
|
||||
ContentLength: size,
|
||||
Progress: logger,
|
||||
}
|
||||
|
||||
err = lease.Upload(ctx, item, f, opts)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if imp.VerifyManifest {
|
||||
mapImportKeyToKey := func(urls []types.HttpNfcLeaseDeviceUrl, importKey string) string {
|
||||
for _, url := range urls {
|
||||
if url.ImportKey == importKey {
|
||||
return url.Key
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
leaseInfo, err := lease.Wait(ctx, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sum, ok := imp.Manifest[file]
|
||||
if !ok {
|
||||
return fmt.Errorf("missing checksum for %v in manifest file", file)
|
||||
}
|
||||
return ValidateChecksum(ctx, lease, sum, file, mapImportKeyToKey(leaseInfo.DeviceUrl, item.DeviceId))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
91
vendor/github.com/vmware/govmomi/ovf/importer/options.go
generated
vendored
Normal file
91
vendor/github.com/vmware/govmomi/ovf/importer/options.go
generated
vendored
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
Copyright (c) 2024-2024 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 importer
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/vmware/govmomi/ovf"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type KeyValue struct {
|
||||
Key string
|
||||
Value string
|
||||
}
|
||||
|
||||
// case insensitive for Key + Value
|
||||
func (kv *KeyValue) UnmarshalJSON(b []byte) error {
|
||||
e := struct {
|
||||
types.KeyValue
|
||||
Key *string
|
||||
Value *string
|
||||
}{
|
||||
types.KeyValue{}, &kv.Key, &kv.Value,
|
||||
}
|
||||
|
||||
err := json.Unmarshal(b, &e)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if kv.Key == "" {
|
||||
kv.Key = e.KeyValue.Key // "key"
|
||||
}
|
||||
|
||||
if kv.Value == "" {
|
||||
kv.Value = e.KeyValue.Value // "value"
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type Property struct {
|
||||
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
|
||||
}
|
||||
138
vendor/github.com/vmware/govmomi/ovf/importer/spec.go
generated
vendored
Normal file
138
vendor/github.com/vmware/govmomi/ovf/importer/spec.go
generated
vendored
Normal file
|
|
@ -0,0 +1,138 @@
|
|||
/*
|
||||
Copyright (c) 2024-2024 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 importer
|
||||
|
||||
import (
|
||||
"golang.org/x/text/cases"
|
||||
"golang.org/x/text/language"
|
||||
|
||||
"github.com/vmware/govmomi/ovf"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
var (
|
||||
allDiskProvisioningOptions = types.OvfCreateImportSpecParamsDiskProvisioningType("").Strings()
|
||||
|
||||
allIPAllocationPolicyOptions = types.VAppIPAssignmentInfoIpAllocationPolicy("").Strings()
|
||||
|
||||
allIPProtocolOptions = types.VAppIPAssignmentInfoProtocols("").Strings()
|
||||
)
|
||||
|
||||
func SpecMap(e *ovf.Envelope, hidden, verbose bool) (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 {
|
||||
continue
|
||||
}
|
||||
if !*v.UserConfigurable && !hidden {
|
||||
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 = cases.Title(language.Und).String(d)
|
||||
}
|
||||
|
||||
np := Property{KeyValue: KeyValue{Key: p.Key(v), Value: d}}
|
||||
|
||||
if verbose {
|
||||
np.Spec = &p.Property[i]
|
||||
}
|
||||
|
||||
res = append(res, np)
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func Spec(fpath string, a Archive, hidden, verbose bool) (*Options, error) {
|
||||
e := &ovf.Envelope{}
|
||||
if fpath != "" {
|
||||
d, err := ReadOvf(fpath, a)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if e, err = 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: SpecMap(e, hidden, verbose),
|
||||
}
|
||||
|
||||
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 verbose {
|
||||
if deploymentOptions != nil {
|
||||
o.AllDeploymentOptions = deploymentOptions
|
||||
}
|
||||
o.AllDiskProvisioningOptions = allDiskProvisioningOptions
|
||||
o.AllIPAllocationPolicyOptions = allIPAllocationPolicyOptions
|
||||
o.AllIPProtocolOptions = allIPProtocolOptions
|
||||
}
|
||||
|
||||
return &o, nil
|
||||
}
|
||||
50
vendor/github.com/vmware/govmomi/vapi/library/finder/path.go
generated
vendored
50
vendor/github.com/vmware/govmomi/vapi/library/finder/path.go
generated
vendored
|
|
@ -21,10 +21,13 @@ import (
|
|||
"fmt"
|
||||
"net/url"
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/property"
|
||||
"github.com/vmware/govmomi/vapi/library"
|
||||
"github.com/vmware/govmomi/vim25"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
|
|
@ -130,3 +133,50 @@ func (f *PathFinder) datastoreName(ctx context.Context, id string) (string, erro
|
|||
f.cache[id] = name
|
||||
return name, nil
|
||||
}
|
||||
|
||||
// ResolveLibraryItemStorage transforms StorageURIs Datastore url (uuid) to Datastore name.
|
||||
func (f *PathFinder) ResolveLibraryItemStorage(ctx context.Context, storage []library.Storage) error {
|
||||
// TODO:
|
||||
// - reuse PathFinder.cache
|
||||
// - the transform here isn't Content Library specific, but is currently the only known use case
|
||||
backing := map[string]*mo.Datastore{}
|
||||
var ids []types.ManagedObjectReference
|
||||
|
||||
// don't think we can have more than 1 Datastore backing currently, future proof anyhow
|
||||
for _, item := range storage {
|
||||
id := item.StorageBacking.DatastoreID
|
||||
if _, ok := backing[id]; ok {
|
||||
continue
|
||||
}
|
||||
backing[id] = nil
|
||||
ids = append(ids, types.ManagedObjectReference{Type: "Datastore", Value: id})
|
||||
}
|
||||
|
||||
var ds []mo.Datastore
|
||||
pc := property.DefaultCollector(f.c)
|
||||
if err := pc.Retrieve(ctx, ids, []string{"name", "info.url"}, &ds); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for i := range ds {
|
||||
backing[ds[i].Self.Value] = &ds[i]
|
||||
}
|
||||
|
||||
for _, item := range storage {
|
||||
b := backing[item.StorageBacking.DatastoreID]
|
||||
dsurl := b.Info.GetDatastoreInfo().Url
|
||||
|
||||
for i := range item.StorageURIs {
|
||||
u := strings.TrimPrefix(item.StorageURIs[i], dsurl)
|
||||
u = strings.TrimPrefix(u, "/")
|
||||
u = strings.SplitN(u, "?", 2)[0] // strip query, if any
|
||||
|
||||
item.StorageURIs[i] = (&object.DatastorePath{
|
||||
Datastore: b.Name,
|
||||
Path: u,
|
||||
}).String()
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
26
vendor/github.com/vmware/govmomi/vim25/mo/type_info.go
generated
vendored
26
vendor/github.com/vmware/govmomi/vim25/mo/type_info.go
generated
vendored
|
|
@ -35,9 +35,6 @@ type typeInfo struct {
|
|||
|
||||
// Map property names to field indices.
|
||||
props map[string][]int
|
||||
|
||||
// Use base type for interface indices.
|
||||
base bool
|
||||
}
|
||||
|
||||
var typeInfoLock sync.RWMutex
|
||||
|
|
@ -68,20 +65,22 @@ func typeInfoForType(tname string) *typeInfo {
|
|||
|
||||
func baseType(ftyp reflect.Type) reflect.Type {
|
||||
base := strings.TrimPrefix(ftyp.Name(), "Base")
|
||||
switch base {
|
||||
case "MethodFault":
|
||||
return nil
|
||||
}
|
||||
if kind, ok := types.TypeFunc()(base); ok {
|
||||
return kind
|
||||
}
|
||||
return ftyp
|
||||
return nil
|
||||
}
|
||||
|
||||
func newTypeInfo(typ reflect.Type, base ...bool) *typeInfo {
|
||||
func newTypeInfo(typ reflect.Type) *typeInfo {
|
||||
t := typeInfo{
|
||||
typ: typ,
|
||||
props: make(map[string][]int),
|
||||
}
|
||||
if len(base) == 1 {
|
||||
t.base = base[0]
|
||||
}
|
||||
|
||||
t.build(typ, "", []int{})
|
||||
|
||||
return &t
|
||||
|
|
@ -170,13 +169,16 @@ func (t *typeInfo) build(typ reflect.Type, fn string, fi []int) {
|
|||
t.build(ftyp, fnc, fic)
|
||||
}
|
||||
|
||||
// Base type can only access base fields, for example Datastore.Info
|
||||
// is types.BaseDataStore, so we create a new(types.DatastoreInfo)
|
||||
// Indexed property path may traverse into array element fields.
|
||||
// When interface, use the base type to index fields.
|
||||
// For example, BaseVirtualDevice:
|
||||
// config.hardware.device[4000].deviceInfo.label
|
||||
if t.base && ftyp.Kind() == reflect.Interface {
|
||||
base := baseType(ftyp)
|
||||
t.build(base, fnc, fic)
|
||||
if ftyp.Kind() == reflect.Interface {
|
||||
if base := baseType(ftyp); base != nil {
|
||||
t.build(base, fnc, fic)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -283,7 +285,7 @@ func assignValue(val reflect.Value, fi []int, pv reflect.Value, field ...string)
|
|||
item = reflect.New(rt.Elem())
|
||||
}
|
||||
|
||||
field := newTypeInfo(item.Type(), true)
|
||||
field := newTypeInfo(item.Type())
|
||||
if ix, ok := field.props[path]; ok {
|
||||
assignValue(item, ix, pv)
|
||||
}
|
||||
|
|
|
|||
125
vendor/github.com/vmware/govmomi/vim25/progress/loger.go
generated
vendored
Normal file
125
vendor/github.com/vmware/govmomi/vim25/progress/loger.go
generated
vendored
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
Copyright (c) 2024-2024 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 progress
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
type LogFunc func(msg string) (int, error)
|
||||
|
||||
type ProgressLogger struct {
|
||||
log LogFunc
|
||||
prefix string
|
||||
|
||||
wg sync.WaitGroup
|
||||
|
||||
sink chan chan Report
|
||||
done chan struct{}
|
||||
}
|
||||
|
||||
func NewProgressLogger(log LogFunc, prefix string) *ProgressLogger {
|
||||
p := &ProgressLogger{
|
||||
log: log,
|
||||
prefix: prefix,
|
||||
|
||||
sink: make(chan chan Report),
|
||||
done: make(chan struct{}),
|
||||
}
|
||||
|
||||
p.wg.Add(1)
|
||||
|
||||
go p.loopA()
|
||||
|
||||
return p
|
||||
}
|
||||
|
||||
// loopA runs before Sink() has been called.
|
||||
func (p *ProgressLogger) loopA() {
|
||||
var err error
|
||||
|
||||
defer p.wg.Done()
|
||||
|
||||
tick := time.NewTicker(100 * time.Millisecond)
|
||||
defer tick.Stop()
|
||||
|
||||
called := false
|
||||
|
||||
for stop := false; !stop; {
|
||||
select {
|
||||
case ch := <-p.sink:
|
||||
err = p.loopB(tick, ch)
|
||||
stop = true
|
||||
called = true
|
||||
case <-p.done:
|
||||
stop = true
|
||||
case <-tick.C:
|
||||
line := fmt.Sprintf("\r%s", p.prefix)
|
||||
p.log(line)
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil && err != io.EOF {
|
||||
p.log(fmt.Sprintf("\r%sError: %s\n", p.prefix, err))
|
||||
} else if called {
|
||||
p.log(fmt.Sprintf("\r%sOK\n", p.prefix))
|
||||
}
|
||||
}
|
||||
|
||||
// loopA runs after Sink() has been called.
|
||||
func (p *ProgressLogger) loopB(tick *time.Ticker, ch <-chan Report) error {
|
||||
var r Report
|
||||
var ok bool
|
||||
var err error
|
||||
|
||||
for ok = true; ok; {
|
||||
select {
|
||||
case r, ok = <-ch:
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
err = r.Error()
|
||||
case <-tick.C:
|
||||
line := fmt.Sprintf("\r%s", p.prefix)
|
||||
if r != nil {
|
||||
line += fmt.Sprintf("(%.0f%%", r.Percentage())
|
||||
detail := r.Detail()
|
||||
if detail != "" {
|
||||
line += fmt.Sprintf(", %s", detail)
|
||||
}
|
||||
line += ")"
|
||||
}
|
||||
p.log(line)
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (p *ProgressLogger) Sink() chan<- Report {
|
||||
ch := make(chan Report)
|
||||
p.sink <- ch
|
||||
return ch
|
||||
}
|
||||
|
||||
func (p *ProgressLogger) Wait() {
|
||||
close(p.done)
|
||||
p.wg.Wait()
|
||||
}
|
||||
4
vendor/github.com/vmware/govmomi/vim25/types/types.go
generated
vendored
4
vendor/github.com/vmware/govmomi/vim25/types/types.go
generated
vendored
|
|
@ -91361,7 +91361,7 @@ type VirtualMachineVirtualNuma struct {
|
|||
// vNUMA node.
|
||||
// If set to be non zero, VM uses the value as vNUMA node size.
|
||||
// If unset, the VM continue to follow the behavior in last poweron.
|
||||
CoresPerNumaNode int32 `xml:"coresPerNumaNode,omitempty" json:"coresPerNumaNode,omitempty"`
|
||||
CoresPerNumaNode *int32 `xml:"coresPerNumaNode" json:"coresPerNumaNode,omitempty"`
|
||||
// Capability to expose virtual NUMA when CPU hotadd is enabled.
|
||||
//
|
||||
// If set to true, ESXi will consider exposing virtual NUMA to
|
||||
|
|
@ -91389,7 +91389,7 @@ type VirtualMachineVirtualNumaInfo struct {
|
|||
// field should be ignored.
|
||||
// In other cases, this field represents the virtual NUMA node size
|
||||
// seen by the guest.
|
||||
CoresPerNumaNode int32 `xml:"coresPerNumaNode,omitempty" json:"coresPerNumaNode,omitempty"`
|
||||
CoresPerNumaNode *int32 `xml:"coresPerNumaNode" json:"coresPerNumaNode,omitempty"`
|
||||
// Whether coresPerNode is determined automatically.
|
||||
AutoCoresPerNumaNode *bool `xml:"autoCoresPerNumaNode" json:"autoCoresPerNumaNode,omitempty"`
|
||||
// Whether virtual NUMA topology is exposed when CPU hotadd is
|
||||
|
|
|
|||
164
vendor/github.com/vmware/govmomi/vmdk/disk_info.go
generated
vendored
Normal file
164
vendor/github.com/vmware/govmomi/vmdk/disk_info.go
generated
vendored
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
/*
|
||||
Copyright (c) 2024-2024 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 vmdk
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type VirtualDiskInfo struct {
|
||||
CapacityInBytes int64
|
||||
DeviceKey int32
|
||||
FileName string
|
||||
Size int64
|
||||
UniqueSize int64
|
||||
}
|
||||
|
||||
// GetVirtualDiskInfoByUUID returns information about a virtual disk identified
|
||||
// by the provided UUID. This method is valid for the following backing types:
|
||||
//
|
||||
// - VirtualDiskFlatVer2BackingInfo
|
||||
// - VirtualDiskSeSparseBackingInfo
|
||||
// - VirtualDiskRawDiskMappingVer1BackingInfo
|
||||
// - VirtualDiskSparseVer2BackingInfo
|
||||
// - VirtualDiskRawDiskVer2BackingInfo
|
||||
//
|
||||
// These are the only backing types that have a UUID property for comparing the
|
||||
// provided value.
|
||||
func GetVirtualDiskInfoByUUID(
|
||||
ctx context.Context,
|
||||
client *vim25.Client,
|
||||
mo mo.VirtualMachine,
|
||||
fetchProperties bool,
|
||||
diskUUID string) (VirtualDiskInfo, error) {
|
||||
|
||||
if diskUUID == "" {
|
||||
return VirtualDiskInfo{}, fmt.Errorf("diskUUID is empty")
|
||||
}
|
||||
|
||||
switch {
|
||||
case fetchProperties,
|
||||
mo.Config == nil,
|
||||
mo.Config.Hardware.Device == nil,
|
||||
mo.LayoutEx == nil,
|
||||
mo.LayoutEx.Disk == nil,
|
||||
mo.LayoutEx.File == nil:
|
||||
|
||||
if ctx == nil {
|
||||
return VirtualDiskInfo{}, fmt.Errorf("ctx is nil")
|
||||
}
|
||||
if client == nil {
|
||||
return VirtualDiskInfo{}, fmt.Errorf("client is nil")
|
||||
}
|
||||
|
||||
obj := object.NewVirtualMachine(client, mo.Self)
|
||||
|
||||
if err := obj.Properties(
|
||||
ctx,
|
||||
mo.Self,
|
||||
[]string{"config", "layoutEx"},
|
||||
&mo); err != nil {
|
||||
|
||||
return VirtualDiskInfo{},
|
||||
fmt.Errorf("failed to retrieve properties: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Find the disk by UUID by inspecting all of the disk backing types that
|
||||
// can have an associated UUID.
|
||||
var (
|
||||
disk *types.VirtualDisk
|
||||
fileName string
|
||||
)
|
||||
for i := range mo.Config.Hardware.Device {
|
||||
switch tvd := mo.Config.Hardware.Device[i].(type) {
|
||||
case *types.VirtualDisk:
|
||||
switch tb := tvd.Backing.(type) {
|
||||
case *types.VirtualDiskFlatVer2BackingInfo:
|
||||
if tb.Uuid == diskUUID {
|
||||
disk = tvd
|
||||
fileName = tb.FileName
|
||||
}
|
||||
case *types.VirtualDiskSeSparseBackingInfo:
|
||||
if tb.Uuid == diskUUID {
|
||||
disk = tvd
|
||||
fileName = tb.FileName
|
||||
}
|
||||
case *types.VirtualDiskRawDiskMappingVer1BackingInfo:
|
||||
if tb.Uuid == diskUUID {
|
||||
disk = tvd
|
||||
fileName = tb.FileName
|
||||
}
|
||||
case *types.VirtualDiskSparseVer2BackingInfo:
|
||||
if tb.Uuid == diskUUID {
|
||||
disk = tvd
|
||||
fileName = tb.FileName
|
||||
}
|
||||
case *types.VirtualDiskRawDiskVer2BackingInfo:
|
||||
if tb.Uuid == diskUUID {
|
||||
disk = tvd
|
||||
fileName = tb.DescriptorFileName
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if disk == nil {
|
||||
return VirtualDiskInfo{},
|
||||
fmt.Errorf("disk not found with uuid %q", diskUUID)
|
||||
}
|
||||
|
||||
// Build a lookup table for determining if file key belongs to this disk
|
||||
// chain.
|
||||
diskFileKeys := map[int32]struct{}{}
|
||||
for i := range mo.LayoutEx.Disk {
|
||||
if d := mo.LayoutEx.Disk[i]; d.Key == disk.Key {
|
||||
for j := range d.Chain {
|
||||
for k := range d.Chain[j].FileKey {
|
||||
diskFileKeys[d.Chain[j].FileKey[k]] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Sum the disk's total size and unique size.
|
||||
var (
|
||||
size int64
|
||||
uniqueSize int64
|
||||
)
|
||||
for i := range mo.LayoutEx.File {
|
||||
f := mo.LayoutEx.File[i]
|
||||
if _, ok := diskFileKeys[f.Key]; ok {
|
||||
size += f.Size
|
||||
uniqueSize += f.UniqueSize
|
||||
}
|
||||
}
|
||||
|
||||
return VirtualDiskInfo{
|
||||
CapacityInBytes: disk.CapacityInBytes,
|
||||
DeviceKey: disk.Key,
|
||||
FileName: fileName,
|
||||
Size: size,
|
||||
UniqueSize: uniqueSize,
|
||||
}, nil
|
||||
}
|
||||
20
vendor/github.com/vmware/govmomi/vmdk/import.go
generated
vendored
20
vendor/github.com/vmware/govmomi/vmdk/import.go
generated
vendored
|
|
@ -10,7 +10,7 @@ You may obtain a copy of the License at
|
|||
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.
|
||||
nSee the License for the specific language governing permissions and
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
|
|
@ -41,8 +41,8 @@ var (
|
|||
ErrInvalidFormat = errors.New("vmdk: invalid format (must be streamOptimized)")
|
||||
)
|
||||
|
||||
// info is used to inspect a vmdk and generate an ovf template
|
||||
type info struct {
|
||||
// Info is used to inspect a vmdk and generate an ovf template
|
||||
type Info struct {
|
||||
Header struct {
|
||||
MagicNumber uint32
|
||||
Version uint32
|
||||
|
|
@ -56,15 +56,15 @@ type info struct {
|
|||
ImportName string
|
||||
}
|
||||
|
||||
// stat looks at the vmdk header to make sure the format is streamOptimized and
|
||||
// Stat looks at the vmdk header to make sure the format is streamOptimized and
|
||||
// extracts the disk capacity required to properly generate the ovf descriptor.
|
||||
func stat(name string) (*info, error) {
|
||||
func Stat(name string) (*Info, error) {
|
||||
f, err := os.Open(filepath.Clean(name))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var di info
|
||||
var di Info
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
|
|
@ -174,8 +174,8 @@ var ovfenv = `<?xml version="1.0" encoding="UTF-8"?>
|
|||
</VirtualSystem>
|
||||
</Envelope>`
|
||||
|
||||
// ovf returns an expanded descriptor template
|
||||
func (di *info) ovf() (string, error) {
|
||||
// OVF returns an expanded descriptor template
|
||||
func (di *Info) OVF() (string, error) {
|
||||
var buf bytes.Buffer
|
||||
|
||||
tmpl, err := template.New("ovf").Parse(ovfenv)
|
||||
|
|
@ -209,7 +209,7 @@ func Import(ctx context.Context, c *vim25.Client, name string, datastore *object
|
|||
m := ovf.NewManager(c)
|
||||
fm := datastore.NewFileManager(p.Datacenter, p.Force)
|
||||
|
||||
disk, err := stat(name)
|
||||
disk, err := Stat(name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
@ -245,7 +245,7 @@ func Import(ctx context.Context, c *vim25.Client, name string, datastore *object
|
|||
}
|
||||
|
||||
// Expand the ovf template
|
||||
descriptor, err := disk.ovf()
|
||||
descriptor, err := disk.OVF()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue