github.com/vmware/govmomi@v0.51.0/vim25/client.go (about) 1 // © Broadcom. All Rights Reserved. 2 // The term “Broadcom” refers to Broadcom Inc. and/or its subsidiaries. 3 // SPDX-License-Identifier: Apache-2.0 4 5 package vim25 6 7 import ( 8 "context" 9 "encoding/json" 10 "strings" 11 12 "github.com/vmware/govmomi/vim25/methods" 13 "github.com/vmware/govmomi/vim25/soap" 14 "github.com/vmware/govmomi/vim25/types" 15 ) 16 17 const ( 18 Namespace = "vim25" 19 Version = "9.0.0.0" 20 Path = "/sdk" 21 ) 22 23 var ( 24 ServiceInstance = types.ManagedObjectReference{ 25 Type: "ServiceInstance", 26 Value: "ServiceInstance", 27 } 28 ) 29 30 // Client is a tiny wrapper around the vim25/soap Client that stores session 31 // specific state (i.e. state that only needs to be retrieved once after the 32 // client has been created). This means the client can be reused after 33 // serialization without performing additional requests for initialization. 34 type Client struct { 35 *soap.Client 36 37 ServiceContent types.ServiceContent 38 39 // RoundTripper is a separate field such that the client's implementation of 40 // the RoundTripper interface can be wrapped by separate implementations for 41 // extra functionality (for example, reauthentication on session timeout). 42 RoundTripper soap.RoundTripper 43 } 44 45 // NewClient creates and returns a new client with the ServiceContent field 46 // filled in. 47 func NewClient(ctx context.Context, rt soap.RoundTripper) (*Client, error) { 48 c := Client{ 49 RoundTripper: rt, 50 } 51 52 // Set client if it happens to be a soap.Client 53 if sc, ok := rt.(*soap.Client); ok { 54 c.Client = sc 55 56 if c.Namespace == "" { 57 c.Namespace = "urn:" + Namespace 58 } else if !strings.Contains(c.Namespace, ":") { 59 c.Namespace = "urn:" + c.Namespace // ensure valid URI format 60 } 61 if c.Version == "" { 62 c.Version = Version 63 } 64 } 65 66 var err error 67 c.ServiceContent, err = methods.GetServiceContent(ctx, rt) 68 if err != nil { 69 return nil, err 70 } 71 72 return &c, nil 73 } 74 75 // RoundTrip dispatches to the RoundTripper field. 76 func (c *Client) RoundTrip(ctx context.Context, req, res soap.HasFault) error { 77 return c.RoundTripper.RoundTrip(ctx, req, res) 78 } 79 80 type marshaledClient struct { 81 SoapClient *soap.Client 82 ServiceContent types.ServiceContent 83 } 84 85 func (c *Client) MarshalJSON() ([]byte, error) { 86 m := marshaledClient{ 87 SoapClient: c.Client, 88 ServiceContent: c.ServiceContent, 89 } 90 91 return json.Marshal(m) 92 } 93 94 func (c *Client) UnmarshalJSON(b []byte) error { 95 var m marshaledClient 96 97 err := json.Unmarshal(b, &m) 98 if err != nil { 99 return err 100 } 101 102 *c = Client{ 103 Client: m.SoapClient, 104 ServiceContent: m.ServiceContent, 105 RoundTripper: m.SoapClient, 106 } 107 108 return nil 109 } 110 111 // Valid returns whether or not the client is valid and ready for use. 112 // This should be called after unmarshalling the client. 113 func (c *Client) Valid() bool { 114 if c == nil { 115 return false 116 } 117 118 if c.Client == nil { 119 return false 120 } 121 122 // Use arbitrary pointer field in the service content. 123 // Doesn't matter which one, as long as it is populated by default. 124 if c.ServiceContent.SessionManager == nil { 125 return false 126 } 127 128 return true 129 } 130 131 // Path returns vim25.Path (see cache.Client) 132 func (c *Client) Path() string { 133 return Path 134 } 135 136 // IsVC returns true if we are connected to a vCenter 137 func (c *Client) IsVC() bool { 138 return c.ServiceContent.About.ApiType == "VirtualCenter" 139 }