vSphere Cloud Provider: update vmware/gomvomi godeps

This commit is contained in:
Doug MacEachern
2018-05-14 14:09:20 -07:00
parent 83768d286c
commit c340f6f9a4
55 changed files with 8733 additions and 596 deletions

View File

@@ -133,3 +133,28 @@ func (dc *Datacenter) PowerOnMultiVMTask(ctx *Context, req *types.PowerOnMultiVM
},
}
}
func (d *Datacenter) DestroyTask(req *types.Destroy_Task) soap.HasFault {
task := CreateTask(d, "destroy", func(t *Task) (types.AnyType, types.BaseMethodFault) {
folders := []types.ManagedObjectReference{
d.VmFolder,
d.HostFolder,
}
for _, ref := range folders {
if len(Map.Get(ref).(*Folder).ChildEntity) != 0 {
return nil, &types.ResourceInUse{}
}
}
Map.Get(*d.Parent).(*Folder).removeChild(d.Self)
return nil, nil
})
return &methods.Destroy_TaskBody{
Res: &types.Destroy_TaskResponse{
Returnval: task.Run(),
},
}
}

View File

@@ -63,6 +63,14 @@ func (s *DistributedVirtualSwitch) AddDVPortgroupTask(c *types.AddDVPortgroup_Ta
VmVnicNetworkResourcePoolKey: spec.VmVnicNetworkResourcePoolKey,
}
if pg.Config.DefaultPortConfig == nil {
pg.Config.DefaultPortConfig = &types.VMwareDVSPortSetting{
Vlan: new(types.VmwareDistributedVirtualSwitchVlanIdSpec),
}
}
pg.PortKeys = []string{}
s.Portgroup = append(s.Portgroup, pg.Self)
s.Summary.PortgroupName = append(s.Summary.PortgroupName, pg.Name)
@@ -111,10 +119,13 @@ func (s *DistributedVirtualSwitch) ReconfigureDvsTask(req *types.ReconfigureDvs_
Map.AddReference(pg, &pg.Host, member.Host)
}
case types.ConfigSpecOperationRemove:
if pg := FindReference(host.Network, s.Portgroup...); pg != nil {
return nil, &types.ResourceInUse{
Type: pg.Type,
Name: pg.Value,
for _, ref := range host.Vm {
vm := Map.Get(ref).(*VirtualMachine)
if pg := FindReference(vm.Network, s.Portgroup...); pg != nil {
return nil, &types.ResourceInUse{
Type: pg.Type,
Name: pg.Value,
}
}
}
@@ -170,10 +181,6 @@ func (s *DistributedVirtualSwitch) dvPortgroups(_ *types.DistributedVirtualSwitc
},
})
if pg.PortKeys == nil {
continue
}
for _, key := range pg.PortKeys {
res = append(res, types.DistributedVirtualPort{
DvsUuid: s.Uuid,

View File

@@ -63,17 +63,14 @@ func NewEventManager(ref types.ManagedObjectReference) object.Reference {
}
}
func (m *EventManager) CreateCollectorForEvents(ctx *Context, req *types.CreateCollectorForEvents) soap.HasFault {
body := new(methods.CreateCollectorForEventsBody)
func (m *EventManager) createCollector(ctx *Context, req *types.CreateCollectorForEvents) (*EventHistoryCollector, *soap.Fault) {
size, err := validatePageSize(req.Filter.MaxCount)
if err != nil {
body.Fault_ = err
return body
return nil, err
}
if len(m.collectors) >= int(m.MaxCollector) {
body.Fault_ = Fault("Too many event collectors to create", new(types.InvalidState))
return body
return nil, Fault("Too many event collectors to create", new(types.InvalidState))
}
collector := &EventHistoryCollector{
@@ -83,6 +80,17 @@ func (m *EventManager) CreateCollectorForEvents(ctx *Context, req *types.CreateC
collector.Filter = req.Filter
collector.fillPage(size)
return collector, nil
}
func (m *EventManager) CreateCollectorForEvents(ctx *Context, req *types.CreateCollectorForEvents) soap.HasFault {
body := new(methods.CreateCollectorForEventsBody)
collector, err := m.createCollector(ctx, req)
if err != nil {
body.Fault_ = err
return body
}
ref := ctx.Session.Put(collector).Reference()
m.collectors[ref] = collector
@@ -93,6 +101,27 @@ func (m *EventManager) CreateCollectorForEvents(ctx *Context, req *types.CreateC
return body
}
func (m *EventManager) QueryEvents(ctx *Context, req *types.QueryEvents) soap.HasFault {
if Map.IsESX() {
return &methods.QueryEventsBody{
Fault_: Fault("", new(types.NotImplemented)),
}
}
body := new(methods.QueryEventsBody)
collector, err := m.createCollector(ctx, &types.CreateCollectorForEvents{Filter: req.Filter})
if err != nil {
body.Fault_ = err
return body
}
body.Res = &types.QueryEventsResponse{
Returnval: collector.GetLatestPage(),
}
return body
}
// formatMessage applies the EventDescriptionEventDetail.FullFormat template to the given event's FullFormattedMessage field.
func (m *EventManager) formatMessage(event types.BaseEvent) {
id := reflect.ValueOf(event).Elem().Type().Name()
@@ -372,15 +401,23 @@ func (c *EventHistoryCollector) DestroyCollector(ctx *Context, req *types.Destro
}
}
func (c *EventHistoryCollector) Get() mo.Reference {
clone := *c
func (c *EventHistoryCollector) GetLatestPage() []types.BaseEvent {
var latestPage []types.BaseEvent
c.page.Do(func(val interface{}) {
if val == nil {
return
}
clone.LatestPage = append(clone.LatestPage, val.(types.BaseEvent))
latestPage = append(latestPage, val.(types.BaseEvent))
})
return latestPage
}
func (c *EventHistoryCollector) Get() mo.Reference {
clone := *c
clone.LatestPage = clone.GetLatestPage()
return &clone
}

View File

@@ -20,6 +20,7 @@ import (
"fmt"
"math/rand"
"path"
"strings"
"github.com/google/uuid"
@@ -514,6 +515,17 @@ func (f *Folder) CreateDVSTask(req *types.CreateDVS_Task) soap.HasFault {
}
}
dvs.AddDVPortgroupTask(&types.AddDVPortgroup_Task{
Spec: []types.DVPortgroupConfigSpec{{
Name: dvs.Name + "-DVUplinks" + strings.TrimPrefix(dvs.Self.Value, "dvs"),
DefaultPortConfig: &types.VMwareDVSPortSetting{
Vlan: &types.VmwareDistributedVirtualSwitchTrunkVlanSpec{
VlanId: []types.NumericRange{{Start: 0, End: 4094}},
},
},
}},
})
return dvs.Reference(), nil
})
@@ -527,3 +539,45 @@ func (f *Folder) CreateDVSTask(req *types.CreateDVS_Task) soap.HasFault {
func (f *Folder) RenameTask(r *types.Rename_Task) soap.HasFault {
return RenameTask(f, r)
}
func (f *Folder) DestroyTask(req *types.Destroy_Task) soap.HasFault {
type destroyer interface {
mo.Reference
DestroyTask(*types.Destroy_Task) soap.HasFault
}
task := CreateTask(f, "destroy", func(*Task) (types.AnyType, types.BaseMethodFault) {
// Attempt to destroy all children
for _, c := range f.ChildEntity {
obj, ok := Map.Get(c).(destroyer)
if !ok {
continue
}
var fault types.BaseMethodFault
Map.WithLock(obj, func() {
id := obj.DestroyTask(&types.Destroy_Task{
This: c,
}).(*methods.Destroy_TaskBody).Res.Returnval
t := Map.Get(id).(*Task)
if t.Info.Error != nil {
fault = t.Info.Error.Fault // For example, can't destroy a powered on VM
}
})
if fault != nil {
return nil, fault
}
}
// Remove the folder itself
Map.Get(*f.Parent).(*Folder).removeChild(f.Self)
return nil, nil
})
return &methods.Destroy_TaskBody{
Res: &types.Destroy_TaskResponse{
Returnval: task.Run(),
},
}
}

View File

@@ -173,6 +173,25 @@ func CreateStandaloneHost(f *Folder, spec types.HostConnectSpec) (*HostSystem, t
return host, nil
}
func (h *HostSystem) DestroyTask(req *types.Destroy_Task) soap.HasFault {
task := CreateTask(h, "destroy", func(t *Task) (types.AnyType, types.BaseMethodFault) {
if len(h.Vm) > 0 {
return nil, &types.ResourceInUse{}
}
f := Map.getEntityParent(h, "Folder").(*Folder)
f.removeChild(h.Reference())
return nil, nil
})
return &methods.Destroy_TaskBody{
Res: &types.Destroy_TaskResponse{
Returnval: task.Run(),
},
}
}
func (h *HostSystem) EnterMaintenanceModeTask(spec *types.EnterMaintenanceMode_Task) soap.HasFault {
task := CreateTask(h, "enterMaintenanceMode", func(t *Task) (types.AnyType, types.BaseMethodFault) {
h.Runtime.InMaintenanceMode = true

View File

@@ -111,17 +111,29 @@ func fieldValueInterface(f reflect.StructField, rval reflect.Value) interface{}
pval = &types.ArrayOfString{
String: v,
}
case []uint8:
pval = &types.ArrayOfByte{
Byte: v,
}
case []int16:
pval = &types.ArrayOfShort{
Short: v,
}
case []int32:
pval = &types.ArrayOfInt{
Int: v,
}
case []int64:
pval = &types.ArrayOfLong{
Long: v,
}
default:
kind := f.Type.Elem().Name()
// Remove govmomi interface prefix name
if strings.HasPrefix(kind, "Base") {
kind = kind[4:]
}
akind, _ := typeFunc("ArrayOf" + kind)
akind, _ := defaultMapType("ArrayOf" + kind)
a := reflect.New(akind)
a.Elem().FieldByName(kind).Set(rval)
pval = a.Interface()
@@ -278,14 +290,10 @@ func (rr *retrieveResult) collectFields(ctx *Context, rval reflect.Value, fields
seen[name] = true
val, err := fieldValue(rval, name)
if err == nil {
rr.add(ctx, name, val, content)
continue
}
switch err {
case errEmptyField:
// ok
case nil, errEmptyField:
rr.add(ctx, name, val, content)
case errMissingField:
content.MissingSet = append(content.MissingSet, types.MissingProperty{
Path: name,
@@ -469,6 +477,19 @@ func (pc *PropertyCollector) RetrievePropertiesEx(ctx *Context, r *types.Retriev
if fault != nil {
body.Fault_ = Fault("", fault)
} else {
objects := res.Objects[:0]
for _, o := range res.Objects {
propSet := o.PropSet[:0]
for _, p := range o.PropSet {
if p.Val != nil {
propSet = append(propSet, p)
}
}
o.PropSet = propSet
objects = append(objects, o)
}
res.Objects = objects
body.Res = &types.RetrievePropertiesExResponse{
Returnval: res,
}

View File

@@ -24,7 +24,7 @@ import (
"strings"
"sync"
"github.com/vmware/govmomi/vim25/methods"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
)
@@ -40,6 +40,7 @@ var refValueMap = map[string]string{
"VirtualMachine": "vm",
"VirtualMachineSnapshot": "snapshot",
"VmwareDistributedVirtualSwitch": "dvs",
"DistributedVirtualSwitch": "dvs",
}
// Map is the default Registry instance.
@@ -59,6 +60,9 @@ type Registry struct {
handlers map[types.ManagedObjectReference]RegisterObject
locks map[types.ManagedObjectReference]sync.Locker
counter int
Namespace string
Path string
}
// NewRegistry creates a new instances of Registry
@@ -67,11 +71,23 @@ func NewRegistry() *Registry {
objects: make(map[types.ManagedObjectReference]mo.Reference),
handlers: make(map[types.ManagedObjectReference]RegisterObject),
locks: make(map[types.ManagedObjectReference]sync.Locker),
Namespace: vim25.Namespace,
Path: vim25.Path,
}
return r
}
func (r *Registry) typeFunc(name string) (reflect.Type, bool) {
if r.Namespace != "" && r.Namespace != vim25.Namespace {
if kind, ok := defaultMapType(r.Namespace + ":" + name); ok {
return kind, ok
}
}
return defaultMapType(name)
}
// typeName returns the type of the given object.
func typeName(item mo.Reference) string {
return reflect.TypeOf(item).Elem().Name()
@@ -332,7 +348,7 @@ func (r *Registry) removeString(obj mo.Reference, field *[]string, val string) {
}
func (r *Registry) content() types.ServiceContent {
return r.Get(methods.ServiceInstance).(*ServiceInstance).Content
return r.Get(vim25.ServiceInstance).(*ServiceInstance).Content
}
// IsESX returns true if this Registry maps an ESX model
@@ -380,6 +396,11 @@ func (r *Registry) SessionManager() *SessionManager {
return r.Get(r.content().SessionManager.Reference()).(*SessionManager)
}
// OptionManager returns the OptionManager singleton
func (r *Registry) OptionManager() *OptionManager {
return r.Get(r.content().Setting.Reference()).(*OptionManager)
}
func (r *Registry) MarshalJSON() ([]byte, error) {
r.m.Lock()
defer r.m.Unlock()

View File

@@ -19,8 +19,10 @@ package simulator
import (
"time"
"github.com/google/uuid"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/simulator/vpx"
"github.com/vmware/govmomi/vim25"
"github.com/vmware/govmomi/vim25/methods"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/soap"
@@ -36,7 +38,7 @@ func NewServiceInstance(content types.ServiceContent, folder mo.Folder) *Service
s := &ServiceInstance{}
s.Self = methods.ServiceInstance
s.Self = vim25.ServiceInstance
s.Content = content
Map.Put(s)
@@ -49,6 +51,7 @@ func NewServiceInstance(content types.ServiceContent, folder mo.Folder) *Service
if content.About.ApiType == "HostAgent" {
CreateDefaultESX(f)
} else {
content.About.InstanceUuid = uuid.New().String()
setting = vpx.Setting
}

View File

@@ -49,33 +49,85 @@ func NewSessionManager(ref types.ManagedObjectReference) object.Reference {
return s
}
func (s *SessionManager) Login(ctx *Context, login *types.Login) soap.HasFault {
body := &methods.LoginBody{}
func createSession(ctx *Context, name string, locale string) types.UserSession {
now := time.Now().UTC()
if login.Locale == "" {
login.Locale = session.Locale
if locale == "" {
locale = session.Locale
}
if login.UserName == "" || login.Password == "" || ctx.Session != nil {
session := Session{
UserSession: types.UserSession{
Key: uuid.New().String(),
UserName: name,
FullName: name,
LoginTime: now,
LastActiveTime: now,
Locale: locale,
MessageLocale: locale,
},
Registry: NewRegistry(),
}
ctx.SetSession(session, true)
return session.UserSession
}
func (s *SessionManager) Login(ctx *Context, req *types.Login) soap.HasFault {
body := new(methods.LoginBody)
if req.UserName == "" || req.Password == "" || ctx.Session != nil {
body.Fault_ = invalidLogin
} else {
session := Session{
UserSession: types.UserSession{
Key: uuid.New().String(),
UserName: login.UserName,
FullName: login.UserName,
LoginTime: time.Now(),
LastActiveTime: time.Now(),
Locale: login.Locale,
MessageLocale: login.Locale,
},
Registry: NewRegistry(),
body.Res = &types.LoginResponse{
Returnval: createSession(ctx, req.UserName, req.Locale),
}
}
return body
}
func (s *SessionManager) LoginExtensionByCertificate(ctx *Context, req *types.LoginExtensionByCertificate) soap.HasFault {
body := new(methods.LoginExtensionByCertificateBody)
if ctx.req.TLS == nil || len(ctx.req.TLS.PeerCertificates) == 0 {
body.Fault_ = Fault("", new(types.NoClientCertificate))
return body
}
if req.ExtensionKey == "" || ctx.Session != nil {
body.Fault_ = invalidLogin
} else {
body.Res = &types.LoginExtensionByCertificateResponse{
Returnval: createSession(ctx, req.ExtensionKey, req.Locale),
}
}
return body
}
func (s *SessionManager) LoginByToken(ctx *Context, req *types.LoginByToken) soap.HasFault {
body := new(methods.LoginByTokenBody)
if ctx.Session != nil {
body.Fault_ = invalidLogin
} else {
var subject struct {
ID string `xml:"Assertion>Subject>NameID"`
}
ctx.SetSession(session, true)
if s, ok := ctx.Header.Security.(*Element); ok {
_ = s.Decode(&subject)
}
body.Res = &types.LoginResponse{
Returnval: session.UserSession,
if subject.ID == "" {
body.Fault_ = invalidLogin
return body
}
body.Res = &types.LoginByTokenResponse{
Returnval: createSession(ctx, subject.ID, req.Locale),
}
}
@@ -163,6 +215,7 @@ var internalContext = &Context{
},
Registry: NewRegistry(),
},
Map: Map,
}
var invalidLogin = Fault("Login failure", new(types.InvalidLogin))
@@ -175,7 +228,9 @@ type Context struct {
context.Context
Session *Session
Header soap.Header
Caller *types.ManagedObjectReference
Map *Registry
}
// mapSession maps an HTTP cookie to a Session.

View File

@@ -21,6 +21,7 @@ import (
"context"
"crypto/tls"
"crypto/x509"
"encoding/base64"
"encoding/json"
"encoding/pem"
"flag"
@@ -28,6 +29,7 @@ import (
"io"
"io/ioutil"
"log"
"net"
"net/http"
"net/http/httptest"
"net/url"
@@ -35,6 +37,7 @@ import (
"path"
"reflect"
"sort"
"strconv"
"strings"
"github.com/vmware/govmomi/find"
@@ -51,15 +54,17 @@ var Trace = false
// Method encapsulates a decoded SOAP client request
type Method struct {
Name string
This types.ManagedObjectReference
Body types.AnyType
Name string
This types.ManagedObjectReference
Header soap.Header
Body types.AnyType
}
// Service decodes incoming requests and dispatches to a Handler
type Service struct {
client *vim25.Client
sm *SessionManager
sdk map[string]*Registry
readAll func(io.Reader) ([]byte, error)
@@ -70,7 +75,8 @@ type Service struct {
// Server provides a simulator Service over HTTP
type Server struct {
*httptest.Server
URL *url.URL
URL *url.URL
Tunnel int
caFile string
}
@@ -80,6 +86,7 @@ func New(instance *ServiceInstance) *Service {
s := &Service{
readAll: ioutil.ReadAll,
sm: Map.SessionManager(),
sdk: make(map[string]*Registry),
}
s.client, _ = vim25.NewClient(context.Background(), s)
@@ -110,12 +117,12 @@ func Fault(msg string, fault types.BaseMethodFault) *soap.Fault {
}
func (s *Service) call(ctx *Context, method *Method) soap.HasFault {
handler := Map.Get(method.This)
handler := ctx.Map.Get(method.This)
session := ctx.Session
if session == nil {
switch method.Name {
case "RetrieveServiceContent", "Login", "RetrieveProperties", "RetrievePropertiesEx", "CloneSession":
case "RetrieveServiceContent", "List", "Login", "LoginByToken", "LoginExtensionByCertificate", "RetrieveProperties", "RetrievePropertiesEx", "CloneSession":
// ok for now, TODO: authz
default:
fault := &types.NotAuthenticated{
@@ -170,7 +177,7 @@ func (s *Service) call(ctx *Context, method *Method) soap.HasFault {
args = append(args, reflect.ValueOf(ctx))
}
args = append(args, reflect.ValueOf(method.Body))
Map.WithLock(handler, func() {
ctx.Map.WithLock(handler, func() {
res = m.Call(args)
})
@@ -197,6 +204,7 @@ func (s *Service) RoundTrip(ctx context.Context, request, response soap.HasFault
}
res := s.call(&Context{
Map: Map,
Context: ctx,
Session: internalContext.Session,
}, method)
@@ -281,6 +289,16 @@ func (s *Service) About(w http.ResponseWriter, r *http.Request) {
_ = enc.Encode(&about)
}
// RegisterSDK adds an HTTP handler for the Registry's Path and Namespace.
func (s *Service) RegisterSDK(r *Registry) {
if s.ServeMux == nil {
s.ServeMux = http.NewServeMux()
}
s.sdk[r.Path] = r
s.ServeMux.HandleFunc(r.Path, s.ServeSDK)
}
// ServeSDK implements the http.Handler interface
func (s *Service) ServeSDK(w http.ResponseWriter, r *http.Request) {
if r.Method != "POST" {
@@ -305,17 +323,19 @@ func (s *Service) ServeSDK(w http.ResponseWriter, r *http.Request) {
res: w,
m: s.sm,
Map: s.sdk[r.URL.Path],
Context: context.Background(),
}
Map.WithLock(s.sm, ctx.mapSession)
ctx.Map.WithLock(s.sm, ctx.mapSession)
var res soap.HasFault
var soapBody interface{}
method, err := UnmarshalBody(body)
method, err := UnmarshalBody(ctx.Map.typeFunc, body)
if err != nil {
res = serverFault(err.Error())
} else {
ctx.Header = method.Header
res = s.call(ctx, method)
}
@@ -447,15 +467,10 @@ func (*Service) ServiceVersions(w http.ResponseWriter, r *http.Request) {
// NewServer returns an http Server instance for the given service
func (s *Service) NewServer() *Server {
s.RegisterSDK(Map)
mux := s.ServeMux
if mux == nil {
mux = http.NewServeMux()
}
path := "/sdk"
mux.HandleFunc(path, s.ServeSDK)
mux.HandleFunc(path+"/vimServiceVersions.xml", s.ServiceVersions)
mux.HandleFunc(Map.Path+"/vimServiceVersions.xml", s.ServiceVersions)
mux.HandleFunc(folderPrefix, s.ServeDatastore)
mux.HandleFunc("/about", s.About)
@@ -466,7 +481,7 @@ func (s *Service) NewServer() *Server {
u := &url.URL{
Scheme: "http",
Host: ts.Listener.Addr().String(),
Path: path,
Path: Map.Path,
User: url.UserPassword("user", "pass"),
}
@@ -478,14 +493,31 @@ func (s *Service) NewServer() *Server {
_ = f.Value.Set("")
}
cert := ""
if s.TLS == nil {
ts.Start()
} else {
ts.TLS = s.TLS
ts.TLS.ClientAuth = tls.RequestClientCert // Used by SessionManager.LoginExtensionByCertificate
ts.StartTLS()
u.Scheme += "s"
cert = base64.StdEncoding.EncodeToString(ts.TLS.Certificates[0].Certificate[0])
}
// Add vcsim config to OptionManager for use by SDK handlers (see lookup/simulator for example)
m := Map.OptionManager()
m.Setting = append(m.Setting,
&types.OptionValue{
Key: "vcsim.server.url",
Value: ts.URL,
},
&types.OptionValue{
Key: "vcsim.server.cert",
Value: cert,
},
)
return &Server{
Server: ts,
URL: u,
@@ -525,6 +557,60 @@ func (s *Server) CertificateFile() (string, error) {
return s.caFile, pem.Encode(f, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})
}
// proxy tunnels SDK requests
func (s *Server) proxy(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodConnect {
http.Error(w, "", http.StatusMethodNotAllowed)
return
}
dst, err := net.Dial("tcp", s.URL.Host)
if err != nil {
http.Error(w, err.Error(), http.StatusBadGateway)
return
}
w.WriteHeader(http.StatusOK)
src, _, err := w.(http.Hijacker).Hijack()
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
go io.Copy(src, dst)
go func() {
_, _ = io.Copy(dst, src)
_ = dst.Close()
_ = src.Close()
}()
}
// StartTunnel runs an HTTP proxy for tunneling SDK requests that require TLS client certificate authentication.
func (s *Server) StartTunnel() error {
tunnel := &http.Server{
Addr: fmt.Sprintf("%s:%d", s.URL.Hostname(), s.Tunnel),
Handler: http.HandlerFunc(s.proxy),
}
l, err := net.Listen("tcp", tunnel.Addr)
if err != nil {
return err
}
if s.Tunnel == 0 {
s.Tunnel = l.Addr().(*net.TCPAddr).Port
}
// Set client proxy port (defaults to vCenter host port 80 in real life)
q := s.URL.Query()
q.Set("GOVMOMI_TUNNEL_PROXY_PORT", strconv.Itoa(s.Tunnel))
s.URL.RawQuery = q.Encode()
go tunnel.Serve(l)
return nil
}
// Close shuts down the server and blocks until all outstanding
// requests on this server have completed.
func (s *Server) Close() {
@@ -536,7 +622,6 @@ func (s *Server) Close() {
var (
vim25MapType = types.TypeFunc()
typeFunc = defaultMapType
)
func defaultMapType(name string) (reflect.Type, bool) {
@@ -552,14 +637,39 @@ func defaultMapType(name string) (reflect.Type, bool) {
return typ, ok
}
// UnmarshalBody extracts the Body from a soap.Envelope and unmarshals to the corresponding govmomi type
func UnmarshalBody(data []byte) (*Method, error) {
body := struct {
// Element can be used to defer decoding of an XML node.
type Element struct {
start xml.StartElement
inner struct {
Content string `xml:",innerxml"`
}{}
}
typeFunc func(string) (reflect.Type, bool)
}
func (e *Element) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
e.start = start
return d.DecodeElement(&e.inner, &start)
}
func (e *Element) decoder() *xml.Decoder {
decoder := xml.NewDecoder(strings.NewReader(e.inner.Content))
decoder.TypeFunc = e.typeFunc // required to decode interface types
return decoder
}
func (e *Element) Decode(val interface{}) error {
return e.decoder().DecodeElement(val, &e.start)
}
// UnmarshalBody extracts the Body from a soap.Envelope and unmarshals to the corresponding govmomi type
func UnmarshalBody(typeFunc func(string) (reflect.Type, bool), data []byte) (*Method, error) {
body := &Element{typeFunc: typeFunc}
req := soap.Envelope{
Body: &body,
Header: &soap.Header{
Security: new(Element),
},
Body: body,
}
err := xml.Unmarshal(data, &req)
@@ -567,40 +677,38 @@ func UnmarshalBody(data []byte) (*Method, error) {
return nil, fmt.Errorf("xml.Unmarshal: %s", err)
}
decoder := xml.NewDecoder(bytes.NewReader([]byte(body.Content)))
decoder.TypeFunc = typeFunc // required to decode interface types
var start *xml.StartElement
var start xml.StartElement
var ok bool
decoder := body.decoder()
for {
tok, derr := decoder.Token()
if derr != nil {
return nil, fmt.Errorf("decoding body: %s", err)
return nil, fmt.Errorf("decoding: %s", derr)
}
if t, ok := tok.(xml.StartElement); ok {
start = &t
if start, ok = tok.(xml.StartElement); ok {
break
}
}
kind := start.Name.Local
if !ok {
return nil, fmt.Errorf("decoding: method token not found")
}
kind := start.Name.Local
rtype, ok := typeFunc(kind)
if !ok {
return nil, fmt.Errorf("no vmomi type defined for '%s'", kind)
}
var val interface{}
if rtype != nil {
val = reflect.New(rtype).Interface()
}
val := reflect.New(rtype).Interface()
err = decoder.DecodeElement(val, start)
err = decoder.DecodeElement(val, &start)
if err != nil {
return nil, fmt.Errorf("decoding %s: %s", kind, err)
}
method := &Method{Name: kind, Body: val}
method := &Method{Name: kind, Header: *req.Header, Body: val}
field := reflect.ValueOf(val).Elem().FieldByName("This")

View File

@@ -39,6 +39,10 @@ func (v *VirtualMachineSnapshot) RemoveSnapshotTask(req *types.RemoveSnapshot_Ta
}
vm.Snapshot.RootSnapshotList = removeSnapshotInTree(vm.Snapshot.RootSnapshotList, req.This, req.RemoveChildren)
if len(vm.Snapshot.RootSnapshotList) == 0 {
vm.Snapshot = nil
}
})
return nil, nil

View File

@@ -17,11 +17,13 @@ limitations under the License.
package simulator
import (
"bytes"
"fmt"
"log"
"net"
"os"
"path"
"strconv"
"strings"
"sync/atomic"
"time"
@@ -63,7 +65,7 @@ func NewVirtualMachine(parent types.ManagedObjectReference, spec *types.VirtualM
MemoryAllocation: &rspec.MemoryAllocation,
CpuAllocation: &rspec.CpuAllocation,
}
vm.Snapshot = &types.VirtualMachineSnapshotInfo{}
vm.Snapshot = nil // intentionally set to nil until a snapshot is created
vm.Storage = &types.VirtualMachineStorageInfo{
Timestamp: time.Now(),
}
@@ -420,6 +422,28 @@ func (vm *VirtualMachine) generateMAC() string {
return mac.String()
}
func numberToString(n int64, sep rune) string {
buf := &bytes.Buffer{}
if n < 0 {
n = -n
buf.WriteRune('-')
}
s := strconv.FormatInt(n, 10)
pos := 3 - (len(s) % 3)
for i := 0; i < len(s); i++ {
if pos == 3 {
if i != 0 {
buf.WriteRune(sep)
}
pos = 0
}
pos++
buf.WriteByte(s[i])
}
return buf.String()
}
func (vm *VirtualMachine) configureDevice(devices object.VirtualDeviceList, spec *types.VirtualDeviceConfigSpec) types.BaseMethodFault {
device := spec.Device
d := device.GetVirtualDevice()
@@ -469,6 +493,7 @@ func (vm *VirtualMachine) configureDevice(devices object.VirtualDeviceList, spec
c.MacAddress = vm.generateMAC()
}
case *types.VirtualDisk:
summary = fmt.Sprintf("%s KB", numberToString(x.CapacityInKB, ','))
switch b := d.Backing.(type) {
case types.BaseVirtualDeviceFileBackingInfo:
info := b.GetVirtualDeviceFileBackingInfo()
@@ -991,8 +1016,7 @@ func (vm *VirtualMachine) RemoveAllSnapshotsTask(req *types.RemoveAllSnapshots_T
refs := allSnapshotsInTree(vm.Snapshot.RootSnapshotList)
vm.Snapshot.CurrentSnapshot = nil
vm.Snapshot.RootSnapshotList = nil
vm.Snapshot = nil
for _, ref := range refs {
Map.Remove(ref)

View File

@@ -57,6 +57,10 @@ var Setting = []types.BaseOptionValue{
Key: "config.vpxd.sso.admin.uri",
Value: "https://127.0.0.1/sso-adminserver/sdk/vsphere.local",
},
&types.OptionValue{
Key: "VirtualCenter.InstanceName",
Value: "127.0.0.1",
},
&types.OptionValue{
Key: "event.batchsize",
Value: int32(2000),