github.com/vmware/govmomi@v0.37.2/vapi/namespace/namespace.go (about)

     1  /*
     2  Copyright (c) 2020-2022 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 namespace
    18  
    19  import (
    20  	"bytes"
    21  	"context"
    22  	"encoding/json"
    23  	"fmt"
    24  	"net/http"
    25  	"os"
    26  	"path"
    27  
    28  	"github.com/vmware/govmomi/vapi/namespace/internal"
    29  	"github.com/vmware/govmomi/vapi/rest"
    30  	"github.com/vmware/govmomi/vim25/types"
    31  )
    32  
    33  // Manager extends rest.Client, adding namespace related methods.
    34  type Manager struct {
    35  	*rest.Client
    36  }
    37  
    38  // NewManager creates a new Manager instance with the given client.
    39  func NewManager(client *rest.Client) *Manager {
    40  	return &Manager{
    41  		Client: client,
    42  	}
    43  }
    44  
    45  // EnableClusterSpec defines a Tanzu Supervisor Cluster for creation.
    46  // See: https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/Clusters/EnableSpec/
    47  // Since 7.0.0:-
    48  type EnableClusterSpec struct {
    49  	MasterDNSSearchDomains []string               `json:"master_DNS_search_domains,omitempty"`
    50  	ImageStorage           ImageStorageSpec       `json:"image_storage"`
    51  	NcpClusterNetworkSpec  *NcpClusterNetworkSpec `json:"ncp_cluster_network_spec,omitempty"`
    52  	// Note: NcpClusterNetworkSpec is replaced by WorkloadNetworksSpec in vSphere 7.0u2+
    53  	// Since 7.0u1:-
    54  	WorkloadNetworksSpec    *WorkloadNetworksEnableSpec `json:"workload_networks_spec,omitempty"`
    55  	MasterManagementNetwork *MasterManagementNetwork    `json:"master_management_network"`
    56  	MasterDNSNames          []string                    `json:"Master_DNS_names,omitempty"`
    57  	MasterNTPServers        []string                    `json:"master_NTP_servers,omitempty"`
    58  	EphemeralStoragePolicy  string                      `json:"ephemeral_storage_policy,omitempty"`
    59  	DefaultImageRepository  string                      `json:"default_image_repository,omitempty"`
    60  	ServiceCidr             *Cidr                       `json:"service_cidr"`
    61  	LoginBanner             string                      `json:"login_banner,omitempty"`
    62  	// Was string until #2860:-
    63  	SizeHint             *SizingHint           `json:"size_hint"`
    64  	WorkerDNS            []string              `json:"worker_DNS,omitempty"`
    65  	DefaultImageRegistry *DefaultImageRegistry `json:"default_image_registry,omitempty"`
    66  	MasterDNS            []string              `json:"master_DNS,omitempty"`
    67  	// Was string until #2860:-
    68  	NetworkProvider                        *NetworkProvider        `json:"network_provider"`
    69  	MasterStoragePolicy                    string                  `json:"master_storage_policy,omitempty"`
    70  	DefaultKubernetesServiceContentLibrary string                  `json:"default_kubernetes_service_content_library,omitempty"`
    71  	WorkloadNTPServers                     []string                `json:"workload_ntp_servers,omitempty"`
    72  	LoadBalancerConfigSpec                 *LoadBalancerConfigSpec `json:"load_balancer_config_spec,omitempty"`
    73  }
    74  
    75  // SizingHint determines the size of the Tanzu Kubernetes Grid
    76  // Supervisor cluster's kubeapi instances.
    77  // Note: Only use TinySizingHint in non-production environments.
    78  // Note: This is a secure coding pattern to avoid Stringly typed fields.
    79  // See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/SizingHint/
    80  // Since 7.0.0
    81  type SizingHint struct {
    82  	slug string
    83  }
    84  
    85  var (
    86  	UndefinedSizingHint = SizingHint{""}
    87  	TinySizingHint      = SizingHint{"TINY"}
    88  	SmallSizingHint     = SizingHint{"SMALL"}
    89  	MediumSizingHint    = SizingHint{"MEDIUM"}
    90  	LargeSizingHint     = SizingHint{"LARGE"}
    91  )
    92  
    93  func (v SizingHint) String() string {
    94  	return v.slug
    95  }
    96  
    97  func (v *SizingHint) UnmarshalJSON(b []byte) error {
    98  	var s string
    99  	if err := json.Unmarshal(b, &s); nil != err {
   100  		return err
   101  	}
   102  	v.FromString(s)
   103  	return nil
   104  }
   105  
   106  func (v SizingHint) MarshalJSON() ([]byte, error) {
   107  	return json.Marshal(v.slug)
   108  }
   109  
   110  func (v *SizingHint) FromString(s string) {
   111  	v.slug = SizingHintFromString(s).slug
   112  }
   113  
   114  func SizingHintFromString(s string) SizingHint {
   115  	if "TINY" == s {
   116  		return TinySizingHint
   117  	}
   118  	if "SMALL" == s {
   119  		return SmallSizingHint
   120  	}
   121  	if "MEDIUM" == s {
   122  		return MediumSizingHint
   123  	}
   124  	if "LARGE" == s {
   125  		return LargeSizingHint
   126  	}
   127  	return UndefinedSizingHint
   128  }
   129  
   130  // ImageStorageSpec defines the storage policy ID (not name) assigned to
   131  // a Tanzu Kubernetes Grid cluster (supervisor or workload clusters)
   132  // See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/Clusters/ImageStorageSpec/
   133  // Since 7.0.0:-
   134  type ImageStorageSpec struct {
   135  	StoragePolicy string `json:"storage_policy"`
   136  }
   137  
   138  // Cidr defines an IPv4 CIDR range for a subnet.
   139  // See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/Namespaces/Instances/Ipv4Cidr/
   140  // TODO decide whether to rename this in the Go API to match the vSphere API.
   141  // Since 7.0.0:-
   142  type Cidr struct {
   143  	Address string `json:"address"`
   144  	Prefix  int    `json:"prefix"`
   145  }
   146  
   147  // NcpClusterNetworkSpec defines an NSX-T network for a Tanzu Kubernetes
   148  // Grid workload cluster in vSphere 7.0.0 until 7.0u1.
   149  // Note: NcpClusterNetworkSpec is replaced by WorkloadNetworksSpec in 7.0u2+.
   150  // See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/Clusters/NCPClusterNetworkEnableSpec/
   151  // TODO decide whether to rename this in the Go API to match the vSphere API.
   152  // Since 7.0.0:-
   153  type NcpClusterNetworkSpec struct {
   154  	NsxEdgeCluster           string `json:"nsx_edge_cluster,omitempty"`
   155  	PodCidrs                 []Cidr `json:"pod_cidrs"`
   156  	EgressCidrs              []Cidr `json:"egress_cidrs"`
   157  	ClusterDistributedSwitch string `json:"cluster_distributed_switch,omitempty"`
   158  	IngressCidrs             []Cidr `json:"ingress_cidrs"`
   159  }
   160  
   161  // NsxNetwork defines a supervisor or workload NSX-T network for use with
   162  // a Tanzu Kubernetes Cluster.
   163  // See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/Networks/NsxNetworkCreateSpec/
   164  // TODO decide whether to rename this in the Go API to match the vSphere API.
   165  // Since 7.0u3:-
   166  type NsxNetwork struct {
   167  	EgressCidrs           []Cidr `json:"egress_cidrs"`
   168  	IngressCidrs          []Cidr `json:"ingress_cidrs"`
   169  	LoadBalancerSize      string `json:"load_balancer_size"`
   170  	NamespaceNetworkCidrs []Cidr `json:"namespace_network_cidrs"`
   171  	NsxTier0Gateway       string `json:"nsx_tier0_gateway"`
   172  	RoutedMode            bool   `json:"routed_mode"`
   173  	SubnetPrefixLength    int    `json:"subnet_prefix_length"`
   174  }
   175  
   176  // IpRange specifies a contiguous set of IPv4 Addresses
   177  // See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/IPRange/
   178  // TODO decide whether to rename this in the Go API to match the vSphere API.
   179  // Note: omitempty allows AddressRanges: []IpRange to become json []
   180  // Since 7.0u1:-
   181  type IpRange struct {
   182  	Address string `json:"address,omitempty"`
   183  	Count   int    `json:"count,omitempty"`
   184  }
   185  
   186  // IpAssignmentMode specifies whether DHCP or a static range assignment
   187  // method is used. This is used for both Supervisor Cluster and Workload
   188  // Cluster networks in 7.0u3 and above.
   189  // See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/Networks/IPAssignmentMode/
   190  // TODO decide whether to rename this in the Go API to match the vSphere API.
   191  // Since 7.0u3:-
   192  type IpAssignmentMode struct {
   193  	slug string
   194  }
   195  
   196  var (
   197  	UndefinedIpAssignmentMode   = IpAssignmentMode{""}
   198  	DhcpIpAssignmentMode        = IpAssignmentMode{"DHCP"}
   199  	StaticRangeIpAssignmentMode = IpAssignmentMode{"STATICRANGE"}
   200  	// NOTE: Add new types at the END of this const to preserve previous values
   201  )
   202  
   203  func (v IpAssignmentMode) String() string {
   204  	return v.slug
   205  }
   206  func (v *IpAssignmentMode) UnmarshalJSON(b []byte) error {
   207  	var s string
   208  	if err := json.Unmarshal(b, &s); nil != err {
   209  		return err
   210  	}
   211  	v.FromString(s)
   212  	return nil
   213  }
   214  
   215  func (v IpAssignmentMode) MarshalJSON() ([]byte, error) {
   216  	return json.Marshal(v.slug)
   217  }
   218  
   219  func (v *IpAssignmentMode) FromString(s string) {
   220  	v.slug = IpAssignmentModeFromString(s).slug
   221  }
   222  
   223  func IpAssignmentModeFromString(s string) IpAssignmentMode {
   224  	if "DHCP" == s {
   225  		return DhcpIpAssignmentMode
   226  	}
   227  	if "STATICRANGE" == s {
   228  		return StaticRangeIpAssignmentMode
   229  	}
   230  	return UndefinedIpAssignmentMode
   231  }
   232  
   233  // See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/Networks/VsphereDVPGNetworkCreateSpec/
   234  // Since 7.0u1:-
   235  type VsphereDVPGNetworkCreateSpec struct {
   236  	AddressRanges []IpRange `json:"address_ranges"`
   237  	Gateway       string    `json:"gateway"`
   238  	PortGroup     string    `json:"portgroup"`
   239  	SubnetMask    string    `json:"subnet_mask"`
   240  	// Since 7.0u3:-
   241  	IpAssignmentMode *IpAssignmentMode `json:"ip_assignment_mode,omitempty"`
   242  }
   243  
   244  // NetworkProvider defines which type of
   245  // See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/Clusters/NetworkProvider/
   246  // Since 7.0.0:-
   247  type NetworkProvider struct {
   248  	slug string
   249  }
   250  
   251  var (
   252  	UndefinedNetworkProvider           = NetworkProvider{""}
   253  	NsxtContainerPluginNetworkProvider = NetworkProvider{"NSXT_CONTAINER_PLUGIN"}
   254  	// Since 7.0u1:-
   255  	VSphereNetworkProvider = NetworkProvider{"VSPHERE_NETWORK"}
   256  	// TODO vSphere (as in product), Vsphere (as in tag), or VSphere (as in camel case)???
   257  	// E.g. see from 7.0u3: https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/NSXTier0Gateway/Summary/
   258  )
   259  
   260  func (v NetworkProvider) String() string {
   261  	return v.slug
   262  }
   263  
   264  func (v *NetworkProvider) UnmarshalJSON(b []byte) error {
   265  	var s string
   266  	if err := json.Unmarshal(b, &s); nil != err {
   267  		return err
   268  	}
   269  	v.FromString(s)
   270  	return nil
   271  }
   272  
   273  func (v NetworkProvider) MarshalJSON() ([]byte, error) {
   274  	return json.Marshal(v.slug)
   275  }
   276  
   277  func (v *NetworkProvider) FromString(s string) {
   278  	v.slug = ClusterNetworkProviderFromString(s).slug
   279  }
   280  
   281  func ClusterNetworkProviderFromString(s string) NetworkProvider {
   282  	if "NSXT_CONTAINER_PLUGIN" == s {
   283  		return NsxtContainerPluginNetworkProvider
   284  	}
   285  	if "VSPHERE_NETWORK" == s {
   286  		return VSphereNetworkProvider
   287  	}
   288  	return UndefinedNetworkProvider
   289  }
   290  
   291  // NetworksCreateSpec specifies a Tanzu Kubernetes Grid Supervisor
   292  // or Workload network that should be created.
   293  // See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/Networks/CreateSpec/
   294  // Since 7.0u1:-
   295  type NetworksCreateSpec struct {
   296  	Network         string                        `json:"network"`
   297  	NetworkProvider *NetworkProvider              `json:"network_provider"`
   298  	VSphereNetwork  *VsphereDVPGNetworkCreateSpec `json:"vsphere_network,omitempty"`
   299  	// Since 7.0u3:-
   300  	NsxNetwork *NsxNetwork `json:"nsx_network,omitempty"`
   301  }
   302  
   303  // WorkloadNetworksEnableSpec defines the primary workload network for a new
   304  // Tanzu Kubernetes Grid supervisor cluster. This may be used by namespaces
   305  // for workloads too.
   306  // See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/Clusters/WorkloadNetworksEnableSpec/
   307  // TODO decide whether to rename this in the Go API to match the vSphere API.
   308  // Since 7.0u1:-
   309  type WorkloadNetworksEnableSpec struct {
   310  	SupervisorPrimaryWorkloadNetwork *NetworksCreateSpec `json:"supervisor_primary_workload_network"`
   311  	// TODO also support other workload networks in network_list
   312  	//      (These are not used for EnableCluster, and so left out for now)
   313  }
   314  
   315  // LoadBalancersServer defines an Avi or HA Proxy load balancer location.
   316  // Host can be an IP Address (normally an Avi Management Virtual IP for
   317  // the Avi Controller(s)) or a hostname.
   318  // See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/LoadBalancers/Server/
   319  // Since 7.0u1:-
   320  type LoadBalancersServer struct {
   321  	Host string `json:"host"`
   322  	Port int    `json:"port"`
   323  }
   324  
   325  // AviConfigCreateSpec defines full information for the linking of
   326  // a Tanzu Kubernetes Grid enabled vSphere cluster to an NSX
   327  // Advanced Load Balancer (formerly Avi Load Balancer)
   328  // See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/LoadBalancers/AviConfigCreateSpec/
   329  // Since 7.0u2:-
   330  type AviConfigCreateSpec struct {
   331  	CertificateAuthorityChain string               `json:"certificate_authority_chain"`
   332  	Password                  string               `json:"password"`
   333  	Server                    *LoadBalancersServer `json:"server"`
   334  	Username                  string               `json:"username"`
   335  }
   336  
   337  // HAProxyConfigCreateSpec defines full information for the linking of
   338  // a Tanzu Kubernetes Grid enabled vSphere cluster to a HA Proxy
   339  // Load Balancer.
   340  // Note: HA Proxy is not supported in vSphere 7.0u3 and above. Use Avi
   341  //
   342  //	with vSphere networking, or NSX-T networking, instead.
   343  //
   344  // See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/LoadBalancers/HAProxyConfigCreateSpec/
   345  // Since 7.0u1:-
   346  type HAProxyConfigCreateSpec struct {
   347  	CertificateAuthorityChain string                `json:"certificate_authority_chain"`
   348  	Password                  string                `json:"password"`
   349  	Servers                   []LoadBalancersServer `json:"servers"`
   350  	Username                  string                `json:"username"`
   351  }
   352  
   353  // A LoadBalancerProvider is an enum type that defines
   354  // the Load Balancer technology in use in a Tanzu Kubernetes Grid
   355  // cluster.
   356  // Note: If invalid or undefined (E.g. if a newer/older vSphere
   357  //
   358  //	version is used whose option isn't listed) then the
   359  //	UndefinedLoadBalancerProvider value shall be set.
   360  //	This translates to an empty string, removing its element
   361  //	from the produces JSON.
   362  //
   363  // See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/LoadBalancers/Provider/
   364  type LoadBalancerProvider struct {
   365  	slug string
   366  }
   367  
   368  var (
   369  	UndefinedLoadBalancerProvider = LoadBalancerProvider{""}
   370  	HAProxyLoadBalancerProvider   = LoadBalancerProvider{"HA_PROXY"}
   371  	AviLoadBalancerProvider       = LoadBalancerProvider{"AVI"}
   372  )
   373  
   374  func (v LoadBalancerProvider) String() string {
   375  	return v.slug
   376  }
   377  
   378  func (v *LoadBalancerProvider) UnmarshalJSON(b []byte) error {
   379  	var s string
   380  	if err := json.Unmarshal(b, &s); nil != err {
   381  		return err
   382  	}
   383  	v.FromString(s)
   384  	return nil
   385  }
   386  
   387  func (v LoadBalancerProvider) MarshalJSON() ([]byte, error) {
   388  	return json.Marshal(v.slug)
   389  }
   390  
   391  func (v *LoadBalancerProvider) FromString(s string) {
   392  	v.slug = LoadBalancerFromString(s).slug
   393  }
   394  
   395  func LoadBalancerFromString(s string) LoadBalancerProvider {
   396  	if "HA_PROXY" == s {
   397  		return HAProxyLoadBalancerProvider
   398  	}
   399  	if "AVI" == s {
   400  		return AviLoadBalancerProvider
   401  	}
   402  	return UndefinedLoadBalancerProvider
   403  }
   404  
   405  // LoadBalancerConfigSpec defines LoadBalancer options for Tanzu
   406  // Kubernetes Grid, both for the Supervisor Cluster and for
   407  // Workload Cluster kubeapi endpoints, and services of type
   408  // LoadBalancer
   409  // See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/LoadBalancers/ConfigSpec/
   410  // Since 7.0u1:-
   411  type LoadBalancerConfigSpec struct {
   412  	// AddressRanges removed since 7.0u2:- (Now in workload network spec)
   413  	AddressRanges           []IpRange                `json:"address_ranges,omitempty"` // omitempty to prevent null being the value
   414  	HAProxyConfigCreateSpec *HAProxyConfigCreateSpec `json:"ha_proxy_config_create_spec,omitempty"`
   415  	// Optional for create:-
   416  	Id       string                `json:"id"`
   417  	Provider *LoadBalancerProvider `json:"provider"`
   418  	// Since 7.0u2:-
   419  	AviConfigCreateSpec *AviConfigCreateSpec `json:"avi_config_create_spec,omitempty"`
   420  }
   421  
   422  // Since 7.0.0:-
   423  type AddressRange struct {
   424  	SubnetMask      string `json:"subnet_mask,omitempty"`
   425  	StartingAddress string `json:"starting_address"`
   426  	Gateway         string `json:"gateway"`
   427  	AddressCount    int    `json:"address_count,omitempty"`
   428  }
   429  
   430  // Since 7.0.0:-
   431  type MasterManagementNetwork struct {
   432  	Mode         *IpAssignmentMode `json:"mode"`
   433  	FloatingIP   string            `json:"floating_IP,omitempty"`
   434  	AddressRange *AddressRange     `json:"address_range,omitempty"`
   435  	Network      string            `json:"network"`
   436  }
   437  
   438  // Since 7.0.0:-
   439  type DefaultImageRegistry struct {
   440  	Hostname string `json:"hostname"`
   441  	Port     int    `json:"port,omitempty"`
   442  }
   443  
   444  // EnableCluster enables vSphere Namespaces on the specified cluster, using the given spec.
   445  // See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/api/vcenter/namespace-management/clusters/clusteractionenable/post/
   446  func (c *Manager) EnableCluster(ctx context.Context, id string, spec *EnableClusterSpec) error {
   447  	var response interface{}
   448  	url := c.Resource(path.Join(internal.NamespaceClusterPath, id)).WithParam("action", "enable")
   449  	fmt.Fprint(os.Stdout, spec)
   450  	err := c.Do(ctx, url.Request(http.MethodPost, spec), response)
   451  	return err
   452  }
   453  
   454  // EnableCluster enables vSphere Namespaces on the specified cluster, using the given spec.
   455  func (c *Manager) DisableCluster(ctx context.Context, id string) error {
   456  	var response interface{}
   457  	url := c.Resource(path.Join(internal.NamespaceClusterPath, id)).WithParam("action", "disable")
   458  	err := c.Do(ctx, url.Request(http.MethodPost), response)
   459  	return err
   460  }
   461  
   462  type KubernetesStatus struct {
   463  	slug string
   464  }
   465  
   466  var (
   467  	UndefinedKubernetesStatus = KubernetesStatus{""}
   468  	ReadyKubernetesStatus     = KubernetesStatus{"READY"}
   469  	WarningKubernetesStatus   = KubernetesStatus{"WARNING"}
   470  	ErrorKubernetesStatus     = KubernetesStatus{"ERROR"}
   471  	// NOTE: Add new types at the END of this const to preserve previous values
   472  )
   473  
   474  func (v KubernetesStatus) String() string {
   475  	return v.slug
   476  }
   477  
   478  func (v *KubernetesStatus) UnmarshalJSON(b []byte) error {
   479  	var s string
   480  	if err := json.Unmarshal(b, &s); nil != err {
   481  		return err
   482  	}
   483  	v.FromString(s)
   484  	return nil
   485  }
   486  
   487  func (v KubernetesStatus) MarshalJSON() ([]byte, error) {
   488  	return json.Marshal(v.slug)
   489  }
   490  
   491  func (v *KubernetesStatus) FromString(s string) {
   492  	v.slug = KubernetesStatusFromString(s).slug
   493  }
   494  
   495  func KubernetesStatusFromString(s string) KubernetesStatus {
   496  	if "READY" == s {
   497  		return ReadyKubernetesStatus
   498  	}
   499  	if "WARNING" == s {
   500  		return WarningKubernetesStatus
   501  	}
   502  	if "ERROR" == s {
   503  		return ErrorKubernetesStatus
   504  	}
   505  	return UndefinedKubernetesStatus
   506  }
   507  
   508  type ConfigStatus struct {
   509  	slug string
   510  }
   511  
   512  var (
   513  	UndefinedConfigStatus   = ConfigStatus{""}
   514  	ConfiguringConfigStatus = ConfigStatus{"CONFIGURING"}
   515  	RemovingConfigStatus    = ConfigStatus{"REMOVING"}
   516  	RunningConfigStatus     = ConfigStatus{"RUNNING"}
   517  	ErrorConfigStatus       = ConfigStatus{"ERROR"}
   518  	// NOTE: Add new types at the END of this const to preserve previous values
   519  )
   520  
   521  func (v ConfigStatus) String() string {
   522  	return v.slug
   523  }
   524  
   525  func (v *ConfigStatus) UnmarshalJSON(b []byte) error {
   526  	var s string
   527  	if err := json.Unmarshal(b, &s); nil != err {
   528  		return err
   529  	}
   530  	v.FromString(s)
   531  	return nil
   532  }
   533  
   534  func (v ConfigStatus) MarshalJSON() ([]byte, error) {
   535  	return json.Marshal(v.slug)
   536  }
   537  
   538  func (v *ConfigStatus) FromString(s string) {
   539  	v.slug = ConfigStatusFromString(s).slug
   540  }
   541  
   542  func ConfigStatusFromString(s string) ConfigStatus {
   543  	if "CONFIGURING" == s {
   544  		return ConfiguringConfigStatus
   545  	}
   546  	if "REMOVING" == s {
   547  		return RemovingConfigStatus
   548  	}
   549  	if "RUNNING" == s {
   550  		return RunningConfigStatus
   551  	}
   552  	if "ERROR" == s {
   553  		return ErrorConfigStatus
   554  	}
   555  	return UndefinedConfigStatus
   556  }
   557  
   558  // TODO CHANGE ENUMS TO: https://stackoverflow.com/questions/53569573/parsing-string-to-enum-from-json-in-golang
   559  // Also: https://eagain.net/articles/go-json-kind/
   560  
   561  // ClusterSummary for a cluster with vSphere Namespaces enabled.
   562  // See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/Clusters/Summary/
   563  // TODO plural vs singular - consistency with REST API above vs Go
   564  // Since 7.0.0:-
   565  type ClusterSummary struct {
   566  	ID   string `json:"cluster"`
   567  	Name string `json:"cluster_name"`
   568  	// Was string until #2860:-
   569  	KubernetesStatus *KubernetesStatus `json:"kubernetes_status"`
   570  	// Was string until #2860:-
   571  	ConfigStatus *ConfigStatus `json:"config_status"`
   572  }
   573  
   574  // TODO whether to replace the below with a Go GUID (json to string) reference type? (I.e. replace ClusterSummary.ID string with ID ManagedObjectID)
   575  // Reference implements the mo.Reference interface
   576  func (c *ClusterSummary) Reference() types.ManagedObjectReference {
   577  	return types.ManagedObjectReference{
   578  		Type:  "ClusterComputeResource",
   579  		Value: c.ID, // TODO replace with c.ID.(string) when ID changes from String to ManagedObjectID
   580  	}
   581  }
   582  
   583  // ListClusters returns a summary of all clusters with vSphere Namespaces enabled.
   584  func (c *Manager) ListClusters(ctx context.Context) ([]ClusterSummary, error) {
   585  	var res []ClusterSummary
   586  	url := c.Resource(internal.NamespaceClusterPath)
   587  	return res, c.Do(ctx, url.Request(http.MethodGet), &res)
   588  }
   589  
   590  // SupportBundleToken information about the token required in the HTTP GET request to generate the support bundle.
   591  // Since 7.0.0:-
   592  type SupportBundleToken struct {
   593  	Expiry string `json:"expiry"`
   594  	Token  string `json:"token"`
   595  }
   596  
   597  // SupportBundleLocation contains the URL to download the per-cluster support bundle from, as well as a token required.
   598  // Since 7.0.0:-
   599  type SupportBundleLocation struct {
   600  	Token SupportBundleToken `json:"wcp_support_bundle_token"`
   601  	URL   string             `json:"url"`
   602  }
   603  
   604  // CreateSupportBundle retrieves the cluster's Namespaces-related support bundle.
   605  func (c *Manager) CreateSupportBundle(ctx context.Context, id string) (*SupportBundleLocation, error) {
   606  	var res SupportBundleLocation
   607  	url := c.Resource(path.Join(internal.NamespaceClusterPath, id, "support-bundle"))
   608  	return &res, c.Do(ctx, url.Request(http.MethodPost), &res)
   609  }
   610  
   611  // SupportBundleRequest returns an http.Request which can be used to download the given support bundle.
   612  func (c *Manager) SupportBundleRequest(ctx context.Context, bundle *SupportBundleLocation) (*http.Request, error) {
   613  	token := internal.SupportBundleToken{Value: bundle.Token.Token}
   614  
   615  	var b bytes.Buffer
   616  	err := json.NewEncoder(&b).Encode(token)
   617  	if err != nil {
   618  		return nil, err
   619  	}
   620  
   621  	return http.NewRequest(http.MethodPost, bundle.URL, &b)
   622  }
   623  
   624  // Since 7.0.0:-
   625  type DistributedSwitchCompatibilitySummary struct {
   626  	Compatible        bool   `json:"compatible"`
   627  	DistributedSwitch string `json:"distributed_switch"`
   628  }
   629  
   630  func (c *Manager) ListCompatibleDistributedSwitches(ctx context.Context, clusterId string) (result []DistributedSwitchCompatibilitySummary, err error) {
   631  	listUrl := c.Resource(internal.NamespaceDistributedSwitchCompatibility).
   632  		WithParam("cluster", clusterId).
   633  		WithParam("compatible", "true")
   634  	return result, c.Do(ctx, listUrl.Request(http.MethodGet), &result)
   635  }
   636  
   637  // Since 7.0.0:-
   638  type EdgeClusterCompatibilitySummary struct {
   639  	Compatible  bool   `json:"compatible"`
   640  	EdgeCluster string `json:"edge_cluster"`
   641  	DisplayName string `json:"display_name"`
   642  }
   643  
   644  func (c *Manager) ListCompatibleEdgeClusters(ctx context.Context, clusterId string, switchId string) (result []EdgeClusterCompatibilitySummary, err error) {
   645  	listUrl := c.Resource(internal.NamespaceEdgeClusterCompatibility).
   646  		WithParam("cluster", clusterId).
   647  		WithParam("compatible", "true").
   648  		WithPathEncodedParam("distributed_switch", switchId)
   649  	return result, c.Do(ctx, listUrl.Request(http.MethodGet), &result)
   650  }
   651  
   652  // NamespacesInstanceStats https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/data-structures/Namespaces/Instances/Stats/
   653  type NamespacesInstanceStats struct {
   654  	CpuUsed     int64 `json:"cpu_used"`
   655  	MemoryUsed  int64 `json:"memory_used"`
   656  	StorageUsed int64 `json:"storage_used"`
   657  }
   658  
   659  // NamespacesInstanceSummary https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/data-structures/Namespaces/Instances/Summary/
   660  type NamespacesInstanceSummary struct {
   661  	ClusterId            string                  `json:"cluster"`
   662  	Namespace            string                  `json:"namespace"`
   663  	ConfigStatus         string                  `json:"config_status"`
   664  	Description          string                  `json:"description"`
   665  	Stats                NamespacesInstanceStats `json:"stats"`
   666  	SelfServiceNamespace bool                    `json:"self_service_namespace,omitempty"`
   667  }
   668  
   669  type LocalizableMessage struct {
   670  	Details  interface{} `json:"details"`
   671  	Severity string      `json:"severity"`
   672  }
   673  
   674  // NamespacesInstanceInfo https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/data-structures/Namespaces/Instances/Info/
   675  type NamespacesInstanceInfo struct {
   676  	ClusterId            string                  `json:"cluster"`
   677  	ConfigStatus         string                  `json:"config_status"`
   678  	Description          string                  `json:"description"`
   679  	Stats                NamespacesInstanceStats `json:"stats"`
   680  	SelfServiceNamespace bool                    `json:"self_service_namespace,omitempty"`
   681  	Messages             []LocalizableMessage    `json:"message"`
   682  	VmServiceSpec        VmServiceSpec           `json:"vm_service_spec,omitempty"`
   683  }
   684  
   685  // NamespacesInstanceCreateSpec https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/data-structures/Namespaces/Instances/CreateSpec/
   686  type NamespacesInstanceCreateSpec struct {
   687  	Cluster       string        `json:"cluster"`
   688  	Namespace     string        `json:"namespace"`
   689  	VmServiceSpec VmServiceSpec `json:"vm_service_spec,omitempty"`
   690  }
   691  
   692  // VmServiceSpec https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/data-structures/Namespaces/Instances/VMServiceSpec/
   693  type VmServiceSpec struct {
   694  	ContentLibraries []string `json:"content_libraries,omitempty"`
   695  	VmClasses        []string `json:"vm_classes,omitempty"`
   696  }
   697  
   698  // NamespacesInstanceUpdateSpec https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/data-structures/Namespaces/Instances/UpdateSpec/
   699  type NamespacesInstanceUpdateSpec struct {
   700  	VmServiceSpec VmServiceSpec `json:"vm_service_spec,omitempty"`
   701  }
   702  
   703  // ListNamespaces https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/api/vcenter/namespaces/instances/get/
   704  func (c *Manager) ListNamespaces(ctx context.Context) ([]NamespacesInstanceSummary, error) {
   705  	resource := c.Resource(internal.NamespacesPath)
   706  	request := resource.Request(http.MethodGet)
   707  	var result []NamespacesInstanceSummary
   708  	return result, c.Do(ctx, request, &result)
   709  }
   710  
   711  // GetNamespace https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/api/vcenter/namespaces/instances/namespace/get/
   712  func (c *Manager) GetNamespace(ctx context.Context, namespace string) (NamespacesInstanceInfo, error) {
   713  	resource := c.Resource(internal.NamespacesPath).WithSubpath(namespace)
   714  	request := resource.Request(http.MethodGet)
   715  	var result NamespacesInstanceInfo
   716  	return result, c.Do(ctx, request, &result)
   717  }
   718  
   719  // CreateNamespace https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/api/vcenter/namespaces/instances/post/
   720  func (c *Manager) CreateNamespace(ctx context.Context, spec NamespacesInstanceCreateSpec) error {
   721  	resource := c.Resource(internal.NamespacesPath)
   722  	request := resource.Request(http.MethodPost, spec)
   723  	return c.Do(ctx, request, nil)
   724  }
   725  
   726  // UpdateNamespace https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/api/vcenter/namespaces/instances/namespace/patch/
   727  func (c *Manager) UpdateNamespace(ctx context.Context, namespace string, spec NamespacesInstanceUpdateSpec) error {
   728  	resource := c.Resource(internal.NamespacesPath).WithSubpath(namespace)
   729  	request := resource.Request(http.MethodPatch, spec)
   730  	return c.Do(ctx, request, nil)
   731  }
   732  
   733  // DeleteNamespace https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/api/vcenter/namespaces/instances/namespace/delete/
   734  func (c *Manager) DeleteNamespace(ctx context.Context, namespace string) error {
   735  	resource := c.Resource(internal.NamespacesPath).WithSubpath(namespace)
   736  	request := resource.Request(http.MethodDelete)
   737  	return c.Do(ctx, request, nil)
   738  }
   739  
   740  // VirtualMachineClassInfo https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/data-structures/NamespaceManagement/VirtualMachineClasses/Info/
   741  type VirtualMachineClassInfo struct {
   742  	ConfigStatus      string               `json:"config_status"`
   743  	Description       string               `json:"description"`
   744  	Id                string               `json:"id"`
   745  	CpuCount          int64                `json:"cpu_count"`
   746  	MemoryMb          int64                `json:"memory_mb"`
   747  	Messages          []LocalizableMessage `json:"messages"`
   748  	Namespaces        []string             `json:"namespaces"`
   749  	Vms               []string             `json:"vms"`
   750  	Devices           VirtualDevices       `json:"devices"`
   751  	CpuReservation    int64                `json:"cpu_reservation,omitempty"`
   752  	MemoryReservation int64                `json:"memory_reservation,omitempty"`
   753  }
   754  
   755  // VirtualMachineClassCreateSpec https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/data-structures/NamespaceManagement/VirtualMachineClasses/CreateSpec/
   756  type VirtualMachineClassCreateSpec struct {
   757  	Id                string         `json:"id"`
   758  	CpuCount          int64          `json:"cpu_count"`
   759  	MemoryMb          int64          `json:"memory_MB"`
   760  	CpuReservation    int64          `json:"cpu_reservation,omitempty"`
   761  	MemoryReservation int64          `json:"memory_reservation,omitempty"`
   762  	Devices           VirtualDevices `json:"devices"`
   763  }
   764  
   765  // VirtualMachineClassUpdateSpec https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/data-structures/NamespaceManagement/VirtualMachineClasses/UpdateSpec/
   766  type VirtualMachineClassUpdateSpec struct {
   767  	Id                string         `json:"id"`
   768  	CpuCount          int64          `json:"cpu_count"`
   769  	MemoryMb          int64          `json:"memory_MB"`
   770  	CpuReservation    int64          `json:"cpu_reservation,omitempty"`
   771  	MemoryReservation int64          `json:"memory_reservation,omitempty"`
   772  	Devices           VirtualDevices `json:"devices"`
   773  }
   774  
   775  // DirectPathIoDevice https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/data-structures/NamespaceManagement/VirtualMachineClasses/DynamicDirectPathIODevice/
   776  type DirectPathIoDevice struct {
   777  	CustomLabel string `json:"custom_label,omitempty"`
   778  	DeviceId    int64  `json:"device_id"`
   779  	VendorId    int64  `json:"vendor_id"`
   780  }
   781  
   782  // VgpuDevice https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/data-structures/NamespaceManagement/VirtualMachineClasses/VGPUDevice/
   783  type VgpuDevice struct {
   784  	ProfileName string `json:"profile_name"`
   785  }
   786  
   787  // VirtualDevices https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/data-structures/NamespaceManagement/VirtualMachineClasses/VirtualDevices/
   788  type VirtualDevices struct {
   789  	DirectPathIoDevices []DirectPathIoDevice `json:"direct_path_io_devices,omitempty"`
   790  	VgpuDevices         []VgpuDevice         `json:"vgpu_devices,omitempty"`
   791  }
   792  
   793  // ListVmClasses https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/api/vcenter/namespace-management/virtual-machine-classes/get/
   794  func (c *Manager) ListVmClasses(ctx context.Context) ([]VirtualMachineClassInfo, error) {
   795  	resource := c.Resource(internal.VmClassesPath)
   796  	request := resource.Request(http.MethodGet)
   797  	var result []VirtualMachineClassInfo
   798  	return result, c.Do(ctx, request, &result)
   799  }
   800  
   801  // GetVmClass https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/api/vcenter/namespace-management/virtual-machine-classes/vm_class/get/
   802  func (c *Manager) GetVmClass(ctx context.Context, vmClass string) (VirtualMachineClassInfo, error) {
   803  	resource := c.Resource(internal.VmClassesPath).WithSubpath(vmClass)
   804  	request := resource.Request(http.MethodGet)
   805  	var result VirtualMachineClassInfo
   806  	return result, c.Do(ctx, request, &result)
   807  }
   808  
   809  // CreateVmClass https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/api/vcenter/namespace-management/virtual-machine-classes/post/
   810  func (c *Manager) CreateVmClass(ctx context.Context, spec VirtualMachineClassCreateSpec) error {
   811  	resource := c.Resource(internal.VmClassesPath)
   812  	request := resource.Request(http.MethodPost, spec)
   813  	return c.Do(ctx, request, nil)
   814  }
   815  
   816  // DeleteVmClass https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/api/vcenter/namespace-management/virtual-machine-classes/vm_class/delete/
   817  func (c *Manager) DeleteVmClass(ctx context.Context, vmClass string) error {
   818  	resource := c.Resource(internal.VmClassesPath).WithSubpath(vmClass)
   819  	request := resource.Request(http.MethodDelete)
   820  	return c.Do(ctx, request, nil)
   821  }
   822  
   823  // UpdateVmClass https://developer.vmware.com/apis/vsphere-automation/v7.0U3/vcenter/api/vcenter/namespace-management/virtual-machine-classes/vm_class/patch/
   824  func (c *Manager) UpdateVmClass(ctx context.Context, vmClass string, spec VirtualMachineClassUpdateSpec) error {
   825  	resource := c.Resource(internal.VmClassesPath).WithSubpath(vmClass)
   826  	request := resource.Request(http.MethodPatch, spec)
   827  	return c.Do(ctx, request, nil)
   828  }