Fix for Support selection of datastore for dynamic provisioning in vSphere
This commit is contained in:

committed by
Ritesh H Shukla

parent
b201ac2f8f
commit
12f75f0b86
68
vendor/github.com/vmware/govmomi/object/authorization_manager.go
generated
vendored
68
vendor/github.com/vmware/govmomi/object/authorization_manager.go
generated
vendored
@@ -17,11 +17,12 @@ limitations under the License.
|
||||
package object
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/vmware/govmomi/vim25"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type AuthorizationManager struct {
|
||||
@@ -106,3 +107,68 @@ func (m AuthorizationManager) SetEntityPermissions(ctx context.Context, entity t
|
||||
_, err := methods.SetEntityPermissions(ctx, m.Client(), &req)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m AuthorizationManager) RetrieveRolePermissions(ctx context.Context, id int32) ([]types.Permission, error) {
|
||||
req := types.RetrieveRolePermissions{
|
||||
This: m.Reference(),
|
||||
RoleId: id,
|
||||
}
|
||||
|
||||
res, err := methods.RetrieveRolePermissions(ctx, m.Client(), &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return res.Returnval, nil
|
||||
}
|
||||
|
||||
func (m AuthorizationManager) RetrieveAllPermissions(ctx context.Context) ([]types.Permission, error) {
|
||||
req := types.RetrieveAllPermissions{
|
||||
This: m.Reference(),
|
||||
}
|
||||
|
||||
res, err := methods.RetrieveAllPermissions(ctx, m.Client(), &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return res.Returnval, nil
|
||||
}
|
||||
|
||||
func (m AuthorizationManager) AddRole(ctx context.Context, name string, ids []string) (int32, error) {
|
||||
req := types.AddAuthorizationRole{
|
||||
This: m.Reference(),
|
||||
Name: name,
|
||||
PrivIds: ids,
|
||||
}
|
||||
|
||||
res, err := methods.AddAuthorizationRole(ctx, m.Client(), &req)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
return res.Returnval, nil
|
||||
}
|
||||
|
||||
func (m AuthorizationManager) RemoveRole(ctx context.Context, id int32, failIfUsed bool) error {
|
||||
req := types.RemoveAuthorizationRole{
|
||||
This: m.Reference(),
|
||||
RoleId: id,
|
||||
FailIfUsed: failIfUsed,
|
||||
}
|
||||
|
||||
_, err := methods.RemoveAuthorizationRole(ctx, m.Client(), &req)
|
||||
return err
|
||||
}
|
||||
|
||||
func (m AuthorizationManager) UpdateRole(ctx context.Context, id int32, name string, ids []string) error {
|
||||
req := types.UpdateAuthorizationRole{
|
||||
This: m.Reference(),
|
||||
RoleId: id,
|
||||
NewName: name,
|
||||
PrivIds: ids,
|
||||
}
|
||||
|
||||
_, err := methods.UpdateAuthorizationRole(ctx, m.Client(), &req)
|
||||
return err
|
||||
}
|
||||
|
3
vendor/github.com/vmware/govmomi/object/cluster_compute_resource.go
generated
vendored
3
vendor/github.com/vmware/govmomi/object/cluster_compute_resource.go
generated
vendored
@@ -17,10 +17,11 @@ 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"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type ClusterComputeResource struct {
|
||||
|
4
vendor/github.com/vmware/govmomi/object/common.go
generated
vendored
4
vendor/github.com/vmware/govmomi/object/common.go
generated
vendored
@@ -17,6 +17,7 @@ limitations under the License.
|
||||
package object
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"path"
|
||||
@@ -26,11 +27,10 @@ import (
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrNotSupported = errors.New("not supported (vCenter only)")
|
||||
ErrNotSupported = errors.New("product/version specific feature not supported by target")
|
||||
)
|
||||
|
||||
// Common contains the fields and functions common to all objects.
|
||||
|
2
vendor/github.com/vmware/govmomi/object/compute_resource.go
generated
vendored
2
vendor/github.com/vmware/govmomi/object/compute_resource.go
generated
vendored
@@ -17,6 +17,7 @@ limitations under the License.
|
||||
package object
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path"
|
||||
|
||||
"github.com/vmware/govmomi/property"
|
||||
@@ -24,7 +25,6 @@ import (
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type ComputeResource struct {
|
||||
|
2
vendor/github.com/vmware/govmomi/object/custom_fields_manager.go
generated
vendored
2
vendor/github.com/vmware/govmomi/object/custom_fields_manager.go
generated
vendored
@@ -17,6 +17,7 @@ limitations under the License.
|
||||
package object
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"strconv"
|
||||
|
||||
@@ -24,7 +25,6 @@ import (
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
var (
|
||||
|
3
vendor/github.com/vmware/govmomi/object/customization_spec_manager.go
generated
vendored
3
vendor/github.com/vmware/govmomi/object/customization_spec_manager.go
generated
vendored
@@ -17,10 +17,11 @@ 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"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type CustomizationSpecManager struct {
|
||||
|
2
vendor/github.com/vmware/govmomi/object/datacenter.go
generated
vendored
2
vendor/github.com/vmware/govmomi/object/datacenter.go
generated
vendored
@@ -17,13 +17,13 @@ limitations under the License.
|
||||
package object
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/vmware/govmomi/vim25"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type DatacenterFolders struct {
|
||||
|
127
vendor/github.com/vmware/govmomi/object/datastore.go
generated
vendored
127
vendor/github.com/vmware/govmomi/object/datastore.go
generated
vendored
@@ -24,6 +24,7 @@ import (
|
||||
"path"
|
||||
"strings"
|
||||
|
||||
"context"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
@@ -33,7 +34,6 @@ import (
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// DatastoreNoSuchDirectoryError is returned when a directory could not be found.
|
||||
@@ -58,6 +58,8 @@ func (e DatastoreNoSuchFileError) Error() string {
|
||||
|
||||
type Datastore struct {
|
||||
Common
|
||||
|
||||
DatacenterPath string
|
||||
}
|
||||
|
||||
func NewDatastore(c *vim25.Client, ref types.ManagedObjectReference) *Datastore {
|
||||
@@ -67,26 +69,14 @@ func NewDatastore(c *vim25.Client, ref types.ManagedObjectReference) *Datastore
|
||||
}
|
||||
|
||||
func (d Datastore) Path(path string) string {
|
||||
name := d.Name()
|
||||
if name == "" {
|
||||
panic("expected non-empty name")
|
||||
}
|
||||
|
||||
return fmt.Sprintf("[%s] %s", name, path)
|
||||
return (&DatastorePath{
|
||||
Datastore: d.Name(),
|
||||
Path: path,
|
||||
}).String()
|
||||
}
|
||||
|
||||
// URL for datastore access over HTTP
|
||||
func (d Datastore) URL(ctx context.Context, dc *Datacenter, path string) (*url.URL, error) {
|
||||
var mdc mo.Datacenter
|
||||
if err := dc.Properties(ctx, dc.Reference(), []string{"name"}, &mdc); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var mds mo.Datastore
|
||||
if err := d.Properties(ctx, d.Reference(), []string{"name"}, &mds); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// NewURL constructs a url.URL with the given file path for datastore access over HTTP.
|
||||
func (d Datastore) NewURL(path string) *url.URL {
|
||||
u := d.c.URL()
|
||||
|
||||
return &url.URL{
|
||||
@@ -94,10 +84,15 @@ func (d Datastore) URL(ctx context.Context, dc *Datacenter, path string) (*url.U
|
||||
Host: u.Host,
|
||||
Path: fmt.Sprintf("/folder/%s", path),
|
||||
RawQuery: url.Values{
|
||||
"dcPath": []string{mdc.Name},
|
||||
"dsName": []string{mds.Name},
|
||||
"dcPath": []string{d.DatacenterPath},
|
||||
"dsName": []string{d.Name()},
|
||||
}.Encode(),
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
// URL is deprecated, use NewURL instead.
|
||||
func (d Datastore) URL(ctx context.Context, dc *Datacenter, path string) (*url.URL, error) {
|
||||
return d.NewURL(path), nil
|
||||
}
|
||||
|
||||
func (d Datastore) Browser(ctx context.Context) (*HostDatastoreBrowser, error) {
|
||||
@@ -111,6 +106,27 @@ func (d Datastore) Browser(ctx context.Context) (*HostDatastoreBrowser, error) {
|
||||
return NewHostDatastoreBrowser(d.c, do.Browser), nil
|
||||
}
|
||||
|
||||
func (d Datastore) useServiceTicket() bool {
|
||||
// If connected to workstation, service ticketing not supported
|
||||
// If connected to ESX, service ticketing not needed
|
||||
if !d.c.IsVC() {
|
||||
return false
|
||||
}
|
||||
|
||||
key := "GOVMOMI_USE_SERVICE_TICKET"
|
||||
|
||||
val := d.c.URL().Query().Get(key)
|
||||
if val == "" {
|
||||
val = os.Getenv(key)
|
||||
}
|
||||
|
||||
if val == "1" || val == "true" {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (d Datastore) useServiceTicketHostName(name string) bool {
|
||||
// No need if talking directly to ESX.
|
||||
if !d.c.IsVC() {
|
||||
@@ -147,39 +163,62 @@ func (d Datastore) useServiceTicketHostName(name string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// ServiceTicket obtains a ticket via AcquireGenericServiceTicket and returns it an http.Cookie with the url.URL
|
||||
// that can be used along with the ticket cookie to access the given path.
|
||||
func (d Datastore) ServiceTicket(ctx context.Context, path string, method string) (*url.URL, *http.Cookie, error) {
|
||||
// We are uploading to an ESX host
|
||||
u := &url.URL{
|
||||
Scheme: d.c.URL().Scheme,
|
||||
Host: d.c.URL().Host,
|
||||
Path: fmt.Sprintf("/folder/%s", path),
|
||||
RawQuery: url.Values{
|
||||
"dsName": []string{d.Name()},
|
||||
}.Encode(),
|
||||
}
|
||||
type datastoreServiceTicketHostKey struct{}
|
||||
|
||||
// HostContext returns a Context where the given host will be used for datastore HTTP access
|
||||
// via the ServiceTicket method.
|
||||
func (d Datastore) HostContext(ctx context.Context, host *HostSystem) context.Context {
|
||||
return context.WithValue(ctx, datastoreServiceTicketHostKey{}, host)
|
||||
}
|
||||
|
||||
// ServiceTicket obtains a ticket via AcquireGenericServiceTicket and returns it an http.Cookie with the url.URL
|
||||
// that can be used along with the ticket cookie to access the given path. An host is chosen at random unless the
|
||||
// the given Context was created with a specific host via the HostContext method.
|
||||
func (d Datastore) ServiceTicket(ctx context.Context, path string, method string) (*url.URL, *http.Cookie, error) {
|
||||
u := d.NewURL(path)
|
||||
|
||||
host, ok := ctx.Value(datastoreServiceTicketHostKey{}).(*HostSystem)
|
||||
|
||||
if !ok {
|
||||
if !d.useServiceTicket() {
|
||||
return u, nil, nil
|
||||
}
|
||||
|
||||
// If connected to VC, the ticket request must be for an ESX host.
|
||||
if d.c.IsVC() {
|
||||
hosts, err := d.AttachedHosts(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if len(hosts) == 0 {
|
||||
return nil, nil, fmt.Errorf("no hosts attached to datastore %#v", d.Reference())
|
||||
// Fallback to letting vCenter choose a host
|
||||
return u, nil, nil
|
||||
}
|
||||
|
||||
// Pick a random attached host
|
||||
host := hosts[rand.Intn(len(hosts))]
|
||||
name, err := host.ObjectName(ctx)
|
||||
host = hosts[rand.Intn(len(hosts))]
|
||||
}
|
||||
|
||||
ips, err := host.ManagementIPs(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if len(ips) > 0 {
|
||||
// prefer a ManagementIP
|
||||
u.Host = ips[0].String()
|
||||
} else {
|
||||
// fallback to inventory name
|
||||
u.Host, err = host.ObjectName(ctx)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
u.Host = name
|
||||
}
|
||||
|
||||
// VC datacenter path will not be valid against ESX
|
||||
q := u.Query()
|
||||
delete(q, "dcPath")
|
||||
u.RawQuery = q.Encode()
|
||||
|
||||
spec := types.SessionManagerHttpServiceRequestSpec{
|
||||
Url: u.String(),
|
||||
// See SessionManagerHttpServiceRequestSpecMethod enum
|
||||
@@ -202,6 +241,8 @@ func (d Datastore) ServiceTicket(ctx context.Context, path string, method string
|
||||
u.Host = ticket.HostName
|
||||
}
|
||||
|
||||
d.Client().SetThumbprint(u.Host, ticket.SslThumbprint)
|
||||
|
||||
return u, cookie, nil
|
||||
}
|
||||
|
||||
@@ -313,7 +354,7 @@ func (d Datastore) AttachedHosts(ctx context.Context) ([]*HostSystem, error) {
|
||||
return hosts, nil
|
||||
}
|
||||
|
||||
// AttachedHosts returns hosts that have this Datastore attached, accessible and writable and are members of the given cluster.
|
||||
// AttachedClusterHosts returns hosts that have this Datastore attached, accessible and writable and are members of the given cluster.
|
||||
func (d Datastore) AttachedClusterHosts(ctx context.Context, cluster *ComputeResource) ([]*HostSystem, error) {
|
||||
var hosts []*HostSystem
|
||||
|
||||
@@ -358,12 +399,12 @@ func (d Datastore) Stat(ctx context.Context, file string) (types.BaseFileInfo, e
|
||||
}
|
||||
|
||||
dsPath := d.Path(path.Dir(file))
|
||||
task, err := b.SearchDatastore(context.TODO(), dsPath, &spec)
|
||||
task, err := b.SearchDatastore(ctx, dsPath, &spec)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
info, err := task.WaitForResult(context.TODO(), nil)
|
||||
info, err := task.WaitForResult(ctx, nil)
|
||||
if err != nil {
|
||||
if info == nil || info.Error != nil {
|
||||
_, ok := info.Error.Fault.(*types.FileNotFound)
|
||||
|
399
vendor/github.com/vmware/govmomi/object/datastore_file.go
generated
vendored
Normal file
399
vendor/github.com/vmware/govmomi/object/datastore_file.go
generated
vendored
Normal file
@@ -0,0 +1,399 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package object
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"path"
|
||||
"time"
|
||||
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
)
|
||||
|
||||
// DatastoreFile implements io.Reader, io.Seeker and io.Closer interfaces for datastore file access.
|
||||
type DatastoreFile struct {
|
||||
d Datastore
|
||||
ctx context.Context
|
||||
name string
|
||||
|
||||
buf io.Reader
|
||||
body io.ReadCloser
|
||||
length int64
|
||||
offset struct {
|
||||
read, seek int64
|
||||
}
|
||||
}
|
||||
|
||||
// Open opens the named file relative to the Datastore.
|
||||
func (d Datastore) Open(ctx context.Context, name string) (*DatastoreFile, error) {
|
||||
return &DatastoreFile{
|
||||
d: d,
|
||||
name: name,
|
||||
length: -1,
|
||||
ctx: ctx,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Read reads up to len(b) bytes from the DatastoreFile.
|
||||
func (f *DatastoreFile) Read(b []byte) (int, error) {
|
||||
if f.offset.read != f.offset.seek {
|
||||
// A Seek() call changed the offset, we need to issue a new GET
|
||||
_ = f.Close()
|
||||
|
||||
f.offset.read = f.offset.seek
|
||||
} else if f.buf != nil {
|
||||
// f.buf + f behaves like an io.MultiReader
|
||||
n, err := f.buf.Read(b)
|
||||
if err == io.EOF {
|
||||
f.buf = nil // buffer has been drained
|
||||
}
|
||||
if n > 0 {
|
||||
return n, nil
|
||||
}
|
||||
}
|
||||
|
||||
body, err := f.get()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
n, err := body.Read(b)
|
||||
|
||||
f.offset.read += int64(n)
|
||||
f.offset.seek += int64(n)
|
||||
|
||||
return n, err
|
||||
}
|
||||
|
||||
// Close closes the DatastoreFile.
|
||||
func (f *DatastoreFile) Close() error {
|
||||
var err error
|
||||
|
||||
if f.body != nil {
|
||||
err = f.body.Close()
|
||||
f.body = nil
|
||||
}
|
||||
|
||||
f.buf = nil
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
// Seek sets the offset for the next Read on the DatastoreFile.
|
||||
func (f *DatastoreFile) Seek(offset int64, whence int) (int64, error) {
|
||||
switch whence {
|
||||
case io.SeekStart:
|
||||
case io.SeekCurrent:
|
||||
offset += f.offset.seek
|
||||
case io.SeekEnd:
|
||||
if f.length < 0 {
|
||||
_, err := f.Stat()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
offset += f.length
|
||||
default:
|
||||
return 0, errors.New("Seek: invalid whence")
|
||||
}
|
||||
|
||||
// allow negative SeekStart for initial Range request
|
||||
if offset < 0 {
|
||||
return 0, errors.New("Seek: invalid offset")
|
||||
}
|
||||
|
||||
f.offset.seek = offset
|
||||
|
||||
return offset, nil
|
||||
}
|
||||
|
||||
type fileStat struct {
|
||||
file *DatastoreFile
|
||||
header http.Header
|
||||
}
|
||||
|
||||
func (s *fileStat) Name() string {
|
||||
return path.Base(s.file.name)
|
||||
}
|
||||
|
||||
func (s *fileStat) Size() int64 {
|
||||
return s.file.length
|
||||
}
|
||||
|
||||
func (s *fileStat) Mode() os.FileMode {
|
||||
return 0
|
||||
}
|
||||
|
||||
func (s *fileStat) ModTime() time.Time {
|
||||
return time.Now() // no Last-Modified
|
||||
}
|
||||
|
||||
func (s *fileStat) IsDir() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (s *fileStat) Sys() interface{} {
|
||||
return s.header
|
||||
}
|
||||
|
||||
func statusError(res *http.Response) error {
|
||||
if res.StatusCode == http.StatusNotFound {
|
||||
return os.ErrNotExist
|
||||
}
|
||||
return errors.New(res.Status)
|
||||
}
|
||||
|
||||
// Stat returns the os.FileInfo interface describing file.
|
||||
func (f *DatastoreFile) Stat() (os.FileInfo, error) {
|
||||
// TODO: consider using Datastore.Stat() instead
|
||||
u, p, err := f.d.downloadTicket(f.ctx, f.name, &soap.Download{Method: "HEAD"})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
res, err := f.d.Client().DownloadRequest(u, p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if res.StatusCode != http.StatusOK {
|
||||
return nil, statusError(res)
|
||||
}
|
||||
|
||||
f.length = res.ContentLength
|
||||
|
||||
return &fileStat{f, res.Header}, nil
|
||||
}
|
||||
|
||||
func (f *DatastoreFile) get() (io.Reader, error) {
|
||||
if f.body != nil {
|
||||
return f.body, nil
|
||||
}
|
||||
|
||||
u, p, err := f.d.downloadTicket(f.ctx, f.name, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if f.offset.read != 0 {
|
||||
p.Headers = map[string]string{
|
||||
"Range": fmt.Sprintf("bytes=%d-", f.offset.read),
|
||||
}
|
||||
}
|
||||
|
||||
res, err := f.d.Client().DownloadRequest(u, p)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch res.StatusCode {
|
||||
case http.StatusOK:
|
||||
f.length = res.ContentLength
|
||||
case http.StatusPartialContent:
|
||||
var start, end int
|
||||
cr := res.Header.Get("Content-Range")
|
||||
_, err = fmt.Sscanf(cr, "bytes %d-%d/%d", &start, &end, &f.length)
|
||||
if err != nil {
|
||||
f.length = -1
|
||||
}
|
||||
case http.StatusRequestedRangeNotSatisfiable:
|
||||
// ok: Read() will return io.EOF
|
||||
default:
|
||||
return nil, statusError(res)
|
||||
}
|
||||
|
||||
if f.length < 0 {
|
||||
_ = res.Body.Close()
|
||||
return nil, errors.New("unable to determine file size")
|
||||
}
|
||||
|
||||
f.body = res.Body
|
||||
|
||||
return f.body, nil
|
||||
}
|
||||
|
||||
func lastIndexLines(s []byte, n *int) int64 {
|
||||
i := len(s) - 1
|
||||
|
||||
for i > 0 {
|
||||
o := bytes.LastIndexByte(s[:i], '\n')
|
||||
if o < 0 {
|
||||
break
|
||||
}
|
||||
|
||||
i = o
|
||||
*n--
|
||||
if *n == 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return int64(i)
|
||||
}
|
||||
|
||||
// Tail seeks to the position of the last N lines of the file.
|
||||
func (f *DatastoreFile) Tail(n int) error {
|
||||
// Read the file in reverse using bsize chunks
|
||||
const bsize = int64(1024 * 16)
|
||||
|
||||
fsize, err := f.Seek(0, io.SeekEnd)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if n == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
chunk := int64(-1)
|
||||
|
||||
buf := bytes.NewBuffer(make([]byte, 0, bsize))
|
||||
|
||||
for {
|
||||
var eof bool
|
||||
var pos int64
|
||||
|
||||
nread := bsize
|
||||
|
||||
offset := chunk * bsize
|
||||
remain := fsize + offset
|
||||
|
||||
if remain < 0 {
|
||||
if pos, err = f.Seek(0, io.SeekStart); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
nread = bsize + remain
|
||||
eof = true
|
||||
} else {
|
||||
if pos, err = f.Seek(offset, io.SeekEnd); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if _, err = io.CopyN(buf, f, nread); err != nil {
|
||||
if err != io.EOF {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
b := buf.Bytes()
|
||||
idx := lastIndexLines(b, &n) + 1
|
||||
|
||||
if n == 0 {
|
||||
if chunk == -1 {
|
||||
// We found all N lines in the last chunk of the file.
|
||||
// The seek offset is also now at the current end of file.
|
||||
// Save this buffer to avoid another GET request when Read() is called.
|
||||
buf.Next(int(idx))
|
||||
f.buf = buf
|
||||
return nil
|
||||
}
|
||||
|
||||
if _, err = f.Seek(pos+idx, io.SeekStart); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
if eof {
|
||||
if remain < 0 {
|
||||
// We found < N lines in the entire file, so seek to the start.
|
||||
_, _ = f.Seek(0, io.SeekStart)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
chunk--
|
||||
buf.Reset()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type followDatastoreFile struct {
|
||||
r *DatastoreFile
|
||||
c chan struct{}
|
||||
i time.Duration
|
||||
}
|
||||
|
||||
// Read reads up to len(b) bytes from the DatastoreFile being followed.
|
||||
// This method will block until data is read, an error other than io.EOF is returned or Close() is called.
|
||||
func (f *followDatastoreFile) Read(p []byte) (int, error) {
|
||||
offset := f.r.offset.seek
|
||||
stop := false
|
||||
|
||||
defer f.r.Close()
|
||||
|
||||
for {
|
||||
n, err := f.r.Read(p)
|
||||
if err != nil && err == io.EOF {
|
||||
_ = f.r.Close() // GET request body has been drained.
|
||||
if stop {
|
||||
return n, err
|
||||
}
|
||||
err = nil
|
||||
}
|
||||
|
||||
if n > 0 {
|
||||
return n, err
|
||||
}
|
||||
|
||||
select {
|
||||
case <-f.c:
|
||||
// Wake up and stop polling once the body has been drained
|
||||
stop = true
|
||||
case <-time.After(f.i):
|
||||
}
|
||||
|
||||
info, serr := f.r.Stat()
|
||||
if serr != nil {
|
||||
// Return EOF rather than 404 if the file goes away
|
||||
if serr == os.ErrNotExist {
|
||||
_ = f.r.Close()
|
||||
return 0, io.EOF
|
||||
}
|
||||
return 0, serr
|
||||
}
|
||||
|
||||
if info.Size() < offset {
|
||||
// assume file has be truncated
|
||||
offset, err = f.r.Seek(0, io.SeekStart)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Close will stop Follow polling and close the underlying DatastoreFile.
|
||||
func (f *followDatastoreFile) Close() error {
|
||||
close(f.c)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Follow returns an io.ReadCloser to stream the file contents as data is appended.
|
||||
func (f *DatastoreFile) Follow(interval time.Duration) io.ReadCloser {
|
||||
return &followDatastoreFile{f, make(chan struct{}), interval}
|
||||
}
|
65
vendor/github.com/vmware/govmomi/object/datastore_path.go
generated
vendored
Normal file
65
vendor/github.com/vmware/govmomi/object/datastore_path.go
generated
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package object
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// DatastorePath contains the components of a datastore path.
|
||||
type DatastorePath struct {
|
||||
Datastore string
|
||||
Path string
|
||||
}
|
||||
|
||||
// FromString parses a datastore path.
|
||||
// Returns true if the path could be parsed, false otherwise.
|
||||
func (p *DatastorePath) FromString(s string) bool {
|
||||
if len(s) == 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
s = strings.TrimSpace(s)
|
||||
|
||||
if !strings.HasPrefix(s, "[") {
|
||||
return false
|
||||
}
|
||||
|
||||
s = s[1:]
|
||||
|
||||
ix := strings.Index(s, "]")
|
||||
if ix < 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
p.Datastore = s[:ix]
|
||||
p.Path = strings.TrimSpace(s[ix+1:])
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
// String formats a datastore path.
|
||||
func (p *DatastorePath) String() string {
|
||||
s := fmt.Sprintf("[%s]", p.Datastore)
|
||||
|
||||
if p.Path == "" {
|
||||
return s
|
||||
}
|
||||
|
||||
return strings.Join([]string{s, p.Path}, " ")
|
||||
}
|
76
vendor/github.com/vmware/govmomi/object/diagnostic_log.go
generated
vendored
Normal file
76
vendor/github.com/vmware/govmomi/object/diagnostic_log.go
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
Copyright (c) 2015 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package object
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"math"
|
||||
)
|
||||
|
||||
// DiagnosticLog wraps DiagnosticManager.BrowseLog
|
||||
type DiagnosticLog struct {
|
||||
m DiagnosticManager
|
||||
|
||||
Key string
|
||||
Host *HostSystem
|
||||
|
||||
Start int32
|
||||
}
|
||||
|
||||
// Seek to log position starting at the last nlines of the log
|
||||
func (l *DiagnosticLog) Seek(ctx context.Context, nlines int32) error {
|
||||
h, err := l.m.BrowseLog(ctx, l.Host, l.Key, math.MaxInt32, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
l.Start = h.LineEnd - nlines
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Copy log starting from l.Start to the given io.Writer
|
||||
// Returns on error or when end of log is reached.
|
||||
func (l *DiagnosticLog) Copy(ctx context.Context, w io.Writer) (int, error) {
|
||||
const max = 500 // VC max == 500, ESX max == 1000
|
||||
written := 0
|
||||
|
||||
for {
|
||||
h, err := l.m.BrowseLog(ctx, l.Host, l.Key, l.Start, max)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
for _, line := range h.LineText {
|
||||
n, err := fmt.Fprintln(w, line)
|
||||
written += n
|
||||
if err != nil {
|
||||
return written, err
|
||||
}
|
||||
}
|
||||
|
||||
l.Start += int32(len(h.LineText))
|
||||
|
||||
if l.Start >= h.LineEnd {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return written, nil
|
||||
}
|
11
vendor/github.com/vmware/govmomi/object/diagnostic_manager.go
generated
vendored
11
vendor/github.com/vmware/govmomi/object/diagnostic_manager.go
generated
vendored
@@ -17,10 +17,11 @@ 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"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type DiagnosticManager struct {
|
||||
@@ -35,6 +36,14 @@ func NewDiagnosticManager(c *vim25.Client) *DiagnosticManager {
|
||||
return &m
|
||||
}
|
||||
|
||||
func (m DiagnosticManager) Log(ctx context.Context, host *HostSystem, key string) *DiagnosticLog {
|
||||
return &DiagnosticLog{
|
||||
m: m,
|
||||
Key: key,
|
||||
Host: host,
|
||||
}
|
||||
}
|
||||
|
||||
func (m DiagnosticManager) BrowseLog(ctx context.Context, host *HostSystem, key string, start, lines int32) (*types.DiagnosticManagerLogHeader, error) {
|
||||
req := types.BrowseDiagnosticLog{
|
||||
This: m.Reference(),
|
||||
|
18
vendor/github.com/vmware/govmomi/object/distributed_virtual_portgroup.go
generated
vendored
18
vendor/github.com/vmware/govmomi/object/distributed_virtual_portgroup.go
generated
vendored
@@ -17,10 +17,12 @@ limitations under the License.
|
||||
package object
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/vmware/govmomi/vim25"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type DistributedVirtualPortgroup struct {
|
||||
@@ -55,3 +57,17 @@ func (p DistributedVirtualPortgroup) EthernetCardBackingInfo(ctx context.Context
|
||||
|
||||
return backing, nil
|
||||
}
|
||||
|
||||
func (p DistributedVirtualPortgroup) Reconfigure(ctx context.Context, spec types.DVPortgroupConfigSpec) (*Task, error) {
|
||||
req := types.ReconfigureDVPortgroup_Task{
|
||||
This: p.Reference(),
|
||||
Spec: spec,
|
||||
}
|
||||
|
||||
res, err := methods.ReconfigureDVPortgroup_Task(ctx, p.Client(), &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewTask(p.Client(), res.Returnval), nil
|
||||
}
|
||||
|
3
vendor/github.com/vmware/govmomi/object/distributed_virtual_switch.go
generated
vendored
3
vendor/github.com/vmware/govmomi/object/distributed_virtual_switch.go
generated
vendored
@@ -17,10 +17,11 @@ 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"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type DistributedVirtualSwitch struct {
|
||||
|
3
vendor/github.com/vmware/govmomi/object/extension_manager.go
generated
vendored
3
vendor/github.com/vmware/govmomi/object/extension_manager.go
generated
vendored
@@ -17,11 +17,12 @@ limitations under the License.
|
||||
package object
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/vmware/govmomi/vim25"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type ExtensionManager struct {
|
||||
|
3
vendor/github.com/vmware/govmomi/object/file_manager.go
generated
vendored
3
vendor/github.com/vmware/govmomi/object/file_manager.go
generated
vendored
@@ -17,10 +17,11 @@ 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"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type FileManager struct {
|
||||
|
3
vendor/github.com/vmware/govmomi/object/folder.go
generated
vendored
3
vendor/github.com/vmware/govmomi/object/folder.go
generated
vendored
@@ -17,11 +17,12 @@ limitations under the License.
|
||||
package object
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/vmware/govmomi/vim25"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type Folder struct {
|
||||
|
3
vendor/github.com/vmware/govmomi/object/history_collector.go
generated
vendored
3
vendor/github.com/vmware/govmomi/object/history_collector.go
generated
vendored
@@ -17,10 +17,11 @@ 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"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type HistoryCollector struct {
|
||||
|
3
vendor/github.com/vmware/govmomi/object/host_account_manager.go
generated
vendored
3
vendor/github.com/vmware/govmomi/object/host_account_manager.go
generated
vendored
@@ -17,10 +17,11 @@ 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"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type HostAccountManager struct {
|
||||
|
250
vendor/github.com/vmware/govmomi/object/host_certificate_info.go
generated
vendored
Normal file
250
vendor/github.com/vmware/govmomi/object/host_certificate_info.go
generated
vendored
Normal file
@@ -0,0 +1,250 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package object
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"crypto/x509/pkix"
|
||||
"encoding/asn1"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/url"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
|
||||
"github.com/vmware/govmomi/vim25/soap"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
// HostCertificateInfo provides helpers for types.HostCertificateManagerCertificateInfo
|
||||
type HostCertificateInfo struct {
|
||||
types.HostCertificateManagerCertificateInfo
|
||||
|
||||
ThumbprintSHA1 string
|
||||
ThumbprintSHA256 string
|
||||
|
||||
Err error
|
||||
Certificate *x509.Certificate `json:"-"`
|
||||
|
||||
subjectName *pkix.Name
|
||||
issuerName *pkix.Name
|
||||
}
|
||||
|
||||
// FromCertificate converts x509.Certificate to HostCertificateInfo
|
||||
func (info *HostCertificateInfo) FromCertificate(cert *x509.Certificate) *HostCertificateInfo {
|
||||
info.Certificate = cert
|
||||
info.subjectName = &cert.Subject
|
||||
info.issuerName = &cert.Issuer
|
||||
|
||||
info.Issuer = info.fromName(info.issuerName)
|
||||
info.NotBefore = &cert.NotBefore
|
||||
info.NotAfter = &cert.NotAfter
|
||||
info.Subject = info.fromName(info.subjectName)
|
||||
|
||||
info.ThumbprintSHA1 = soap.ThumbprintSHA1(cert)
|
||||
|
||||
// SHA-256 for info purposes only, API fields all use SHA-1
|
||||
sum := sha256.Sum256(cert.Raw)
|
||||
hex := make([]string, len(sum))
|
||||
for i, b := range sum {
|
||||
hex[i] = fmt.Sprintf("%02X", b)
|
||||
}
|
||||
info.ThumbprintSHA256 = strings.Join(hex, ":")
|
||||
|
||||
if info.Status == "" {
|
||||
info.Status = string(types.HostCertificateManagerCertificateInfoCertificateStatusUnknown)
|
||||
}
|
||||
|
||||
return info
|
||||
}
|
||||
|
||||
// FromURL connects to the given URL.Host via tls.Dial with the given tls.Config and populates the HostCertificateInfo
|
||||
// via tls.ConnectionState. If the certificate was verified with the given tls.Config, the Err field will be nil.
|
||||
// Otherwise, Err will be set to the x509.UnknownAuthorityError or x509.HostnameError.
|
||||
// If tls.Dial returns an error of any other type, that error is returned.
|
||||
func (info *HostCertificateInfo) FromURL(u *url.URL, config *tls.Config) error {
|
||||
addr := u.Host
|
||||
if !(strings.LastIndex(addr, ":") > strings.LastIndex(addr, "]")) {
|
||||
addr += ":443"
|
||||
}
|
||||
|
||||
conn, err := tls.Dial("tcp", addr, config)
|
||||
if err != nil {
|
||||
switch err.(type) {
|
||||
case x509.UnknownAuthorityError:
|
||||
case x509.HostnameError:
|
||||
default:
|
||||
return err
|
||||
}
|
||||
|
||||
info.Err = err
|
||||
|
||||
conn, err = tls.Dial("tcp", addr, &tls.Config{InsecureSkipVerify: true})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
info.Status = string(types.HostCertificateManagerCertificateInfoCertificateStatusGood)
|
||||
}
|
||||
|
||||
state := conn.ConnectionState()
|
||||
_ = conn.Close()
|
||||
info.FromCertificate(state.PeerCertificates[0])
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var emailAddressOID = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 1}
|
||||
|
||||
func (info *HostCertificateInfo) fromName(name *pkix.Name) string {
|
||||
var attrs []string
|
||||
|
||||
oids := map[string]string{
|
||||
emailAddressOID.String(): "emailAddress",
|
||||
}
|
||||
|
||||
for _, attr := range name.Names {
|
||||
if key, ok := oids[attr.Type.String()]; ok {
|
||||
attrs = append(attrs, fmt.Sprintf("%s=%s", key, attr.Value))
|
||||
}
|
||||
}
|
||||
|
||||
attrs = append(attrs, fmt.Sprintf("CN=%s", name.CommonName))
|
||||
|
||||
add := func(key string, vals []string) {
|
||||
for _, val := range vals {
|
||||
attrs = append(attrs, fmt.Sprintf("%s=%s", key, val))
|
||||
}
|
||||
}
|
||||
|
||||
elts := []struct {
|
||||
key string
|
||||
val []string
|
||||
}{
|
||||
{"OU", name.OrganizationalUnit},
|
||||
{"O", name.Organization},
|
||||
{"L", name.Locality},
|
||||
{"ST", name.Province},
|
||||
{"C", name.Country},
|
||||
}
|
||||
|
||||
for _, elt := range elts {
|
||||
add(elt.key, elt.val)
|
||||
}
|
||||
|
||||
return strings.Join(attrs, ",")
|
||||
}
|
||||
|
||||
func (info *HostCertificateInfo) toName(s string) *pkix.Name {
|
||||
var name pkix.Name
|
||||
|
||||
for _, pair := range strings.Split(s, ",") {
|
||||
attr := strings.SplitN(pair, "=", 2)
|
||||
if len(attr) != 2 {
|
||||
continue
|
||||
}
|
||||
|
||||
v := attr[1]
|
||||
|
||||
switch strings.ToLower(attr[0]) {
|
||||
case "cn":
|
||||
name.CommonName = v
|
||||
case "ou":
|
||||
name.OrganizationalUnit = append(name.OrganizationalUnit, v)
|
||||
case "o":
|
||||
name.Organization = append(name.Organization, v)
|
||||
case "l":
|
||||
name.Locality = append(name.Locality, v)
|
||||
case "st":
|
||||
name.Province = append(name.Province, v)
|
||||
case "c":
|
||||
name.Country = append(name.Country, v)
|
||||
case "emailaddress":
|
||||
name.Names = append(name.Names, pkix.AttributeTypeAndValue{Type: emailAddressOID, Value: v})
|
||||
}
|
||||
}
|
||||
|
||||
return &name
|
||||
}
|
||||
|
||||
// SubjectName parses Subject into a pkix.Name
|
||||
func (info *HostCertificateInfo) SubjectName() *pkix.Name {
|
||||
if info.subjectName != nil {
|
||||
return info.subjectName
|
||||
}
|
||||
|
||||
return info.toName(info.Subject)
|
||||
}
|
||||
|
||||
// IssuerName parses Issuer into a pkix.Name
|
||||
func (info *HostCertificateInfo) IssuerName() *pkix.Name {
|
||||
if info.issuerName != nil {
|
||||
return info.issuerName
|
||||
}
|
||||
|
||||
return info.toName(info.Issuer)
|
||||
}
|
||||
|
||||
// Write outputs info similar to the Chrome Certificate Viewer.
|
||||
func (info *HostCertificateInfo) Write(w io.Writer) error {
|
||||
tw := tabwriter.NewWriter(w, 2, 0, 2, ' ', 0)
|
||||
|
||||
s := func(val string) string {
|
||||
if val != "" {
|
||||
return val
|
||||
}
|
||||
return "<Not Part Of Certificate>"
|
||||
}
|
||||
|
||||
ss := func(val []string) string {
|
||||
return s(strings.Join(val, ","))
|
||||
}
|
||||
|
||||
name := func(n *pkix.Name) {
|
||||
fmt.Fprintf(tw, " Common Name (CN):\t%s\n", s(n.CommonName))
|
||||
fmt.Fprintf(tw, " Organization (O):\t%s\n", ss(n.Organization))
|
||||
fmt.Fprintf(tw, " Organizational Unit (OU):\t%s\n", ss(n.OrganizationalUnit))
|
||||
}
|
||||
|
||||
status := info.Status
|
||||
if info.Err != nil {
|
||||
status = fmt.Sprintf("ERROR %s", info.Err)
|
||||
}
|
||||
fmt.Fprintf(tw, "Certificate Status:\t%s\n", status)
|
||||
|
||||
fmt.Fprintln(tw, "Issued To:\t")
|
||||
name(info.SubjectName())
|
||||
|
||||
fmt.Fprintln(tw, "Issued By:\t")
|
||||
name(info.IssuerName())
|
||||
|
||||
fmt.Fprintln(tw, "Validity Period:\t")
|
||||
fmt.Fprintf(tw, " Issued On:\t%s\n", info.NotBefore)
|
||||
fmt.Fprintf(tw, " Expires On:\t%s\n", info.NotAfter)
|
||||
|
||||
if info.ThumbprintSHA1 != "" {
|
||||
fmt.Fprintln(tw, "Thumbprints:\t")
|
||||
if info.ThumbprintSHA256 != "" {
|
||||
fmt.Fprintf(tw, " SHA-256 Thumbprint:\t%s\n", info.ThumbprintSHA256)
|
||||
}
|
||||
fmt.Fprintf(tw, " SHA-1 Thumbprint:\t%s\n", info.ThumbprintSHA1)
|
||||
}
|
||||
|
||||
return tw.Flush()
|
||||
}
|
162
vendor/github.com/vmware/govmomi/object/host_certificate_manager.go
generated
vendored
Normal file
162
vendor/github.com/vmware/govmomi/object/host_certificate_manager.go
generated
vendored
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package object
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/vmware/govmomi/property"
|
||||
"github.com/vmware/govmomi/vim25"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
// HostCertificateManager provides helper methods around the HostSystem.ConfigManager.CertificateManager
|
||||
type HostCertificateManager struct {
|
||||
Common
|
||||
Host *HostSystem
|
||||
}
|
||||
|
||||
// NewHostCertificateManager creates a new HostCertificateManager helper
|
||||
func NewHostCertificateManager(c *vim25.Client, ref types.ManagedObjectReference, host types.ManagedObjectReference) *HostCertificateManager {
|
||||
return &HostCertificateManager{
|
||||
Common: NewCommon(c, ref),
|
||||
Host: NewHostSystem(c, host),
|
||||
}
|
||||
}
|
||||
|
||||
// CertificateInfo wraps the host CertificateManager certificateInfo property with the HostCertificateInfo helper.
|
||||
// The ThumbprintSHA1 field is set to HostSystem.Summary.Config.SslThumbprint if the host system is managed by a vCenter.
|
||||
func (m HostCertificateManager) CertificateInfo(ctx context.Context) (*HostCertificateInfo, error) {
|
||||
var hs mo.HostSystem
|
||||
var cm mo.HostCertificateManager
|
||||
|
||||
pc := property.DefaultCollector(m.Client())
|
||||
|
||||
err := pc.RetrieveOne(ctx, m.Reference(), []string{"certificateInfo"}, &cm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
_ = pc.RetrieveOne(ctx, m.Host.Reference(), []string{"summary.config.sslThumbprint"}, &hs)
|
||||
|
||||
return &HostCertificateInfo{
|
||||
HostCertificateManagerCertificateInfo: cm.CertificateInfo,
|
||||
ThumbprintSHA1: hs.Summary.Config.SslThumbprint,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// GenerateCertificateSigningRequest requests the host system to generate a certificate-signing request (CSR) for itself.
|
||||
// The CSR is then typically provided to a Certificate Authority to sign and issue the SSL certificate for the host system.
|
||||
// Use InstallServerCertificate to import this certificate.
|
||||
func (m HostCertificateManager) GenerateCertificateSigningRequest(ctx context.Context, useIPAddressAsCommonName bool) (string, error) {
|
||||
req := types.GenerateCertificateSigningRequest{
|
||||
This: m.Reference(),
|
||||
UseIpAddressAsCommonName: useIPAddressAsCommonName,
|
||||
}
|
||||
|
||||
res, err := methods.GenerateCertificateSigningRequest(ctx, m.Client(), &req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return res.Returnval, nil
|
||||
}
|
||||
|
||||
// GenerateCertificateSigningRequestByDn requests the host system to generate a certificate-signing request (CSR) for itself.
|
||||
// Alternative version similar to GenerateCertificateSigningRequest but takes a Distinguished Name (DN) as a parameter.
|
||||
func (m HostCertificateManager) GenerateCertificateSigningRequestByDn(ctx context.Context, distinguishedName string) (string, error) {
|
||||
req := types.GenerateCertificateSigningRequestByDn{
|
||||
This: m.Reference(),
|
||||
DistinguishedName: distinguishedName,
|
||||
}
|
||||
|
||||
res, err := methods.GenerateCertificateSigningRequestByDn(ctx, m.Client(), &req)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return res.Returnval, nil
|
||||
}
|
||||
|
||||
// InstallServerCertificate imports the given SSL certificate to the host system.
|
||||
func (m HostCertificateManager) InstallServerCertificate(ctx context.Context, cert string) error {
|
||||
req := types.InstallServerCertificate{
|
||||
This: m.Reference(),
|
||||
Cert: cert,
|
||||
}
|
||||
|
||||
_, err := methods.InstallServerCertificate(ctx, m.Client(), &req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// NotifyAffectedService is internal, not exposing as we don't have a use case other than with InstallServerCertificate
|
||||
// Without this call, hostd needs to be restarted to use the updated certificate
|
||||
// Note: using Refresh as it has the same struct/signature, we just need to use different xml name tags
|
||||
body := struct {
|
||||
Req *types.Refresh `xml:"urn:vim25 NotifyAffectedServices,omitempty"`
|
||||
Res *types.RefreshResponse `xml:"urn:vim25 NotifyAffectedServicesResponse,omitempty"`
|
||||
methods.RefreshBody
|
||||
}{
|
||||
Req: &types.Refresh{This: m.Reference()},
|
||||
}
|
||||
|
||||
return m.Client().RoundTrip(ctx, &body, &body)
|
||||
}
|
||||
|
||||
// ListCACertificateRevocationLists returns the SSL CRLs of Certificate Authorities that are trusted by the host system.
|
||||
func (m HostCertificateManager) ListCACertificateRevocationLists(ctx context.Context) ([]string, error) {
|
||||
req := types.ListCACertificateRevocationLists{
|
||||
This: m.Reference(),
|
||||
}
|
||||
|
||||
res, err := methods.ListCACertificateRevocationLists(ctx, m.Client(), &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return res.Returnval, nil
|
||||
}
|
||||
|
||||
// ListCACertificates returns the SSL certificates of Certificate Authorities that are trusted by the host system.
|
||||
func (m HostCertificateManager) ListCACertificates(ctx context.Context) ([]string, error) {
|
||||
req := types.ListCACertificates{
|
||||
This: m.Reference(),
|
||||
}
|
||||
|
||||
res, err := methods.ListCACertificates(ctx, m.Client(), &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return res.Returnval, nil
|
||||
}
|
||||
|
||||
// ReplaceCACertificatesAndCRLs replaces the trusted CA certificates and CRL used by the host system.
|
||||
// These determine whether the server can verify the identity of an external entity.
|
||||
func (m HostCertificateManager) ReplaceCACertificatesAndCRLs(ctx context.Context, caCert []string, caCrl []string) error {
|
||||
req := types.ReplaceCACertificatesAndCRLs{
|
||||
This: m.Reference(),
|
||||
CaCert: caCert,
|
||||
CaCrl: caCrl,
|
||||
}
|
||||
|
||||
_, err := methods.ReplaceCACertificatesAndCRLs(ctx, m.Client(), &req)
|
||||
return err
|
||||
}
|
51
vendor/github.com/vmware/govmomi/object/host_config_manager.go
generated
vendored
51
vendor/github.com/vmware/govmomi/object/host_config_manager.go
generated
vendored
@@ -17,10 +17,11 @@ limitations under the License.
|
||||
package object
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/vmware/govmomi/vim25"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type HostConfigManager struct {
|
||||
@@ -96,6 +97,11 @@ func (m HostConfigManager) VsanSystem(ctx context.Context) (*HostVsanSystem, err
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Added in 5.5
|
||||
if h.ConfigManager.VsanSystem == nil {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
return NewHostVsanSystem(m.c, *h.ConfigManager.VsanSystem), nil
|
||||
}
|
||||
|
||||
@@ -107,7 +113,21 @@ func (m HostConfigManager) AccountManager(ctx context.Context) (*HostAccountMana
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewHostAccountManager(m.c, *h.ConfigManager.AccountManager), nil
|
||||
ref := h.ConfigManager.AccountManager // Added in 6.0
|
||||
if ref == nil {
|
||||
// Versions < 5.5 can use the ServiceContent ref,
|
||||
// but we can only use it when connected directly to ESX.
|
||||
c := m.Client()
|
||||
if !c.IsVC() {
|
||||
ref = c.ServiceContent.AccountManager
|
||||
}
|
||||
|
||||
if ref == nil {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
}
|
||||
|
||||
return NewHostAccountManager(m.c, *ref), nil
|
||||
}
|
||||
|
||||
func (m HostConfigManager) OptionManager(ctx context.Context) (*OptionManager, error) {
|
||||
@@ -131,3 +151,30 @@ func (m HostConfigManager) ServiceSystem(ctx context.Context) (*HostServiceSyste
|
||||
|
||||
return NewHostServiceSystem(m.c, *h.ConfigManager.ServiceSystem), nil
|
||||
}
|
||||
|
||||
func (m HostConfigManager) CertificateManager(ctx context.Context) (*HostCertificateManager, error) {
|
||||
var h mo.HostSystem
|
||||
|
||||
err := m.Properties(ctx, m.Reference(), []string{"configManager.certificateManager"}, &h)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Added in 6.0
|
||||
if h.ConfigManager.CertificateManager == nil {
|
||||
return nil, ErrNotSupported
|
||||
}
|
||||
|
||||
return NewHostCertificateManager(m.c, *h.ConfigManager.CertificateManager, m.Reference()), nil
|
||||
}
|
||||
|
||||
func (m HostConfigManager) DateTimeSystem(ctx context.Context) (*HostDateTimeSystem, error) {
|
||||
var h mo.HostSystem
|
||||
|
||||
err := m.Properties(ctx, m.Reference(), []string{"configManager.dateTimeSystem"}, &h)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewHostDateTimeSystem(m.c, *h.ConfigManager.DateTimeSystem), nil
|
||||
}
|
||||
|
3
vendor/github.com/vmware/govmomi/object/host_datastore_browser.go
generated
vendored
3
vendor/github.com/vmware/govmomi/object/host_datastore_browser.go
generated
vendored
@@ -17,10 +17,11 @@ 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"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type HostDatastoreBrowser struct {
|
||||
|
3
vendor/github.com/vmware/govmomi/object/host_datastore_system.go
generated
vendored
3
vendor/github.com/vmware/govmomi/object/host_datastore_system.go
generated
vendored
@@ -17,10 +17,11 @@ 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"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type HostDatastoreSystem struct {
|
||||
|
69
vendor/github.com/vmware/govmomi/object/host_date_time_system.go
generated
vendored
Normal file
69
vendor/github.com/vmware/govmomi/object/host_date_time_system.go
generated
vendored
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
Copyright (c) 2016 VMware, Inc. All Rights Reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package object
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/vmware/govmomi/vim25"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
)
|
||||
|
||||
type HostDateTimeSystem struct {
|
||||
Common
|
||||
}
|
||||
|
||||
func NewHostDateTimeSystem(c *vim25.Client, ref types.ManagedObjectReference) *HostDateTimeSystem {
|
||||
return &HostDateTimeSystem{
|
||||
Common: NewCommon(c, ref),
|
||||
}
|
||||
}
|
||||
|
||||
func (s HostDateTimeSystem) UpdateConfig(ctx context.Context, config types.HostDateTimeConfig) error {
|
||||
req := types.UpdateDateTimeConfig{
|
||||
This: s.Reference(),
|
||||
Config: config,
|
||||
}
|
||||
|
||||
_, err := methods.UpdateDateTimeConfig(ctx, s.c, &req)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s HostDateTimeSystem) Update(ctx context.Context, date time.Time) error {
|
||||
req := types.UpdateDateTime{
|
||||
This: s.Reference(),
|
||||
DateTime: date,
|
||||
}
|
||||
|
||||
_, err := methods.UpdateDateTime(ctx, s.c, &req)
|
||||
return err
|
||||
}
|
||||
|
||||
func (s HostDateTimeSystem) Query(ctx context.Context) (*time.Time, error) {
|
||||
req := types.QueryDateTime{
|
||||
This: s.Reference(),
|
||||
}
|
||||
|
||||
res, err := methods.QueryDateTime(ctx, s.c, &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &res.Returnval, nil
|
||||
}
|
2
vendor/github.com/vmware/govmomi/object/host_firewall_system.go
generated
vendored
2
vendor/github.com/vmware/govmomi/object/host_firewall_system.go
generated
vendored
@@ -17,6 +17,7 @@ limitations under the License.
|
||||
package object
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strings"
|
||||
@@ -25,7 +26,6 @@ import (
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type HostFirewallSystem struct {
|
||||
|
3
vendor/github.com/vmware/govmomi/object/host_network_system.go
generated
vendored
3
vendor/github.com/vmware/govmomi/object/host_network_system.go
generated
vendored
@@ -17,10 +17,11 @@ 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"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type HostNetworkSystem struct {
|
||||
|
3
vendor/github.com/vmware/govmomi/object/host_service_system.go
generated
vendored
3
vendor/github.com/vmware/govmomi/object/host_service_system.go
generated
vendored
@@ -17,11 +17,12 @@ limitations under the License.
|
||||
package object
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/vmware/govmomi/vim25"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type HostServiceSystem struct {
|
||||
|
2
vendor/github.com/vmware/govmomi/object/host_storage_system.go
generated
vendored
2
vendor/github.com/vmware/govmomi/object/host_storage_system.go
generated
vendored
@@ -17,12 +17,12 @@ limitations under the License.
|
||||
package object
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/vmware/govmomi/vim25"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type HostStorageSystem struct {
|
||||
|
2
vendor/github.com/vmware/govmomi/object/host_system.go
generated
vendored
2
vendor/github.com/vmware/govmomi/object/host_system.go
generated
vendored
@@ -17,6 +17,7 @@ limitations under the License.
|
||||
package object
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
|
||||
@@ -24,7 +25,6 @@ import (
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type HostSystem struct {
|
||||
|
3
vendor/github.com/vmware/govmomi/object/host_virtual_nic_manager.go
generated
vendored
3
vendor/github.com/vmware/govmomi/object/host_virtual_nic_manager.go
generated
vendored
@@ -17,11 +17,12 @@ limitations under the License.
|
||||
package object
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/vmware/govmomi/vim25"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type HostVirtualNicManager struct {
|
||||
|
3
vendor/github.com/vmware/govmomi/object/host_vsan_system.go
generated
vendored
3
vendor/github.com/vmware/govmomi/object/host_vsan_system.go
generated
vendored
@@ -17,11 +17,12 @@ limitations under the License.
|
||||
package object
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/vmware/govmomi/vim25"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type HostVsanSystem struct {
|
||||
|
2
vendor/github.com/vmware/govmomi/object/http_nfc_lease.go
generated
vendored
2
vendor/github.com/vmware/govmomi/object/http_nfc_lease.go
generated
vendored
@@ -17,6 +17,7 @@ limitations under the License.
|
||||
package object
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
@@ -25,7 +26,6 @@ import (
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type HttpNfcLease struct {
|
||||
|
31
vendor/github.com/vmware/govmomi/object/list_view.go
generated
vendored
31
vendor/github.com/vmware/govmomi/object/list_view.go
generated
vendored
@@ -17,10 +17,11 @@ 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"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type ListView struct {
|
||||
@@ -37,7 +38,33 @@ func (v ListView) Destroy(ctx context.Context) error {
|
||||
req := types.DestroyView{
|
||||
This: v.Reference(),
|
||||
}
|
||||
|
||||
_, err := methods.DestroyView(ctx, v.c, &req)
|
||||
return err
|
||||
}
|
||||
|
||||
func (v ListView) Add(ctx context.Context, refs []types.ManagedObjectReference) error {
|
||||
req := types.ModifyListView{
|
||||
This: v.Reference(),
|
||||
Add: refs,
|
||||
}
|
||||
_, err := methods.ModifyListView(ctx, v.c, &req)
|
||||
return err
|
||||
}
|
||||
|
||||
func (v ListView) Remove(ctx context.Context, refs []types.ManagedObjectReference) error {
|
||||
req := types.ModifyListView{
|
||||
This: v.Reference(),
|
||||
Remove: refs,
|
||||
}
|
||||
_, err := methods.ModifyListView(ctx, v.c, &req)
|
||||
return err
|
||||
}
|
||||
|
||||
func (v ListView) Reset(ctx context.Context, refs []types.ManagedObjectReference) error {
|
||||
req := types.ResetListView{
|
||||
This: v.Reference(),
|
||||
Obj: refs,
|
||||
}
|
||||
_, err := methods.ResetListView(ctx, v.c, &req)
|
||||
return err
|
||||
}
|
||||
|
3
vendor/github.com/vmware/govmomi/object/namespace_manager.go
generated
vendored
3
vendor/github.com/vmware/govmomi/object/namespace_manager.go
generated
vendored
@@ -17,10 +17,11 @@ 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"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type DatastoreNamespaceManager struct {
|
||||
|
3
vendor/github.com/vmware/govmomi/object/network.go
generated
vendored
3
vendor/github.com/vmware/govmomi/object/network.go
generated
vendored
@@ -17,9 +17,10 @@ limitations under the License.
|
||||
package object
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/vmware/govmomi/vim25"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type Network struct {
|
||||
|
3
vendor/github.com/vmware/govmomi/object/network_reference.go
generated
vendored
3
vendor/github.com/vmware/govmomi/object/network_reference.go
generated
vendored
@@ -17,8 +17,9 @@ limitations under the License.
|
||||
package object
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// The NetworkReference interface is implemented by managed objects
|
||||
|
3
vendor/github.com/vmware/govmomi/object/option_manager.go
generated
vendored
3
vendor/github.com/vmware/govmomi/object/option_manager.go
generated
vendored
@@ -17,10 +17,11 @@ 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"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type OptionManager struct {
|
||||
|
3
vendor/github.com/vmware/govmomi/object/ovf_manager.go
generated
vendored
3
vendor/github.com/vmware/govmomi/object/ovf_manager.go
generated
vendored
@@ -17,10 +17,11 @@ 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"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type OvfManager struct {
|
||||
|
3
vendor/github.com/vmware/govmomi/object/resource_pool.go
generated
vendored
3
vendor/github.com/vmware/govmomi/object/resource_pool.go
generated
vendored
@@ -17,10 +17,11 @@ 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"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type ResourcePool struct {
|
||||
|
3
vendor/github.com/vmware/govmomi/object/search_index.go
generated
vendored
3
vendor/github.com/vmware/govmomi/object/search_index.go
generated
vendored
@@ -17,10 +17,11 @@ 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"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type SearchIndex struct {
|
||||
|
3
vendor/github.com/vmware/govmomi/object/storage_resource_manager.go
generated
vendored
3
vendor/github.com/vmware/govmomi/object/storage_resource_manager.go
generated
vendored
@@ -17,10 +17,11 @@ 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"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type StorageResourceManager struct {
|
||||
|
3
vendor/github.com/vmware/govmomi/object/task.go
generated
vendored
3
vendor/github.com/vmware/govmomi/object/task.go
generated
vendored
@@ -17,12 +17,13 @@ limitations under the License.
|
||||
package object
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/vmware/govmomi/property"
|
||||
"github.com/vmware/govmomi/task"
|
||||
"github.com/vmware/govmomi/vim25"
|
||||
"github.com/vmware/govmomi/vim25/progress"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
// Task is a convenience wrapper around task.Task that keeps a reference to
|
||||
|
2
vendor/github.com/vmware/govmomi/object/types.go
generated
vendored
2
vendor/github.com/vmware/govmomi/object/types.go
generated
vendored
@@ -47,7 +47,7 @@ func NewReference(c *vim25.Client, e types.ManagedObjectReference) Reference {
|
||||
return NewClusterComputeResource(c, e)
|
||||
case "HostSystem":
|
||||
return NewHostSystem(c, e)
|
||||
case "Network":
|
||||
case "Network", "OpaqueNetwork":
|
||||
return NewNetwork(c, e)
|
||||
case "ResourcePool":
|
||||
return NewResourcePool(c, e)
|
||||
|
12
vendor/github.com/vmware/govmomi/object/virtual_app.go
generated
vendored
12
vendor/github.com/vmware/govmomi/object/virtual_app.go
generated
vendored
@@ -17,7 +17,7 @@ limitations under the License.
|
||||
package object
|
||||
|
||||
import (
|
||||
"golang.org/x/net/context"
|
||||
"context"
|
||||
|
||||
"github.com/vmware/govmomi/vim25"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
@@ -34,7 +34,7 @@ func NewVirtualApp(c *vim25.Client, ref types.ManagedObjectReference) *VirtualAp
|
||||
}
|
||||
}
|
||||
|
||||
func (p VirtualApp) CreateChildVM_Task(ctx context.Context, config types.VirtualMachineConfigSpec, host *HostSystem) (*Task, error) {
|
||||
func (p VirtualApp) CreateChildVM(ctx context.Context, config types.VirtualMachineConfigSpec, host *HostSystem) (*Task, error) {
|
||||
req := types.CreateChildVM_Task{
|
||||
This: p.Reference(),
|
||||
Config: config,
|
||||
@@ -53,7 +53,7 @@ func (p VirtualApp) CreateChildVM_Task(ctx context.Context, config types.Virtual
|
||||
return NewTask(p.c, res.Returnval), nil
|
||||
}
|
||||
|
||||
func (p VirtualApp) UpdateVAppConfig(ctx context.Context, spec types.VAppConfigSpec) error {
|
||||
func (p VirtualApp) UpdateConfig(ctx context.Context, spec types.VAppConfigSpec) error {
|
||||
req := types.UpdateVAppConfig{
|
||||
This: p.Reference(),
|
||||
Spec: spec,
|
||||
@@ -63,7 +63,7 @@ func (p VirtualApp) UpdateVAppConfig(ctx context.Context, spec types.VAppConfigS
|
||||
return err
|
||||
}
|
||||
|
||||
func (p VirtualApp) PowerOnVApp_Task(ctx context.Context) (*Task, error) {
|
||||
func (p VirtualApp) PowerOn(ctx context.Context) (*Task, error) {
|
||||
req := types.PowerOnVApp_Task{
|
||||
This: p.Reference(),
|
||||
}
|
||||
@@ -76,7 +76,7 @@ func (p VirtualApp) PowerOnVApp_Task(ctx context.Context) (*Task, error) {
|
||||
return NewTask(p.c, res.Returnval), nil
|
||||
}
|
||||
|
||||
func (p VirtualApp) PowerOffVApp_Task(ctx context.Context, force bool) (*Task, error) {
|
||||
func (p VirtualApp) PowerOff(ctx context.Context, force bool) (*Task, error) {
|
||||
req := types.PowerOffVApp_Task{
|
||||
This: p.Reference(),
|
||||
Force: force,
|
||||
@@ -91,7 +91,7 @@ func (p VirtualApp) PowerOffVApp_Task(ctx context.Context, force bool) (*Task, e
|
||||
|
||||
}
|
||||
|
||||
func (p VirtualApp) SuspendVApp_Task(ctx context.Context) (*Task, error) {
|
||||
func (p VirtualApp) Suspend(ctx context.Context) (*Task, error) {
|
||||
req := types.SuspendVApp_Task{
|
||||
This: p.Reference(),
|
||||
}
|
||||
|
115
vendor/github.com/vmware/govmomi/object/virtual_device_list.go
generated
vendored
115
vendor/github.com/vmware/govmomi/object/virtual_device_list.go
generated
vendored
@@ -84,6 +84,9 @@ func (l VirtualDeviceList) Select(f func(device types.BaseVirtualDevice) bool) V
|
||||
// SelectByType returns a new list with devices that are equal to or extend the given type.
|
||||
func (l VirtualDeviceList) SelectByType(deviceType types.BaseVirtualDevice) VirtualDeviceList {
|
||||
dtype := reflect.TypeOf(deviceType)
|
||||
if dtype == nil {
|
||||
return nil
|
||||
}
|
||||
dname := dtype.Elem().Name()
|
||||
|
||||
return l.Select(func(device types.BaseVirtualDevice) bool {
|
||||
@@ -242,6 +245,7 @@ func (l VirtualDeviceList) CreateSCSIController(name string) (types.BaseVirtualD
|
||||
scsi := c.GetVirtualSCSIController()
|
||||
scsi.BusNumber = l.newSCSIBusNumber()
|
||||
scsi.Key = l.NewKey()
|
||||
scsi.ScsiCtlrUnitNumber = 7
|
||||
return c.(types.BaseVirtualDevice), nil
|
||||
}
|
||||
|
||||
@@ -270,6 +274,63 @@ func (l VirtualDeviceList) newSCSIBusNumber() int32 {
|
||||
return -1
|
||||
}
|
||||
|
||||
// FindNVMEController will find the named NVME controller if given, otherwise will pick an available controller.
|
||||
// An error is returned if the named controller is not found or not an NVME controller. Or, if name is not
|
||||
// given and no available controller can be found.
|
||||
func (l VirtualDeviceList) FindNVMEController(name string) (*types.VirtualNVMEController, error) {
|
||||
if name != "" {
|
||||
d := l.Find(name)
|
||||
if d == nil {
|
||||
return nil, fmt.Errorf("device '%s' not found", name)
|
||||
}
|
||||
if c, ok := d.(*types.VirtualNVMEController); ok {
|
||||
return c, nil
|
||||
}
|
||||
return nil, fmt.Errorf("%s is not an NVME controller", name)
|
||||
}
|
||||
|
||||
c := l.PickController((*types.VirtualNVMEController)(nil))
|
||||
if c == nil {
|
||||
return nil, errors.New("no available NVME controller")
|
||||
}
|
||||
|
||||
return c.(*types.VirtualNVMEController), nil
|
||||
}
|
||||
|
||||
// CreateNVMEController creates a new NVMWE controller.
|
||||
func (l VirtualDeviceList) CreateNVMEController() (types.BaseVirtualDevice, error) {
|
||||
nvme := &types.VirtualNVMEController{}
|
||||
nvme.BusNumber = l.newNVMEBusNumber()
|
||||
nvme.Key = l.NewKey()
|
||||
|
||||
return nvme, nil
|
||||
}
|
||||
|
||||
var nvmeBusNumbers = []int{0, 1, 2, 3}
|
||||
|
||||
// newNVMEBusNumber returns the bus number to use for adding a new NVME bus device.
|
||||
// -1 is returned if there are no bus numbers available.
|
||||
func (l VirtualDeviceList) newNVMEBusNumber() int32 {
|
||||
var used []int
|
||||
|
||||
for _, d := range l.SelectByType((*types.VirtualNVMEController)(nil)) {
|
||||
num := d.(types.BaseVirtualController).GetVirtualController().BusNumber
|
||||
if num >= 0 {
|
||||
used = append(used, int(num))
|
||||
} // else caller is creating a new vm using NVMEControllerTypes
|
||||
}
|
||||
|
||||
sort.Ints(used)
|
||||
|
||||
for i, n := range nvmeBusNumbers {
|
||||
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 {
|
||||
@@ -277,6 +338,8 @@ func (l VirtualDeviceList) FindDiskController(name string) (types.BaseVirtualCon
|
||||
return l.FindIDEController("")
|
||||
case name == "scsi" || name == "":
|
||||
return l.FindSCSIController("")
|
||||
case name == "nvme":
|
||||
return l.FindNVMEController("")
|
||||
default:
|
||||
if c, ok := l.Find(name).(types.BaseVirtualController); ok {
|
||||
return c, nil
|
||||
@@ -296,6 +359,8 @@ func (l VirtualDeviceList) PickController(kind types.BaseVirtualController) type
|
||||
return num < 15
|
||||
case *types.VirtualIDEController:
|
||||
return num < 2
|
||||
case *types.VirtualNVMEController:
|
||||
return num < 8
|
||||
default:
|
||||
return true
|
||||
}
|
||||
@@ -310,20 +375,31 @@ func (l VirtualDeviceList) PickController(kind types.BaseVirtualController) type
|
||||
|
||||
// newUnitNumber returns the unit number to use for attaching a new device to the given controller.
|
||||
func (l VirtualDeviceList) newUnitNumber(c types.BaseVirtualController) int32 {
|
||||
units := make([]bool, 30)
|
||||
|
||||
switch sc := c.(type) {
|
||||
case types.BaseVirtualSCSIController:
|
||||
// The SCSI controller sits on its own bus
|
||||
units[sc.GetVirtualSCSIController().ScsiCtlrUnitNumber] = true
|
||||
}
|
||||
|
||||
key := c.GetVirtualController().Key
|
||||
var max int32 = -1
|
||||
|
||||
for _, device := range l {
|
||||
d := device.GetVirtualDevice()
|
||||
|
||||
if d.ControllerKey == key {
|
||||
if d.UnitNumber != nil && *d.UnitNumber > max {
|
||||
max = *d.UnitNumber
|
||||
}
|
||||
if d.ControllerKey == key && d.UnitNumber != nil {
|
||||
units[int(*d.UnitNumber)] = true
|
||||
}
|
||||
}
|
||||
|
||||
return max + 1
|
||||
for unit, used := range units {
|
||||
if !used {
|
||||
return int32(unit)
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
// NewKey returns the key to use for adding a new device to the device list.
|
||||
@@ -384,12 +460,14 @@ func (l VirtualDeviceList) CreateDisk(c types.BaseVirtualController, ds types.Ma
|
||||
func (l VirtualDeviceList) ChildDisk(parent *types.VirtualDisk) *types.VirtualDisk {
|
||||
disk := *parent
|
||||
backing := disk.Backing.(*types.VirtualDiskFlatVer2BackingInfo)
|
||||
ds := strings.SplitN(backing.FileName[1:], "]", 2)
|
||||
p := new(DatastorePath)
|
||||
p.FromString(backing.FileName)
|
||||
p.Path = ""
|
||||
|
||||
// Use specified disk as parent backing to a new disk.
|
||||
disk.Backing = &types.VirtualDiskFlatVer2BackingInfo{
|
||||
VirtualDeviceFileBackingInfo: types.VirtualDeviceFileBackingInfo{
|
||||
FileName: fmt.Sprintf("[%s]", ds[0]),
|
||||
FileName: p.String(),
|
||||
Datastore: backing.Datastore,
|
||||
},
|
||||
Parent: backing,
|
||||
@@ -595,7 +673,17 @@ func (l VirtualDeviceList) CreateSerialPort() (*types.VirtualSerialPort, error)
|
||||
}
|
||||
|
||||
// ConnectSerialPort connects a serial port to a server or client uri.
|
||||
func (l VirtualDeviceList) ConnectSerialPort(device *types.VirtualSerialPort, uri string, client bool) *types.VirtualSerialPort {
|
||||
func (l VirtualDeviceList) ConnectSerialPort(device *types.VirtualSerialPort, uri string, client bool, proxyuri string) *types.VirtualSerialPort {
|
||||
if strings.HasPrefix(uri, "[") {
|
||||
device.Backing = &types.VirtualSerialPortFileBackingInfo{
|
||||
VirtualDeviceFileBackingInfo: types.VirtualDeviceFileBackingInfo{
|
||||
FileName: uri,
|
||||
},
|
||||
}
|
||||
|
||||
return device
|
||||
}
|
||||
|
||||
direction := types.VirtualDeviceURIBackingOptionDirectionServer
|
||||
if client {
|
||||
direction = types.VirtualDeviceURIBackingOptionDirectionClient
|
||||
@@ -605,6 +693,7 @@ func (l VirtualDeviceList) ConnectSerialPort(device *types.VirtualSerialPort, ur
|
||||
VirtualDeviceURIBackingInfo: types.VirtualDeviceURIBackingInfo{
|
||||
Direction: string(direction),
|
||||
ServiceURI: uri,
|
||||
ProxyURI: proxyuri,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -728,7 +817,11 @@ func (l VirtualDeviceList) SelectBootOrder(order []types.BaseVirtualMachineBootO
|
||||
|
||||
// TypeName returns the vmodl type name of the device
|
||||
func (l VirtualDeviceList) TypeName(device types.BaseVirtualDevice) string {
|
||||
return reflect.TypeOf(device).Elem().Name()
|
||||
dtype := reflect.TypeOf(device)
|
||||
if dtype == nil {
|
||||
return ""
|
||||
}
|
||||
return dtype.Elem().Name()
|
||||
}
|
||||
|
||||
var deviceNameRegexp = regexp.MustCompile(`(?:Virtual)?(?:Machine)?(\w+?)(?:Card|Device|Controller)?$`)
|
||||
@@ -754,6 +847,8 @@ func (l VirtualDeviceList) Type(device types.BaseVirtualDevice) string {
|
||||
return "pvscsi"
|
||||
case *types.VirtualLsiLogicSASController:
|
||||
return "lsilogic-sas"
|
||||
case *types.VirtualNVMEController:
|
||||
return "nvme"
|
||||
default:
|
||||
return l.deviceName(device)
|
||||
}
|
||||
|
3
vendor/github.com/vmware/govmomi/object/virtual_disk_manager.go
generated
vendored
3
vendor/github.com/vmware/govmomi/object/virtual_disk_manager.go
generated
vendored
@@ -17,10 +17,11 @@ 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"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
type VirtualDiskManager struct {
|
||||
|
212
vendor/github.com/vmware/govmomi/object/virtual_machine.go
generated
vendored
212
vendor/github.com/vmware/govmomi/object/virtual_machine.go
generated
vendored
@@ -17,15 +17,17 @@ limitations under the License.
|
||||
package object
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net"
|
||||
"path"
|
||||
|
||||
"github.com/vmware/govmomi/property"
|
||||
"github.com/vmware/govmomi/vim25"
|
||||
"github.com/vmware/govmomi/vim25/methods"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
"golang.org/x/net/context"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -227,9 +229,12 @@ func (v VirtualMachine) WaitForIP(ctx context.Context) (string, error) {
|
||||
|
||||
// WaitForNetIP waits for the VM guest.net property to report an IP address for all VM NICs.
|
||||
// Only consider IPv4 addresses if the v4 param is true.
|
||||
// By default, wait for all NICs to get an IP address, unless 1 or more device is given.
|
||||
// A device can be specified by the MAC address or the device name, e.g. "ethernet-0".
|
||||
// Returns a map with MAC address as the key and IP address list as the value.
|
||||
func (v VirtualMachine) WaitForNetIP(ctx context.Context, v4 bool) (map[string][]string, error) {
|
||||
func (v VirtualMachine) WaitForNetIP(ctx context.Context, v4 bool, device ...string) (map[string][]string, error) {
|
||||
macs := make(map[string][]string)
|
||||
eths := make(map[string]string)
|
||||
|
||||
p := property.DefaultCollector(v.c)
|
||||
|
||||
@@ -240,14 +245,15 @@ func (v VirtualMachine) WaitForNetIP(ctx context.Context, v4 bool) (map[string][
|
||||
continue
|
||||
}
|
||||
|
||||
devices := c.Val.(types.ArrayOfVirtualDevice).VirtualDevice
|
||||
for _, device := range devices {
|
||||
if nic, ok := device.(types.BaseVirtualEthernetCard); ok {
|
||||
devices := VirtualDeviceList(c.Val.(types.ArrayOfVirtualDevice).VirtualDevice)
|
||||
for _, d := range devices {
|
||||
if nic, ok := d.(types.BaseVirtualEthernetCard); ok {
|
||||
mac := nic.GetVirtualEthernetCard().MacAddress
|
||||
if mac == "" {
|
||||
return false
|
||||
}
|
||||
macs[mac] = nil
|
||||
eths[devices.Name(d)] = mac
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -255,6 +261,17 @@ func (v VirtualMachine) WaitForNetIP(ctx context.Context, v4 bool) (map[string][
|
||||
return true
|
||||
})
|
||||
|
||||
if len(device) != 0 {
|
||||
// Only wait for specific NIC(s)
|
||||
macs = make(map[string][]string)
|
||||
for _, mac := range device {
|
||||
if eth, ok := eths[mac]; ok {
|
||||
mac = eth // device name, e.g. "ethernet-0"
|
||||
}
|
||||
macs[mac] = nil
|
||||
}
|
||||
}
|
||||
|
||||
err = property.Wait(ctx, p, v.Reference(), []string{"guest.net"}, func(pc []types.PropertyChange) bool {
|
||||
for _, c := range pc {
|
||||
if c.Op != types.PropertyChangeOpAssign {
|
||||
@@ -300,18 +317,28 @@ func (v VirtualMachine) WaitForNetIP(ctx context.Context, v4 bool) (map[string][
|
||||
func (v VirtualMachine) Device(ctx context.Context) (VirtualDeviceList, error) {
|
||||
var o mo.VirtualMachine
|
||||
|
||||
err := v.Properties(ctx, v.Reference(), []string{"config.hardware.device"}, &o)
|
||||
err := v.Properties(ctx, v.Reference(), []string{"config.hardware.device", "summary.runtime.connectionState"}, &o)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Quoting the SDK doc:
|
||||
// The virtual machine configuration is not guaranteed to be available.
|
||||
// For example, the configuration information would be unavailable if the server
|
||||
// is unable to access the virtual machine files on disk, and is often also unavailable
|
||||
// during the initial phases of virtual machine creation.
|
||||
if o.Config == nil {
|
||||
return nil, fmt.Errorf("%s Config is not available, connectionState=%s",
|
||||
v.Reference(), o.Summary.Runtime.ConnectionState)
|
||||
}
|
||||
|
||||
return VirtualDeviceList(o.Config.Hardware.Device), nil
|
||||
}
|
||||
|
||||
func (v VirtualMachine) HostSystem(ctx context.Context) (*HostSystem, error) {
|
||||
var o mo.VirtualMachine
|
||||
|
||||
err := v.Properties(ctx, v.Reference(), []string{"summary"}, &o)
|
||||
err := v.Properties(ctx, v.Reference(), []string{"summary.runtime.host"}, &o)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -470,24 +497,102 @@ func (v VirtualMachine) RemoveAllSnapshot(ctx context.Context, consolidate *bool
|
||||
return NewTask(v.c, res.Returnval), nil
|
||||
}
|
||||
|
||||
// RevertToSnapshot reverts to a named snapshot
|
||||
func (v VirtualMachine) RevertToSnapshot(ctx context.Context, name string, suppressPowerOn bool) (*Task, error) {
|
||||
type snapshotMap map[string][]Reference
|
||||
|
||||
func (m snapshotMap) add(parent string, tree []types.VirtualMachineSnapshotTree) {
|
||||
for i, st := range tree {
|
||||
sname := st.Name
|
||||
names := []string{sname, st.Snapshot.Value}
|
||||
|
||||
if parent != "" {
|
||||
sname = path.Join(parent, sname)
|
||||
// Add full path as an option to resolve duplicate names
|
||||
names = append(names, sname)
|
||||
}
|
||||
|
||||
for _, name := range names {
|
||||
m[name] = append(m[name], &tree[i].Snapshot)
|
||||
}
|
||||
|
||||
m.add(sname, st.ChildSnapshotList)
|
||||
}
|
||||
}
|
||||
|
||||
// findSnapshot supports snapshot lookup by name, where name can be:
|
||||
// 1) snapshot ManagedObjectReference.Value (unique)
|
||||
// 2) snapshot name (may not be unique)
|
||||
// 3) snapshot tree path (may not be unique)
|
||||
func (v VirtualMachine) findSnapshot(ctx context.Context, name string) (Reference, error) {
|
||||
var o mo.VirtualMachine
|
||||
|
||||
err := v.Properties(ctx, v.Reference(), []string{"snapshot"}, &o)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
snapshotTree := o.Snapshot.RootSnapshotList
|
||||
if len(snapshotTree) < 1 {
|
||||
if o.Snapshot == nil || len(o.Snapshot.RootSnapshotList) == 0 {
|
||||
return nil, errors.New("No snapshots for this VM")
|
||||
}
|
||||
|
||||
snapshot, err := traverseSnapshotInTree(snapshotTree, name)
|
||||
m := make(snapshotMap)
|
||||
m.add("", o.Snapshot.RootSnapshotList)
|
||||
|
||||
s := m[name]
|
||||
switch len(s) {
|
||||
case 0:
|
||||
return nil, fmt.Errorf("snapshot %q not found", name)
|
||||
case 1:
|
||||
return s[0], nil
|
||||
default:
|
||||
return nil, fmt.Errorf("%q resolves to %d snapshots", name, len(s))
|
||||
}
|
||||
}
|
||||
|
||||
// RemoveSnapshot removes a named snapshot
|
||||
func (v VirtualMachine) RemoveSnapshot(ctx context.Context, name string, removeChildren bool, consolidate *bool) (*Task, error) {
|
||||
snapshot, err := v.findSnapshot(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req := types.RemoveSnapshot_Task{
|
||||
This: snapshot.Reference(),
|
||||
RemoveChildren: removeChildren,
|
||||
Consolidate: consolidate,
|
||||
}
|
||||
|
||||
res, err := methods.RemoveSnapshot_Task(ctx, v.c, &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewTask(v.c, res.Returnval), nil
|
||||
}
|
||||
|
||||
// RevertToCurrentSnapshot reverts to the current snapshot
|
||||
func (v VirtualMachine) RevertToCurrentSnapshot(ctx context.Context, suppressPowerOn bool) (*Task, error) {
|
||||
req := types.RevertToCurrentSnapshot_Task{
|
||||
This: v.Reference(),
|
||||
SuppressPowerOn: types.NewBool(suppressPowerOn),
|
||||
}
|
||||
|
||||
res, err := methods.RevertToCurrentSnapshot_Task(ctx, v.c, &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewTask(v.c, res.Returnval), nil
|
||||
}
|
||||
|
||||
// RevertToSnapshot reverts to a named snapshot
|
||||
func (v VirtualMachine) RevertToSnapshot(ctx context.Context, name string, suppressPowerOn bool) (*Task, error) {
|
||||
snapshot, err := v.findSnapshot(ctx, name)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req := types.RevertToSnapshot_Task{
|
||||
This: snapshot,
|
||||
This: snapshot.Reference(),
|
||||
SuppressPowerOn: types.NewBool(suppressPowerOn),
|
||||
}
|
||||
|
||||
@@ -499,32 +604,6 @@ func (v VirtualMachine) RevertToSnapshot(ctx context.Context, name string, suppr
|
||||
return NewTask(v.c, res.Returnval), nil
|
||||
}
|
||||
|
||||
// traverseSnapshotInTree is a recursive function that will traverse a snapshot tree to find a given snapshot
|
||||
func traverseSnapshotInTree(tree []types.VirtualMachineSnapshotTree, name string) (types.ManagedObjectReference, error) {
|
||||
var o types.ManagedObjectReference
|
||||
if tree == nil {
|
||||
return o, errors.New("Snapshot tree is empty")
|
||||
}
|
||||
for _, s := range tree {
|
||||
if s.Name == name {
|
||||
o = s.Snapshot
|
||||
break
|
||||
} else {
|
||||
childTree := s.ChildSnapshotList
|
||||
var err error
|
||||
o, err = traverseSnapshotInTree(childTree, name)
|
||||
if err != nil {
|
||||
return o, err
|
||||
}
|
||||
}
|
||||
}
|
||||
if o.Value == "" {
|
||||
return o, errors.New("Snapshot not found")
|
||||
}
|
||||
|
||||
return o, nil
|
||||
}
|
||||
|
||||
// IsToolsRunning returns true if VMware Tools is currently running in the guest OS, and false otherwise.
|
||||
func (v VirtualMachine) IsToolsRunning(ctx context.Context) (bool, error) {
|
||||
var o mo.VirtualMachine
|
||||
@@ -591,3 +670,58 @@ func (v VirtualMachine) MarkAsVirtualMachine(ctx context.Context, pool ResourceP
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v VirtualMachine) Migrate(ctx context.Context, pool *ResourcePool, host *HostSystem, priority types.VirtualMachineMovePriority, state types.VirtualMachinePowerState) (*Task, error) {
|
||||
req := types.MigrateVM_Task{
|
||||
This: v.Reference(),
|
||||
Priority: priority,
|
||||
State: state,
|
||||
}
|
||||
|
||||
if pool != nil {
|
||||
ref := pool.Reference()
|
||||
req.Pool = &ref
|
||||
}
|
||||
|
||||
if host != nil {
|
||||
ref := host.Reference()
|
||||
req.Host = &ref
|
||||
}
|
||||
|
||||
res, err := methods.MigrateVM_Task(ctx, v.c, &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewTask(v.c, res.Returnval), nil
|
||||
}
|
||||
|
||||
func (v VirtualMachine) Unregister(ctx context.Context) error {
|
||||
req := types.UnregisterVM{
|
||||
This: v.Reference(),
|
||||
}
|
||||
|
||||
_, err := methods.UnregisterVM(ctx, v.Client(), &req)
|
||||
return err
|
||||
}
|
||||
|
||||
// QueryEnvironmentBrowser is a helper to get the environmentBrowser property.
|
||||
func (v VirtualMachine) QueryConfigTarget(ctx context.Context) (*types.ConfigTarget, error) {
|
||||
var vm mo.VirtualMachine
|
||||
|
||||
err := v.Properties(ctx, v.Reference(), []string{"environmentBrowser"}, &vm)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
req := types.QueryConfigTarget{
|
||||
This: vm.EnvironmentBrowser,
|
||||
}
|
||||
|
||||
res, err := methods.QueryConfigTarget(ctx, v.Client(), &req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return res.Returnval, nil
|
||||
}
|
||||
|
Reference in New Issue
Block a user