github.com/vmware/govmomi@v0.37.2/vim25/client.go (about)

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