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  }