From 642156dd6e5118c1ceecd396b885ac7a17d67d87 Mon Sep 17 00:00:00 2001 From: Adam Fowler Date: Wed, 20 Jul 2022 12:56:42 +0100 Subject: [PATCH] api: Adds vSphere 7.0u1-u3 support to namespace-management (Tanzu) Closes: #2860 Signed-off-by: Adam Fowler --- govc/namespace/cluster/enable.go | 28 +- vapi/namespace/namespace.go | 512 ++++++++++++++++++++++++-- vapi/namespace/simulator/simulator.go | 6 +- 3 files changed, 506 insertions(+), 40 deletions(-) diff --git a/govc/namespace/cluster/enable.go b/govc/namespace/cluster/enable.go index 8e5797bf4..2d3bf08ab 100644 --- a/govc/namespace/cluster/enable.go +++ b/govc/namespace/cluster/enable.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2020 VMware, Inc. All Rights Reserved. +Copyright (c) 2020-2022 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -33,7 +33,7 @@ type enableCluster struct { ControlPlaneDNSSearchDomains string ImageStoragePolicy string NcpClusterNetworkSpec workloadNetwork - ControlPlaneManagementNetwork namespace.MasterManagementNetwork + ControlPlaneManagementNetwork masterManagementNetwork ControlPlaneDNSNames string ControlPlaneNTPServers string EphemeralStoragePolicy string @@ -51,6 +51,13 @@ type enableCluster struct { *flags.ClusterFlag } +type masterManagementNetwork struct { + Mode string + FloatingIP string + AddressRange *namespace.AddressRange + Network string +} + type workloadNetwork struct { NsxEdgeCluster string PodCidrs string @@ -71,7 +78,7 @@ type objectReferences struct { func init() { newEnableCluster := &enableCluster{ - ControlPlaneManagementNetwork: namespace.MasterManagementNetwork{ + ControlPlaneManagementNetwork: masterManagementNetwork{ AddressRange: &namespace.AddressRange{}, }, } @@ -303,7 +310,11 @@ func (cmd *enableCluster) toVapiSpec(refs objectReferences) (*namespace.EnableCl if (cmd.ControlPlaneManagementNetwork.Mode != "") || (cmd.ControlPlaneManagementNetwork.FloatingIP != "") || (cmd.ControlPlaneManagementNetwork.Network != "") { - masterManagementNetwork = &cmd.ControlPlaneManagementNetwork + masterManagementNetwork.AddressRange = cmd.ControlPlaneManagementNetwork.AddressRange + masterManagementNetwork.FloatingIP = cmd.ControlPlaneManagementNetwork.FloatingIP + ipam := namespace.IpAssignmentModeFromString(cmd.ControlPlaneManagementNetwork.Mode) + masterManagementNetwork.Mode = &ipam + masterManagementNetwork.Network = cmd.ControlPlaneManagementNetwork.Network } if masterManagementNetwork != nil { if (masterManagementNetwork.AddressRange.SubnetMask == "") && @@ -315,9 +326,12 @@ func (cmd *enableCluster) toVapiSpec(refs objectReferences) (*namespace.EnableCl masterManagementNetwork.Network = refs.Network } + sh := namespace.SizingHintFromString(cmd.SizeHint) + np := namespace.ClusterNetworkProviderFromString(cmd.NetworkProvider) + spec := namespace.EnableClusterSpec{ MasterDNSSearchDomains: splitCommaSeparatedList(cmd.ControlPlaneDNSSearchDomains), - ImageStorage: namespace.ImageStorage{StoragePolicy: refs.ImageStoragePolicy}, + ImageStorage: namespace.ImageStorageSpec{StoragePolicy: refs.ImageStoragePolicy}, NcpClusterNetworkSpec: &namespace.NcpClusterNetworkSpec{ NsxEdgeCluster: refs.EdgeCluster, PodCidrs: podCidrs, @@ -332,11 +346,11 @@ func (cmd *enableCluster) toVapiSpec(refs objectReferences) (*namespace.EnableCl DefaultImageRepository: cmd.DefaultImageRepository, ServiceCidr: serviceCidr, LoginBanner: cmd.LoginBanner, - SizeHint: cmd.SizeHint, + SizeHint: &sh, WorkerDNS: splitCommaSeparatedList(cmd.WorkerDNS), DefaultImageRegistry: nil, MasterDNS: splitCommaSeparatedList(cmd.ControlPlaneDNS), - NetworkProvider: cmd.NetworkProvider, + NetworkProvider: &np, MasterStoragePolicy: refs.ControlPlaneStoragePolicy, DefaultKubernetesServiceContentLibrary: cmd.DefaultKubernetesServiceContentLibrary, } diff --git a/vapi/namespace/namespace.go b/vapi/namespace/namespace.go index c22bfddc9..99245310a 100644 --- a/vapi/namespace/namespace.go +++ b/vapi/namespace/namespace.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2020 VMware, Inc. All Rights Reserved. +Copyright (c) 2020-2022 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -20,7 +20,9 @@ import ( "bytes" "context" "encoding/json" + "fmt" "net/http" + "os" "path" "github.com/vmware/govmomi/vapi/namespace/internal" @@ -40,35 +42,114 @@ func NewManager(client *rest.Client) *Manager { } } +// EnableClusterSpec defines a Tanzu Supervisor Cluster for creation. +// See: https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/Clusters/EnableSpec/ +// Since 7.0.0:- type EnableClusterSpec struct { - MasterDNSSearchDomains []string `json:"master_DNS_search_domains,omitempty"` - ImageStorage ImageStorage `json:"image_storage"` - NcpClusterNetworkSpec *NcpClusterNetworkSpec `json:"ncp_cluster_network_spec"` - MasterManagementNetwork *MasterManagementNetwork `json:"master_management_network"` - MasterDNSNames []string `json:"Master_DNS_names,omitempty"` - MasterNTPServers []string `json:"master_NTP_servers,omitempty"` - EphemeralStoragePolicy string `json:"ephemeral_storage_policy,omitempty"` - DefaultImageRepository string `json:"default_image_repository,omitempty"` - ServiceCidr *Cidr `json:"service_cidr"` - LoginBanner string `json:"login_banner,omitempty"` - SizeHint string `json:"size_hint"` - WorkerDNS []string `json:"worker_DNS,omitempty"` - DefaultImageRegistry *DefaultImageRegistry `json:"default_image_registry,omitempty"` - MasterDNS []string `json:"master_DNS,omitempty"` - NetworkProvider string `json:"network_provider"` - MasterStoragePolicy string `json:"master_storage_policy,omitempty"` - DefaultKubernetesServiceContentLibrary string `json:"default_kubernetes_service_content_library,omitempty"` -} - -type ImageStorage struct { + MasterDNSSearchDomains []string `json:"master_DNS_search_domains,omitempty"` + ImageStorage ImageStorageSpec `json:"image_storage"` + NcpClusterNetworkSpec *NcpClusterNetworkSpec `json:"ncp_cluster_network_spec,omitempty"` + // Note: NcpClusterNetworkSpec is replaced by WorkloadNetworksSpec in vSphere 7.0u2+ + // Since 7.0u1:- + WorkloadNetworksSpec *WorkloadNetworksEnableSpec `json:"workload_networks_spec,omitempty"` + MasterManagementNetwork *MasterManagementNetwork `json:"master_management_network"` + MasterDNSNames []string `json:"Master_DNS_names,omitempty"` + MasterNTPServers []string `json:"master_NTP_servers,omitempty"` + EphemeralStoragePolicy string `json:"ephemeral_storage_policy,omitempty"` + DefaultImageRepository string `json:"default_image_repository,omitempty"` + ServiceCidr *Cidr `json:"service_cidr"` + LoginBanner string `json:"login_banner,omitempty"` + // Was string until #2860:- + SizeHint *SizingHint `json:"size_hint"` + WorkerDNS []string `json:"worker_DNS,omitempty"` + DefaultImageRegistry *DefaultImageRegistry `json:"default_image_registry,omitempty"` + MasterDNS []string `json:"master_DNS,omitempty"` + // Was string until #2860:- + NetworkProvider *NetworkProvider `json:"network_provider"` + MasterStoragePolicy string `json:"master_storage_policy,omitempty"` + DefaultKubernetesServiceContentLibrary string `json:"default_kubernetes_service_content_library,omitempty"` + WorkloadNTPServers []string `json:"workload_ntp_servers,omitempty"` + LoadBalancerConfigSpec *LoadBalancerConfigSpec `json:"load_balancer_config_spec,omitempty"` +} + +// SizingHint determines the size of the Tanzu Kubernetes Grid +// Supervisor cluster's kubeapi instances. +// Note: Only use TinySizingHint in non-production environments. +// Note: This is a secure coding pattern to avoid Stringly typed fields. +// See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/SizingHint/ +// Since 7.0.0 +type SizingHint struct { + slug string +} + +var ( + UndefinedSizingHint = SizingHint{""} + TinySizingHint = SizingHint{"TINY"} + SmallSizingHint = SizingHint{"SMALL"} + MediumSizingHint = SizingHint{"MEDIUM"} + LargeSizingHint = SizingHint{"LARGE"} +) + +func (v SizingHint) String() string { + return v.slug +} + +func (v *SizingHint) UnmarshalJSON(b []byte) error { + var s string + if err := json.Unmarshal(b, &s); nil != err { + return err + } + v.FromString(s) + return nil +} + +func (v SizingHint) MarshalJSON() ([]byte, error) { + return json.Marshal(v.slug) +} + +func (v *SizingHint) FromString(s string) { + v.slug = SizingHintFromString(s).slug +} + +func SizingHintFromString(s string) SizingHint { + if "TINY" == s { + return TinySizingHint + } + if "SMALL" == s { + return SmallSizingHint + } + if "MEDIUM" == s { + return MediumSizingHint + } + if "LARGE" == s { + return LargeSizingHint + } + return UndefinedSizingHint +} + +// ImageStorageSpec defines the storage policy ID (not name) assigned to +// a Tanzu Kubernetes Grid cluster (supervisor or workload clusters) +// See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/Clusters/ImageStorageSpec/ +// Since 7.0.0:- +type ImageStorageSpec struct { StoragePolicy string `json:"storage_policy"` } +// Cidr defines an IPv4 CIDR range for a subnet. +// See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/Namespaces/Instances/Ipv4Cidr/ +// TODO decide whether to rename this in the Go API to match the vSphere API. +// Since 7.0.0:- type Cidr struct { Address string `json:"address"` Prefix int `json:"prefix"` } +// NcpClusterNetworkSpec defines an NSX-T network for a Tanzu Kubernetes +// Grid workload cluster in vSphere 7.0.0 until 7.0u1. +// Note: NcpClusterNetworkSpec is replaced by WorkloadNetworksSpec in 7.0u2+. +// See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/Clusters/NCPClusterNetworkEnableSpec/ +// TODO decide whether to rename this in the Go API to match the vSphere API. +// Since 7.0.0:- type NcpClusterNetworkSpec struct { NsxEdgeCluster string `json:"nsx_edge_cluster,omitempty"` PodCidrs []Cidr `json:"pod_cidrs"` @@ -77,6 +158,264 @@ type NcpClusterNetworkSpec struct { IngressCidrs []Cidr `json:"ingress_cidrs"` } +// NsxNetwork defines a supervisor or workload NSX-T network for use with +// a Tanzu Kubernetes Cluster. +// See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/Networks/NsxNetworkCreateSpec/ +// TODO decide whether to rename this in the Go API to match the vSphere API. +// Since 7.0u3:- +type NsxNetwork struct { + EgressCidrs []Cidr `json:"egress_cidrs"` + IngressCidrs []Cidr `json:"ingress_cidrs"` + LoadBalancerSize string `json:"load_balancer_size"` + NamespaceNetworkCidrs []Cidr `json:"namespace_network_cidrs"` + NsxTier0Gateway string `json:"nsx_tier0_gateway"` + RoutedMode bool `json:"routed_mode"` + SubnetPrefixLength int `json:"subnet_prefix_length"` +} + +// IpRange specifies a contiguous set of IPv4 Addresses +// See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/IPRange/ +// TODO decide whether to rename this in the Go API to match the vSphere API. +// Note: omitempty allows AddressRanges: []IpRange to become json [] +// Since 7.0u1:- +type IpRange struct { + Address string `json:"address,omitempty"` + Count int `json:"count,omitempty"` +} + +// IpAssignmentMode specifies whether DHCP or a static range assignment +// method is used. This is used for both Supervisor Cluster and Workload +// Cluster networks in 7.0u3 and above. +// See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/Networks/IPAssignmentMode/ +// TODO decide whether to rename this in the Go API to match the vSphere API. +// Since 7.0u3:- +type IpAssignmentMode struct { + slug string +} + +var ( + UndefinedIpAssignmentMode = IpAssignmentMode{""} + DhcpIpAssignmentMode = IpAssignmentMode{"DHCP"} + StaticRangeIpAssignmentMode = IpAssignmentMode{"STATICRANGE"} + // NOTE: Add new types at the END of this const to preserve previous values +) + +func (v IpAssignmentMode) String() string { + return v.slug +} +func (v *IpAssignmentMode) UnmarshalJSON(b []byte) error { + var s string + if err := json.Unmarshal(b, &s); nil != err { + return err + } + v.FromString(s) + return nil +} + +func (v IpAssignmentMode) MarshalJSON() ([]byte, error) { + return json.Marshal(v.slug) +} + +func (v *IpAssignmentMode) FromString(s string) { + v.slug = IpAssignmentModeFromString(s).slug +} + +func IpAssignmentModeFromString(s string) IpAssignmentMode { + if "DHCP" == s { + return DhcpIpAssignmentMode + } + if "STATICRANGE" == s { + return StaticRangeIpAssignmentMode + } + return UndefinedIpAssignmentMode +} + +// See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/Networks/VsphereDVPGNetworkCreateSpec/ +// Since 7.0u1:- +type VsphereDVPGNetworkCreateSpec struct { + AddressRanges []IpRange `json:"address_ranges"` + Gateway string `json:"gateway"` + PortGroup string `json:"portgroup"` + SubnetMask string `json:"subnet_mask"` + // Since 7.0u3:- + IpAssignmentMode *IpAssignmentMode `json:"ip_assignment_mode,omitempty"` +} + +// NetworkProvider defines which type of +// See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/Clusters/NetworkProvider/ +// Since 7.0.0:- +type NetworkProvider struct { + slug string +} + +var ( + UndefinedNetworkProvider = NetworkProvider{""} + NsxtContainerPluginNetworkProvider = NetworkProvider{"NSXT_CONTAINER_PLUGIN"} + // Since 7.0u1:- + VSphereNetworkProvider = NetworkProvider{"VSPHERE_NETWORK"} + // TODO vSphere (as in product), Vsphere (as in tag), or VSphere (as in camel case)??? + // E.g. see from 7.0u3: https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/NSXTier0Gateway/Summary/ +) + +func (v NetworkProvider) String() string { + return v.slug +} + +func (v *NetworkProvider) UnmarshalJSON(b []byte) error { + var s string + if err := json.Unmarshal(b, &s); nil != err { + return err + } + v.FromString(s) + return nil +} + +func (v NetworkProvider) MarshalJSON() ([]byte, error) { + return json.Marshal(v.slug) +} + +func (v *NetworkProvider) FromString(s string) { + v.slug = ClusterNetworkProviderFromString(s).slug +} + +func ClusterNetworkProviderFromString(s string) NetworkProvider { + if "NSXT_CONTAINER_PLUGIN" == s { + return NsxtContainerPluginNetworkProvider + } + if "VSPHERE_NETWORK" == s { + return VSphereNetworkProvider + } + return UndefinedNetworkProvider +} + +// NetworksCreateSpec specifies a Tanzu Kubernetes Grid Supervisor +// or Workload network that should be created. +// See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/Networks/CreateSpec/ +// Since 7.0u1:- +type NetworksCreateSpec struct { + Network string `json:"network"` + NetworkProvider *NetworkProvider `json:"network_provider"` + VSphereNetwork *VsphereDVPGNetworkCreateSpec `json:"vsphere_network,omitempty"` + // Since 7.0u3:- + NsxNetwork *NsxNetwork `json:"nsx_network,omitempty"` +} + +// WorkloadNetworksEnableSpec defines the primary workload network for a new +// Tanzu Kubernetes Grid supervisor cluster. This may be used by namespaces +// for workloads too. +// See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/Clusters/WorkloadNetworksEnableSpec/ +// TODO decide whether to rename this in the Go API to match the vSphere API. +// Since 7.0u1:- +type WorkloadNetworksEnableSpec struct { + SupervisorPrimaryWorkloadNetwork *NetworksCreateSpec `json:"supervisor_primary_workload_network"` + // TODO also support other workload networks in network_list + // (These are not used for EnableCluster, and so left out for now) +} + +// LoadBalancersServer defines an Avi or HA Proxy load balancer location. +// Host can be an IP Address (normally an Avi Management Virtual IP for +// the Avi Controller(s)) or a hostname. +// See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/LoadBalancers/Server/ +// Since 7.0u1:- +type LoadBalancersServer struct { + Host string `json:"host"` + Port int `json:"port"` +} + +// AviConfigCreateSpec defines full information for the linking of +// a Tanzu Kubernetes Grid enabled vSphere cluster to an NSX +// Advanced Load Balancer (formerly Avi Load Balancer) +// See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/LoadBalancers/AviConfigCreateSpec/ +// Since 7.0u2:- +type AviConfigCreateSpec struct { + CertificateAuthorityChain string `json:"certificate_authority_chain"` + Password string `json:"password"` + Server *LoadBalancersServer `json:"server"` + Username string `json:"username"` +} + +// HAProxyConfigCreateSpec defines full information for the linking of +// a Tanzu Kubernetes Grid enabled vSphere cluster to a HA Proxy +// Load Balancer. +// Note: HA Proxy is not supported in vSphere 7.0u3 and above. Use Avi +// with vSphere networking, or NSX-T networking, instead. +// See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/LoadBalancers/HAProxyConfigCreateSpec/ +// Since 7.0u1:- +type HAProxyConfigCreateSpec struct { + CertificateAuthorityChain string `json:"certificate_authority_chain"` + Password string `json:"password"` + Servers []LoadBalancersServer `json:"servers"` + Username string `json:"username"` +} + +// A LoadBalancerProvider is an enum type that defines +// the Load Balancer technology in use in a Tanzu Kubernetes Grid +// cluster. +// Note: If invalid or undefined (E.g. if a newer/older vSphere +// version is used whose option isn't listed) then the +// UndefinedLoadBalancerProvider value shall be set. +// This translates to an empty string, removing its element +// from the produces JSON. +// See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/LoadBalancers/Provider/ +type LoadBalancerProvider struct { + slug string +} + +var ( + UndefinedLoadBalancerProvider = LoadBalancerProvider{""} + HAProxyLoadBalancerProvider = LoadBalancerProvider{"HA_PROXY"} + AviLoadBalancerProvider = LoadBalancerProvider{"AVI"} +) + +func (v LoadBalancerProvider) String() string { + return v.slug +} + +func (v *LoadBalancerProvider) UnmarshalJSON(b []byte) error { + var s string + if err := json.Unmarshal(b, &s); nil != err { + return err + } + v.FromString(s) + return nil +} + +func (v LoadBalancerProvider) MarshalJSON() ([]byte, error) { + return json.Marshal(v.slug) +} + +func (v *LoadBalancerProvider) FromString(s string) { + v.slug = LoadBalancerFromString(s).slug +} + +func LoadBalancerFromString(s string) LoadBalancerProvider { + if "HA_PROXY" == s { + return HAProxyLoadBalancerProvider + } + if "AVI" == s { + return AviLoadBalancerProvider + } + return UndefinedLoadBalancerProvider +} + +// LoadBalancerConfigSpec defines LoadBalancer options for Tanzu +// Kubernetes Grid, both for the Supervisor Cluster and for +// Workload Cluster kubeapi endpoints, and services of type +// LoadBalancer +// See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/LoadBalancers/ConfigSpec/ +// Since 7.0u1:- +type LoadBalancerConfigSpec struct { + // AddressRanges removed since 7.0u2:- (Now in workload network spec) + AddressRanges []IpRange `json:"address_ranges,omitempty"` // omitempty to prevent null being the value + HAProxyConfigCreateSpec *HAProxyConfigCreateSpec `json:"ha_proxy_config_create_spec,omitempty"` + // Optional for create:- + Id string `json:"id"` + Provider *LoadBalancerProvider `json:"provider"` + // Since 7.0u2:- + AviConfigCreateSpec *AviConfigCreateSpec `json:"avi_config_create_spec,omitempty"` +} + +// Since 7.0.0:- type AddressRange struct { SubnetMask string `json:"subnet_mask,omitempty"` StartingAddress string `json:"starting_address"` @@ -84,22 +423,26 @@ type AddressRange struct { AddressCount int `json:"address_count,omitempty"` } +// Since 7.0.0:- type MasterManagementNetwork struct { - Mode string `json:"mode"` - FloatingIP string `json:"floating_IP,omitempty"` - AddressRange *AddressRange `json:"address_range,omitempty"` - Network string `json:"network"` + Mode *IpAssignmentMode `json:"mode"` + FloatingIP string `json:"floating_IP,omitempty"` + AddressRange *AddressRange `json:"address_range,omitempty"` + Network string `json:"network"` } +// Since 7.0.0:- type DefaultImageRegistry struct { Hostname string `json:"hostname"` Port int `json:"port,omitempty"` } // EnableCluster enables vSphere Namespaces on the specified cluster, using the given spec. +// See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/api/vcenter/namespace-management/clusters/clusteractionenable/post/ func (c *Manager) EnableCluster(ctx context.Context, id string, spec *EnableClusterSpec) error { var response interface{} url := c.Resource(path.Join(internal.NamespaceClusterPath, id)).WithParam("action", "enable") + fmt.Fprint(os.Stdout, spec) err := c.Do(ctx, url.Request(http.MethodPost, spec), response) return err } @@ -112,19 +455,124 @@ func (c *Manager) DisableCluster(ctx context.Context, id string) error { return err } +type KubernetesStatus struct { + slug string +} + +var ( + UndefinedKubernetesStatus = KubernetesStatus{""} + ReadyKubernetesStatus = KubernetesStatus{"READY"} + WarningKubernetesStatus = KubernetesStatus{"WARNING"} + ErrorKubernetesStatus = KubernetesStatus{"ERROR"} + // NOTE: Add new types at the END of this const to preserve previous values +) + +func (v KubernetesStatus) String() string { + return v.slug +} + +func (v *KubernetesStatus) UnmarshalJSON(b []byte) error { + var s string + if err := json.Unmarshal(b, &s); nil != err { + return err + } + v.FromString(s) + return nil +} + +func (v KubernetesStatus) MarshalJSON() ([]byte, error) { + return json.Marshal(v.slug) +} + +func (v *KubernetesStatus) FromString(s string) { + v.slug = KubernetesStatusFromString(s).slug +} + +func KubernetesStatusFromString(s string) KubernetesStatus { + if "READY" == s { + return ReadyKubernetesStatus + } + if "WARNING" == s { + return WarningKubernetesStatus + } + if "ERROR" == s { + return ErrorKubernetesStatus + } + return UndefinedKubernetesStatus +} + +type ConfigStatus struct { + slug string +} + +var ( + UndefinedConfigStatus = ConfigStatus{""} + ConfiguringConfigStatus = ConfigStatus{"CONFIGURING"} + RemovingConfigStatus = ConfigStatus{"REMOVING"} + RunningConfigStatus = ConfigStatus{"RUNNING"} + ErrorConfigStatus = ConfigStatus{"ERROR"} + // NOTE: Add new types at the END of this const to preserve previous values +) + +func (v ConfigStatus) String() string { + return v.slug +} + +func (v *ConfigStatus) UnmarshalJSON(b []byte) error { + var s string + if err := json.Unmarshal(b, &s); nil != err { + return err + } + v.FromString(s) + return nil +} + +func (v ConfigStatus) MarshalJSON() ([]byte, error) { + return json.Marshal(v.slug) +} + +func (v *ConfigStatus) FromString(s string) { + v.slug = ConfigStatusFromString(s).slug +} + +func ConfigStatusFromString(s string) ConfigStatus { + if "CONFIGURING" == s { + return ConfiguringConfigStatus + } + if "REMOVING" == s { + return RemovingConfigStatus + } + if "RUNNING" == s { + return RunningConfigStatus + } + if "ERROR" == s { + return ErrorConfigStatus + } + return UndefinedConfigStatus +} + +// TODO CHANGE ENUMS TO: https://stackoverflow.com/questions/53569573/parsing-string-to-enum-from-json-in-golang +// Also: https://eagain.net/articles/go-json-kind/ + // ClusterSummary for a cluster with vSphere Namespaces enabled. +// See https://developer.vmware.com/apis/vsphere-automation/latest/vcenter/data-structures/NamespaceManagement/Clusters/Summary/ +// TODO plural vs singular - consistency with REST API above vs Go +// Since 7.0.0:- type ClusterSummary struct { - ID string `json:"cluster"` - Name string `json:"cluster_name"` - KubernetesStatus string `json:"kubernetes_status"` - ConfigStatus string `json:"config_status"` + ID string `json:"cluster"` + Name string `json:"cluster_name"` + // Was string until #2860:- + KubernetesStatus *KubernetesStatus `json:"kubernetes_status"` + // Was string until #2860:- + ConfigStatus *ConfigStatus `json:"config_status"` } +// TODO whether to replace the below with a Go GUID (json to string) reference type? (I.e. replace ClusterSummary.ID string with ID ManagedObjectID) // Reference implements the mo.Reference interface func (c *ClusterSummary) Reference() types.ManagedObjectReference { return types.ManagedObjectReference{ Type: "ClusterComputeResource", - Value: c.ID, + Value: c.ID, // TODO replace with c.ID.(string) when ID changes from String to ManagedObjectID } } @@ -136,12 +584,14 @@ func (c *Manager) ListClusters(ctx context.Context) ([]ClusterSummary, error) { } // SupportBundleToken information about the token required in the HTTP GET request to generate the support bundle. +// Since 7.0.0:- type SupportBundleToken struct { Expiry string `json:"expiry"` Token string `json:"token"` } // SupportBundleLocation contains the URL to download the per-cluster support bundle from, as well as a token required. +// Since 7.0.0:- type SupportBundleLocation struct { Token SupportBundleToken `json:"wcp_support_bundle_token"` URL string `json:"url"` @@ -167,6 +617,7 @@ func (c *Manager) SupportBundleRequest(ctx context.Context, bundle *SupportBundl return http.NewRequest(http.MethodPost, bundle.URL, &b) } +// Since 7.0.0:- type DistributedSwitchCompatibilitySummary struct { Compatible bool `json:"compatible"` DistributedSwitch string `json:"distributed_switch"` @@ -179,6 +630,7 @@ func (c *Manager) ListCompatibleDistributedSwitches(ctx context.Context, cluster return result, c.Do(ctx, listUrl.Request(http.MethodGet), &result) } +// Since 7.0.0:- type EdgeClusterCompatibilitySummary struct { Compatible bool `json:"compatible"` EdgeCluster string `json:"edge_cluster"` diff --git a/vapi/namespace/simulator/simulator.go b/vapi/namespace/simulator/simulator.go index 285a8696a..afde46bdf 100644 --- a/vapi/namespace/simulator/simulator.go +++ b/vapi/namespace/simulator/simulator.go @@ -1,5 +1,5 @@ /* -Copyright (c) 2020 VMware, Inc. All Rights Reserved. +Copyright (c) 2020-2022 VMware, Inc. All Rights Reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -104,8 +104,8 @@ func (h *Handler) clusters(w http.ResponseWriter, r *http.Request) { for i, ref := range refs { clusters[i] = namespace.ClusterSummary{ ID: ref.Value, - ConfigStatus: "RUNNING", - KubernetesStatus: "READY", + ConfigStatus: &namespace.RunningConfigStatus, + KubernetesStatus: &namespace.ReadyKubernetesStatus, } } vapi.StatusOK(w, clusters)