go.mod: update github.com/vmware/govmomi to v0.48.0

Needs manual change of import paths.
This commit is contained in:
Achilleas Koutsou 2025-01-31 18:26:22 +01:00 committed by Sanne Raymaekers
parent 3a6bea380e
commit bec893e37c
170 changed files with 7474 additions and 1604 deletions

View file

@ -18,12 +18,12 @@ package finder
import (
"context"
"errors"
"fmt"
"net/url"
"path"
"strings"
"github.com/vmware/govmomi/internal"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/property"
"github.com/vmware/govmomi/vapi/library"
@ -135,78 +135,133 @@ func (f *PathFinder) datastoreName(ctx context.Context, id string) (string, erro
return name, nil
}
func (f *PathFinder) convertPath(ctx context.Context, b *mo.Datastore, path string) (string, error) {
if !internal.IsDatastoreVSAN(*b) {
func (f *PathFinder) convertPath(
ctx context.Context,
dc *object.Datacenter,
ds mo.Datastore,
path string) (string, error) {
if v := ds.Capability.TopLevelDirectoryCreateSupported; v != nil && *v {
return path, nil
}
var dc *object.Datacenter
entities, err := mo.Ancestors(ctx, f.c, f.c.ServiceContent.PropertyCollector, b.Self)
if err != nil {
return "", err
if dc == nil {
entities, err := mo.Ancestors(
ctx,
f.c,
f.c.ServiceContent.PropertyCollector,
ds.Self)
if err != nil {
return "", fmt.Errorf("failed to find ancestors: %w", err)
}
for _, entity := range entities {
if entity.Self.Type == "Datacenter" {
dc = object.NewDatacenter(f.c, entity.Self)
break
}
}
}
for _, entity := range entities {
if entity.Self.Type == "Datacenter" {
dc = object.NewDatacenter(f.c, entity.Self)
break
}
if dc == nil {
return "", errors.New("failed to find datacenter")
}
m := object.NewDatastoreNamespaceManager(f.c)
return m.ConvertNamespacePathToUuidPath(ctx, dc, path)
}
// ResolveLibraryItemStorage transforms StorageURIs Datastore url (uuid) to Datastore name.
func (f *PathFinder) ResolveLibraryItemStorage(ctx context.Context, storage []library.Storage) error {
// ResolveLibraryItemStorage transforms the StorageURIs field in the provided
// storage items from a datastore URL, ex.
// "ds:///vmfs/volumes/DATASTORE_UUID/contentlib-LIB_UUID/ITEM_UUID/file.vmdk",
// to the format that includes the datastore name, ex.
// "[DATASTORE_NAME] contentlib-LIB_UUID/ITEM_UUID/file.vmdk".
//
// If datastoreMap is provided, then it will be updated with the datastores
// involved in the resolver. The properties name, summary.url, and
// capability.topLevelDirectoryCreateSupported will be available after the
// resolver completes.
//
// If a storage item resides on a datastore that does not support the creation
// of top-level directories, then this means the datastore is vSAN and the
// storage item path needs to be further converted. If this occurs, then the
// datacenter to which the datastore belongs is required. If the datacenter
// parameter is non-nil, it is used, otherwise the datacenter for each datastore
// is resolved as needed. It is much more efficient to send in the datacenter if
// it is known ahead of time that the content library is stored on a vSAN
// datastore.
func (f *PathFinder) ResolveLibraryItemStorage(
ctx context.Context,
datacenter *object.Datacenter,
datastoreMap map[string]mo.Datastore,
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{}
// - the transform here isn't Content Library specific, but is currently
// the only known use case
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})
if datastoreMap == nil {
datastoreMap = map[string]mo.Datastore{}
}
var ds []mo.Datastore
pc := property.DefaultCollector(f.c)
props := []string{"name", "summary.url", "summary.type"}
if err := pc.Retrieve(ctx, ids, props, &ds); err != nil {
// Currently ContentLibrary only supports a single storage backing, but this
// future proofs things.
for _, item := range storage {
id := item.StorageBacking.DatastoreID
if _, ok := datastoreMap[id]; ok {
continue
}
datastoreMap[id] = mo.Datastore{}
ids = append(
ids,
types.ManagedObjectReference{Type: "Datastore", Value: id})
}
var (
datastores []mo.Datastore
pc = property.DefaultCollector(f.c)
props = []string{
"name",
"summary.url",
"capability.topLevelDirectoryCreateSupported",
}
)
if err := pc.Retrieve(ctx, ids, props, &datastores); err != nil {
return err
}
for i := range ds {
backing[ds[i].Self.Value] = &ds[i]
for i := range datastores {
datastoreMap[datastores[i].Self.Value] = datastores[i]
}
for _, item := range storage {
b := backing[item.StorageBacking.DatastoreID]
dsurl := b.Summary.Url
ds := datastoreMap[item.StorageBacking.DatastoreID]
dsURL := ds.Summary.Url
for i := range item.StorageURIs {
uri, err := url.Parse(item.StorageURIs[i])
szURI := item.StorageURIs[i]
uri, err := url.Parse(szURI)
if err != nil {
return err
return fmt.Errorf(
"failed to parse storage URI %q: %w", szURI, err)
}
uri.OmitHost = false // `ds://` required for ConvertNamespacePathToUuidPath()
uri.Path = path.Clean(uri.Path) // required for ConvertNamespacePathToUuidPath()
uri.RawQuery = ""
u, err := f.convertPath(ctx, b, uri.String())
uriPath := uri.String()
u, err := f.convertPath(ctx, datacenter, ds, uriPath)
if err != nil {
return err
return fmt.Errorf("failed to convert path %q: %w", uriPath, err)
}
u = strings.TrimPrefix(u, dsurl)
u = strings.TrimPrefix(u, dsURL)
u = strings.TrimPrefix(u, "/")
item.StorageURIs[i] = (&object.DatastorePath{
Datastore: b.Name,
Datastore: ds.Name,
Path: u,
}).String()
}

View file

@ -50,6 +50,13 @@ type Library struct {
Publication *Publication `json:"publish_info,omitempty"`
SecurityPolicyID string `json:"security_policy_id,omitempty"`
UnsetSecurityPolicyID bool `json:"unset_security_policy_id,omitempty"`
ServerGUID string `json:"server_guid,omitempty"`
StateInfo *StateInfo `json:"state_info,omitempty"`
}
// StateInfo provides the state info of a content library.
type StateInfo struct {
State string `json:"state"`
}
// Subscription info

View file

@ -1,11 +1,11 @@
/*
Copyright (c) 2018 VMware, Inc. All Rights Reserved.
Copyright (c) 2018-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,8 +22,10 @@ import (
"encoding/json"
"fmt"
"io"
"mime"
"net/http"
"net/url"
"os"
"strings"
"sync"
"time"
@ -273,6 +275,36 @@ func (c *Client) DownloadFile(ctx context.Context, file string, u *url.URL, para
return c.Client.DownloadFile(ctx, file, u, &p)
}
// DownloadAttachment writes the response to given filename, defaulting to Content-Disposition filename in the response.
// A filename of "-" writes the response to stdout.
func (c *Client) DownloadAttachment(ctx context.Context, req *http.Request, filename string) error {
return c.Client.Do(ctx, req, func(res *http.Response) error {
if filename == "" {
d := res.Header.Get("Content-Disposition")
_, params, err := mime.ParseMediaType(d)
if err == nil {
filename = params["filename"]
}
}
var w io.Writer
if filename == "-" {
w = os.Stdout
} else {
f, err := os.Create(filename)
if err != nil {
return err
}
defer f.Close()
w = f
}
_, err := io.Copy(w, res.Body)
return err
})
}
// Upload wraps soap.Client.Upload, adding the REST authentication header
func (c *Client) Upload(ctx context.Context, f io.Reader, u *url.URL, param *soap.Upload) error {
p := *param