github.com/netdata/go.d.plugin@v0.58.1/modules/vsphere/client/client.go (about)

     1  // SPDX-License-Identifier: GPL-3.0-or-later
     2  
     3  package client
     4  
     5  import (
     6  	"context"
     7  	"net/http"
     8  	"net/url"
     9  	"time"
    10  
    11  	"github.com/netdata/go.d.plugin/pkg/tlscfg"
    12  
    13  	"github.com/vmware/govmomi"
    14  	"github.com/vmware/govmomi/performance"
    15  	"github.com/vmware/govmomi/session"
    16  	"github.com/vmware/govmomi/view"
    17  	"github.com/vmware/govmomi/vim25"
    18  	"github.com/vmware/govmomi/vim25/mo"
    19  	"github.com/vmware/govmomi/vim25/soap"
    20  	"github.com/vmware/govmomi/vim25/types"
    21  )
    22  
    23  const (
    24  	datacenter      = "Datacenter"
    25  	folder          = "Folder"
    26  	computeResource = "ComputeResource"
    27  	hostSystem      = "HostSystem"
    28  	virtualMachine  = "VirtualMachine"
    29  
    30  	maxIdleConnections = 32
    31  )
    32  
    33  type Config struct {
    34  	URL      string
    35  	User     string
    36  	Password string
    37  	tlscfg.TLSConfig
    38  	Timeout time.Duration
    39  }
    40  
    41  type Client struct {
    42  	client *govmomi.Client
    43  	root   *view.ContainerView
    44  	perf   *performance.Manager
    45  }
    46  
    47  func newSoapClient(config Config) (*soap.Client, error) {
    48  	soapURL, err := soap.ParseURL(config.URL)
    49  	if err != nil || soapURL == nil {
    50  		return nil, err
    51  	}
    52  	soapURL.User = url.UserPassword(config.User, config.Password)
    53  	soapClient := soap.NewClient(soapURL, config.TLSConfig.InsecureSkipVerify)
    54  
    55  	tlsConfig, err := tlscfg.NewTLSConfig(config.TLSConfig)
    56  	if err != nil {
    57  		return nil, err
    58  	}
    59  	if tlsConfig != nil && len(tlsConfig.Certificates) > 0 {
    60  		soapClient.SetCertificate(tlsConfig.Certificates[0])
    61  	}
    62  	if config.TLSConfig.TLSCA != "" {
    63  		if err := soapClient.SetRootCAs(config.TLSConfig.TLSCA); err != nil {
    64  			return nil, err
    65  		}
    66  	}
    67  
    68  	if t, ok := soapClient.Transport.(*http.Transport); ok {
    69  		t.MaxIdleConnsPerHost = maxIdleConnections
    70  		t.TLSHandshakeTimeout = config.Timeout
    71  	}
    72  	soapClient.Timeout = config.Timeout
    73  
    74  	return soapClient, nil
    75  }
    76  
    77  func newContainerView(ctx context.Context, client *govmomi.Client) (*view.ContainerView, error) {
    78  	viewManager := view.NewManager(client.Client)
    79  	return viewManager.CreateContainerView(ctx, client.ServiceContent.RootFolder, []string{}, true)
    80  }
    81  
    82  func newPerformanceManager(client *vim25.Client) *performance.Manager {
    83  	perfManager := performance.NewManager(client)
    84  	perfManager.Sort = true
    85  	return perfManager
    86  }
    87  
    88  func New(config Config) (*Client, error) {
    89  	ctx := context.Background()
    90  	soapClient, err := newSoapClient(config)
    91  	if err != nil {
    92  		return nil, err
    93  	}
    94  
    95  	vimClient, err := vim25.NewClient(ctx, soapClient)
    96  	if err != nil {
    97  		return nil, err
    98  	}
    99  
   100  	vmomiClient := &govmomi.Client{
   101  		Client:         vimClient,
   102  		SessionManager: session.NewManager(vimClient),
   103  	}
   104  
   105  	userInfo := url.UserPassword(config.User, config.Password)
   106  	addKeepAlive(vmomiClient, userInfo)
   107  
   108  	err = vmomiClient.Login(ctx, userInfo)
   109  	if err != nil {
   110  		return nil, err
   111  	}
   112  
   113  	containerView, err := newContainerView(ctx, vmomiClient)
   114  	if err != nil {
   115  		return nil, err
   116  	}
   117  
   118  	perfManager := newPerformanceManager(vimClient)
   119  
   120  	client := &Client{
   121  		client: vmomiClient,
   122  		perf:   perfManager,
   123  		root:   containerView,
   124  	}
   125  
   126  	return client, nil
   127  }
   128  
   129  func (c *Client) IsSessionActive() (bool, error) {
   130  	return c.client.SessionManager.SessionIsActive(context.Background())
   131  }
   132  
   133  func (c *Client) Version() string {
   134  	return c.client.ServiceContent.About.Version
   135  }
   136  
   137  func (c *Client) Login(userinfo *url.Userinfo) error {
   138  	return c.client.Login(context.Background(), userinfo)
   139  }
   140  
   141  func (c *Client) Logout() error {
   142  	return c.client.Logout(context.Background())
   143  }
   144  
   145  func (c *Client) PerformanceMetrics(pqs []types.PerfQuerySpec) ([]performance.EntityMetric, error) {
   146  	metrics, err := c.perf.Query(context.Background(), pqs)
   147  	if err != nil {
   148  		return nil, err
   149  	}
   150  	return c.perf.ToMetricSeries(context.Background(), metrics)
   151  }
   152  
   153  func (c *Client) Datacenters(pathSet ...string) (dcs []mo.Datacenter, err error) {
   154  	err = c.root.Retrieve(context.Background(), []string{datacenter}, pathSet, &dcs)
   155  	return
   156  }
   157  
   158  func (c *Client) Folders(pathSet ...string) (folders []mo.Folder, err error) {
   159  	err = c.root.Retrieve(context.Background(), []string{folder}, pathSet, &folders)
   160  	return
   161  }
   162  
   163  func (c *Client) ComputeResources(pathSet ...string) (computes []mo.ComputeResource, err error) {
   164  	err = c.root.Retrieve(context.Background(), []string{computeResource}, pathSet, &computes)
   165  	return
   166  }
   167  
   168  func (c *Client) Hosts(pathSet ...string) (hosts []mo.HostSystem, err error) {
   169  	err = c.root.Retrieve(context.Background(), []string{hostSystem}, pathSet, &hosts)
   170  	return
   171  }
   172  
   173  func (c *Client) VirtualMachines(pathSet ...string) (vms []mo.VirtualMachine, err error) {
   174  	err = c.root.Retrieve(context.Background(), []string{virtualMachine}, pathSet, &vms)
   175  	return
   176  }
   177  
   178  func (c *Client) CounterInfoByName() (map[string]*types.PerfCounterInfo, error) {
   179  	return c.perf.CounterInfoByName(context.Background())
   180  }