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:
dependabot[bot] 2024-07-25 04:38:39 +00:00 committed by Tomáš Hozza
parent fd71c9cefa
commit ca2c2dfa4f
104 changed files with 4713 additions and 2477 deletions

View file

@ -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)
}

View file

@ -1,205 +0,0 @@
/*
Copyright (c) 2014-2015 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package importx
import (
"archive/tar"
"bytes"
"context"
"errors"
"flag"
"fmt"
"io"
"net/url"
"os"
"path"
"path/filepath"
"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)
if err != nil {
return nil, err
}
defer r.Close()
return io.ReadAll(r)
}
func (f *ArchiveFlag) ReadEnvelope(data []byte) (*ovf.Envelope, error) {
e, err := ovf.Unmarshal(bytes.NewReader(data))
if err != nil {
return nil, fmt.Errorf("failed to parse ovf: %s", err)
}
return e, nil
}
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)
}
type TapeArchive struct {
Path string
Opener
}
type TapeArchiveEntry struct {
io.Reader
f io.Closer
Name string
}
func (t *TapeArchiveEntry) Close() error {
return t.f.Close()
}
func (t *TapeArchive) Open(name string) (io.ReadCloser, int64, error) {
f, _, err := t.OpenFile(t.Path)
if err != nil {
return nil, 0, err
}
r := tar.NewReader(f)
for {
h, err := r.Next()
if err == io.EOF {
break
}
if err != nil {
return nil, 0, err
}
matched, err := path.Match(name, path.Base(h.Name))
if err != nil {
return nil, 0, err
}
if matched {
return &TapeArchiveEntry{r, f, h.Name}, h.Size, nil
}
}
_ = f.Close()
return nil, 0, os.ErrNotExist
}
type FileArchive struct {
Path string
Opener
}
func (t *FileArchive) Open(name string) (io.ReadCloser, int64, error) {
fpath := name
if name != t.Path {
index := strings.LastIndex(t.Path, "/")
if index != -1 {
fpath = t.Path[:index] + "/" + name
}
}
return t.OpenFile(fpath)
}
type Opener struct {
*vim25.Client
}
func isRemotePath(path string) bool {
if strings.HasPrefix(path, "http://") || strings.HasPrefix(path, "https://") {
return true
}
return false
}
func (o Opener) OpenLocal(path string) (io.ReadCloser, int64, error) {
f, err := os.Open(filepath.Clean(path))
if err != nil {
return nil, 0, err
}
s, err := f.Stat()
if err != nil {
return nil, 0, err
}
return f, s.Size(), nil
}
func (o Opener) OpenFile(path string) (io.ReadCloser, int64, error) {
if isRemotePath(path) {
return o.OpenRemote(path)
}
return o.OpenLocal(path)
}
func (o Opener) OpenRemote(link string) (io.ReadCloser, int64, error) {
if o.Client == nil {
return nil, 0, errors.New("remote path not supported")
}
u, err := url.Parse(link)
if err != nil {
return nil, 0, err
}
return o.Download(context.Background(), u, &soap.DefaultDownload)
}

View file

@ -1,59 +0,0 @@
/*
Copyright (c) 2014 VMware, Inc. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package importx
import (
"fmt"
"path"
)
type importable struct {
localPath string
remotePath string
}
func (i importable) Ext() string {
return path.Ext(i.localPath)
}
func (i importable) Base() string {
return path.Base(i.localPath)
}
func (i importable) BaseClean() string {
b := i.Base()
e := i.Ext()
return b[:len(b)-len(e)]
}
func (i importable) RemoteSrcVMDK() string {
file := fmt.Sprintf("%s-src.vmdk", i.BaseClean())
return i.toRemotePath(file)
}
func (i importable) RemoteDstVMDK() string {
file := fmt.Sprintf("%s.vmdk", i.BaseClean())
return i.toRemotePath(file)
}
func (i importable) toRemotePath(p string) string {
if i.remotePath == "" {
return p
}
return path.Join(i.remotePath, p)
}

View file

@ -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
}

View file

@ -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)
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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

View file

@ -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 {

View file

@ -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
}