k8c.io/api/v3@v3.0.0-20230904060738-b0a93889c0b6/pkg/apis/kubermatic/v1/datacenter.go (about)

     1  /*
     2  Copyright 2023 The Kubermatic Kubernetes Platform contributors.
     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 v1
    18  
    19  import (
    20  	corev1 "k8s.io/api/core/v1"
    21  	networkingv1 "k8s.io/api/networking/v1"
    22  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    23  	"k8s.io/apimachinery/pkg/util/sets"
    24  )
    25  
    26  // +genclient
    27  // +kubebuilder:resource:scope=Cluster
    28  // +kubebuilder:object:generate=true
    29  // +kubebuilder:object:root=true
    30  // +kubebuilder:subresource:status
    31  // +kubebuilder:printcolumn:JSONPath=".status.clusters",name="Clusters",type="integer"
    32  // +kubebuilder:printcolumn:JSONPath=".metadata.creationTimestamp",name="Age",type="date"
    33  
    34  // Datacenter is an allowed cloud provider configuration for user clusters. Each cluster
    35  // must be scheduled to use exactly one of the available datacenters (of the same provider,
    36  // i.e. an AWS cluster cannot use a Hetzner datacenter).
    37  type Datacenter struct {
    38  	metav1.TypeMeta   `json:",inline"`
    39  	metav1.ObjectMeta `json:"metadata,omitempty"`
    40  
    41  	Spec   DatacenterSpec   `json:"spec,omitempty"`
    42  	Status DatacenterStatus `json:"status,omitempty"`
    43  }
    44  
    45  // DatacenterSpec configures a KKP datacenter. Provider configuration is mutually exclusive,
    46  // and as such only a single provider can be configured per datacenter.
    47  type DatacenterSpec struct {
    48  	// Provider contains cloud-provider related configuration.
    49  	Provider DatacenterProviderSpec `json:"provider"`
    50  
    51  	// Node holds node-specific settings, like e.g. HTTP proxy, Docker
    52  	// registries and the like. Proxy settings are inherited from the seed if
    53  	// not specified here.
    54  	Node *NodeSettings `json:"node,omitempty"`
    55  
    56  	// Optional: When defined, only users with an e-mail address on the
    57  	// given domains can make use of this datacenter. You can define multiple
    58  	// domains, e.g. "example.com", one of which must match the email domain
    59  	// exactly (i.e. "example.com" will not match "user@test.example.com").
    60  	RequiredEmails []string `json:"requiredEmails,omitempty"`
    61  
    62  	// Optional: EnforceAuditLogging enforces audit logging on every cluster within the DC,
    63  	// ignoring cluster-specific settings.
    64  	EnforceAuditLogging bool `json:"enforceAuditLogging,omitempty"`
    65  
    66  	// Optional: EnforcePodSecurityPolicy enforces pod security policy plugin on every clusters within the DC,
    67  	// ignoring cluster-specific settings.
    68  	EnforcePodSecurityPolicy bool `json:"enforcePodSecurityPolicy,omitempty"`
    69  
    70  	// Optional: ProviderReconciliationInterval is the time that must have passed since a
    71  	// Cluster's status.lastProviderReconciliation to make the cliuster controller
    72  	// perform an in-depth provider reconciliation, where for example missing security
    73  	// groups will be reconciled.
    74  	// Setting this too low can cause rate limits by the cloud provider, setting this
    75  	// too high means that *if* a resource at a cloud provider is removed/changed outside
    76  	// of KKP, it will take this long to fix it.
    77  	ProviderReconciliationInterval *metav1.Duration `json:"providerReconciliationInterval,omitempty"`
    78  
    79  	// Optional: DefaultOperatingSystemProfiles specifies the OperatingSystemProfiles to use for each supported operating system.
    80  	DefaultOperatingSystemProfiles OperatingSystemProfileList `json:"operatingSystemProfiles,omitempty"`
    81  
    82  	// Optional: MachineFlavorFilter is used to filter out allowed machine flavors based on the specified resource limits like CPU, Memory, and GPU etc.
    83  	MachineFlavorFilter *MachineFlavorFilter `json:"machineFlavorFilter,omitempty"`
    84  }
    85  
    86  // DatacenterSpec configures a KKP datacenter. Provider configuration is mutually exclusive,
    87  // and as such only a single provider can be configured per datacenter.
    88  type DatacenterProviderSpec struct {
    89  	// ProviderName is the name of the cloud provider used for this datacenter.
    90  	// This must match the given provider spec (e.g. if the providerName is
    91  	// "aws", then the `aws` field must be set).
    92  	ProviderName CloudProvider `json:"providerName"`
    93  	// Digitalocean contains settings for Digitalocean (DO).
    94  	Digitalocean *DatacenterSpecDigitalocean `json:"digitalocean,omitempty"`
    95  	// BringYourOwn contains settings for clusters using manually created
    96  	// nodes via kubeadm.
    97  	BringYourOwn *DatacenterSpecBringYourOwn `json:"bringyourown,omitempty"`
    98  	// AWS configures an Amazon Web Services (AWS) datacenter.
    99  	AWS *DatacenterSpecAWS `json:"aws,omitempty"`
   100  	// Azure configures an Azure datacenter.
   101  	Azure *DatacenterSpecAzure `json:"azure,omitempty"`
   102  	// OpenStack configures an OpenStack datacenter.
   103  	OpenStack *DatacenterSpecOpenStack `json:"openstack,omitempty"`
   104  	// Packet configures an Equinix Metal datacenter.
   105  	Packet *DatacenterSpecPacket `json:"packet,omitempty"`
   106  	// Hetzner configures a Hetzner datacenter.
   107  	Hetzner *DatacenterSpecHetzner `json:"hetzner,omitempty"`
   108  	// VSphere configures a VMware vSphere datacenter.
   109  	VSphere *DatacenterSpecVSphere `json:"vsphere,omitempty"`
   110  	// VMwareCloudDirector configures a VMware Cloud Director datacenter.
   111  	VMwareCloudDirector *DatacenterSpecVMwareCloudDirector `json:"vmwareclouddirector,omitempty"`
   112  	// GCP configures a Google Cloud Platform (GCP) datacenter.
   113  	GCP *DatacenterSpecGCP `json:"gcp,omitempty"`
   114  	// KubeVirt configures a KubeVirt datacenter.
   115  	KubeVirt *DatacenterSpecKubeVirt `json:"kubevirt,omitempty"`
   116  	// Alibaba configures an Alibaba Cloud datacenter.
   117  	Alibaba *DatacenterSpecAlibaba `json:"alibaba,omitempty"`
   118  	// Anexia configures an Anexia datacenter.
   119  	Anexia *DatacenterSpecAnexia `json:"anexia,omitempty"`
   120  	// Nutanix configures a Nutanix HCI datacenter.
   121  	Nutanix *DatacenterSpecNutanix `json:"nutanix,omitempty"`
   122  
   123  	//nolint:staticcheck
   124  	//lint:ignore SA5008 omitgenyaml is used by the example-yaml-generator
   125  	Fake *DatacenterSpecFake `json:"fake,omitempty,omitgenyaml"`
   126  }
   127  
   128  // ImageList defines a map of operating system and the image to use.
   129  type ImageList map[OperatingSystem]string
   130  
   131  // ImageListWithVersions defines a map of operating system with their versions to use.
   132  type ImageListWithVersions map[OperatingSystem]OSVersions
   133  
   134  // OSVersions defines a map of OS version and the source to download the image.
   135  type OSVersions map[string]string
   136  
   137  // OperatingSystemProfileList defines a map of operating system and the OperatingSystemProfile to use.
   138  type OperatingSystemProfileList map[OperatingSystem]string
   139  
   140  // DatacenterSpecHetzner describes a Hetzner cloud datacenter.
   141  type DatacenterSpecHetzner struct {
   142  	// Datacenter location, e.g. "nbg1-dc3". A list of existing datacenters can be found
   143  	// at https://docs.hetzner.com/general/others/data-centers-and-connection/
   144  	Datacenter string `json:"datacenter"`
   145  	// Network is the pre-existing Hetzner network in which the machines are running.
   146  	// While machines can be in multiple networks, a single one must be chosen for the
   147  	// HCloud CCM to work.
   148  	Network string `json:"network"`
   149  	// Optional: Detailed location of the datacenter, like "Hamburg" or "Datacenter 7".
   150  	// For informational purposes only.
   151  	Location string `json:"location,omitempty"`
   152  }
   153  
   154  // DatacenterSpecDigitalocean describes a DigitalOcean datacenter.
   155  type DatacenterSpecDigitalocean struct {
   156  	// Datacenter location, e.g. "ams3". A list of existing datacenters can be found
   157  	// at https://www.digitalocean.com/docs/platform/availability-matrix/
   158  	Region string `json:"region"`
   159  }
   160  
   161  // DatacenterSpecOpenStack describes an OpenStack datacenter.
   162  type DatacenterSpecOpenStack struct {
   163  	AuthURL          string `json:"authURL"`
   164  	AvailabilityZone string `json:"availabilityZone,omitempty"`
   165  	Region           string `json:"region"`
   166  	// Optional
   167  	IgnoreVolumeAZ bool `json:"ignoreVolumeAZ,omitempty"` //nolint:tagliatelle
   168  	// Optional
   169  	EnforceFloatingIP bool `json:"enforceFloatingIP,omitempty"`
   170  	// Used for automatic network creation
   171  	DNSServers []string `json:"dnsServers,omitempty"`
   172  	// Images to use for each supported operating system.
   173  	Images ImageList `json:"images"`
   174  	// Optional: Gets mapped to the "manage-security-groups" setting in the cloud config.
   175  	// This setting defaults to true.
   176  	ManageSecurityGroups *bool `json:"manageSecurityGroups,omitempty"`
   177  	// Optional: Gets mapped to the "use-octavia" setting in the cloud config.
   178  	// use-octavia is enabled by default in CCM since v1.17.0, and disabled by
   179  	// default with the in-tree cloud provider.
   180  	UseOctavia *bool `json:"useOctavia,omitempty"`
   181  	// Optional: Gets mapped to the "trust-device-path" setting in the cloud config.
   182  	// This setting defaults to false.
   183  	TrustDevicePath *bool `json:"trustDevicePath,omitempty"`
   184  	// Optional: Restrict the allowed VM configurations that can be chosen in
   185  	// the KKP dashboard. This setting does not affect the validation webhook for
   186  	// MachineDeployments.
   187  	NodeSizeRequirements *OpenStackNodeSizeRequirements `json:"nodeSizeRequirements,omitempty"`
   188  	// Optional: List of enabled flavors for the given datacenter
   189  	EnabledFlavors []string `json:"enabledFlavors,omitempty"`
   190  	// Optional: defines if the IPv6 is enabled for the datacenter
   191  	IPv6Enabled *bool `json:"ipv6Enabled,omitempty"`
   192  }
   193  
   194  type OpenStackNodeSizeRequirements struct {
   195  	// VCPUs is the minimum required amount of (virtual) CPUs
   196  	MinimumVCPUs int `json:"minimumVCPUs,omitempty"` //nolint:tagliatelle
   197  	// MinimumMemory is the minimum required amount of memory, measured in MB
   198  	MinimumMemory int `json:"minimumMemory,omitempty"`
   199  }
   200  
   201  // DatacenterSpecAzure describes an Azure cloud datacenter.
   202  type DatacenterSpecAzure struct {
   203  	// Region to use, for example "westeurope". A list of available regions can be
   204  	// found at https://azure.microsoft.com/en-us/global-infrastructure/locations/
   205  	Location string `json:"location"`
   206  }
   207  
   208  // DatacenterSpecVSphere describes a vSphere datacenter.
   209  type DatacenterSpecVSphere struct {
   210  	// Endpoint URL to use, including protocol, for example "https://vcenter.example.com".
   211  	Endpoint string `json:"endpoint"`
   212  	// If set to true, disables the TLS certificate check against the endpoint.
   213  	AllowInsecure bool `json:"allowInsecure,omitempty"`
   214  	// The default Datastore to be used for provisioning volumes using storage
   215  	// classes/dynamic provisioning and for storing virtual machine files in
   216  	// case no `Datastore` or `DatastoreCluster` is provided at Cluster level.
   217  	DefaultDatastore string `json:"datastore"`
   218  	// The name of the datacenter to use.
   219  	Datacenter string `json:"datacenter"`
   220  	// The name of the vSphere cluster to use. Used for out-of-tree CSI Driver.
   221  	Cluster string `json:"cluster"`
   222  	// The name of the storage policy to use for the storage class created in the user cluster.
   223  	DefaultStoragePolicy string `json:"storagePolicy,omitempty"`
   224  	// Optional: The root path for cluster specific VM folders. Each cluster gets its own
   225  	// folder below the root folder. Must be the FQDN (for example
   226  	// "/datacenter-1/vm/all-kubermatic-vms-in-here") and defaults to the root VM
   227  	// folder: "/datacenter-1/vm"
   228  	RootPath string `json:"rootPath,omitempty"`
   229  	// A list of VM templates to use for a given operating system. You must
   230  	// define at least one template.
   231  	// See: https://github.com/kubermatic/machine-controller/blob/master/docs/vsphere.md#template-vms-preparation
   232  	Templates ImageList `json:"templates"`
   233  	// Optional: Infra management user is the user that will be used for everything
   234  	// except the cloud provider functionality, which will still use the credentials
   235  	// passed in via the Kubermatic dashboard/API.
   236  	InfraManagementUser *VSphereCredentials `json:"infraManagementUser,omitempty"`
   237  	// Optional: defines if the IPv6 is enabled for the datacenter
   238  	IPv6Enabled *bool `json:"ipv6Enabled,omitempty"`
   239  	// DefaultTagCategoryID is the tag category id that will be used as default, if users don't specify it on a cluster level,
   240  	// and they don't wish KKP to create default generated tag category, upon cluster creation.
   241  	DefaultTagCategoryID string `json:"defaultTagCategoryID,omitempty"`
   242  }
   243  
   244  type DatacenterSpecVMwareCloudDirector struct {
   245  	// Endpoint URL to use, including protocol, for example "https://vclouddirector.example.com".
   246  	URL string `json:"url"`
   247  	// If set to true, disables the TLS certificate check against the endpoint.
   248  	AllowInsecure bool `json:"allowInsecure,omitempty"`
   249  	// The default catalog which contains the VM templates.
   250  	DefaultCatalog string `json:"catalog,omitempty"`
   251  	// The name of the storage profile to use for disks attached to the VMs.
   252  	DefaultStorageProfile string `json:"storageProfile,omitempty"`
   253  	// A list of VM templates to use for a given operating system. You must
   254  	// define at least one template.
   255  	Templates ImageList `json:"templates"`
   256  }
   257  
   258  // DatacenterSpecAWS describes an AWS datacenter.
   259  type DatacenterSpecAWS struct {
   260  	// The AWS region to use, e.g. "us-east-1". For a list of available regions, see
   261  	// https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-regions-availability-zones.html
   262  	Region string `json:"region"`
   263  
   264  	// List of AMIs to use for a given operating system.
   265  	// This gets defaulted by querying for the latest AMI for the given distribution
   266  	// when machines are created, so under normal circumstances it is not necessary
   267  	// to define the AMIs statically.
   268  	Images ImageList `json:"images,omitempty"`
   269  }
   270  
   271  // DatacenterSpecBringYourOwn describes a datacenter our of bring your own nodes.
   272  type DatacenterSpecBringYourOwn struct {
   273  }
   274  
   275  // DatacenterSpecPacket describes a Packet datacenter.
   276  type DatacenterSpecPacket struct {
   277  	// The list of enabled facilities, for example "ams1", for a full list of available
   278  	// facilities see https://metal.equinix.com/developers/docs/locations/facilities/
   279  	Facilities []string `json:"facilities,omitempty"`
   280  	// Metros are facilities that are grouped together geographically and share capacity
   281  	// and networking features, see https://metal.equinix.com/developers/docs/locations/metros/
   282  	Metro string `json:"metro,omitempty"`
   283  }
   284  
   285  // DatacenterSpecGCP describes a GCP datacenter.
   286  type DatacenterSpecGCP struct {
   287  	// Region to use, for example "europe-west3", for a full list of regions see
   288  	// https://cloud.google.com/compute/docs/regions-zones/
   289  	Region string `json:"region"`
   290  	// List of enabled zones, for example [a, c]. See the link above for the available
   291  	// zones in your chosen region.
   292  	ZoneSuffixes []string `json:"zoneSuffixes"`
   293  
   294  	// Optional: Regional clusters spread their resources across multiple availability zones.
   295  	// Refer to the official documentation for more details on this:
   296  	// https://cloud.google.com/kubernetes-engine/docs/concepts/regional-clusters
   297  	Regional bool `json:"regional,omitempty"`
   298  }
   299  
   300  // DatacenterSpecFake describes a fake datacenter.
   301  type DatacenterSpecFake struct {
   302  	FakeProperty string `json:"fakeProperty,omitempty"`
   303  }
   304  
   305  // DatacenterSpecKubeVirt describes a kubevirt datacenter.
   306  type DatacenterSpecKubeVirt struct {
   307  	// +kubebuilder:validation:Enum=ClusterFirstWithHostNet;ClusterFirst;Default;None
   308  	// +kubebuilder:default=ClusterFirst
   309  
   310  	// DNSPolicy represents the dns policy for the pod. Valid values are 'ClusterFirstWithHostNet', 'ClusterFirst',
   311  	// 'Default' or 'None'. Defaults to "ClusterFirst". DNS parameters given in DNSConfig will be merged with the
   312  	// policy selected with DNSPolicy.
   313  	DNSPolicy string `json:"dnsPolicy,omitempty"`
   314  
   315  	// DNSConfig represents the DNS parameters of a pod. Parameters specified here will be merged to the generated DNS
   316  	// configuration based on DNSPolicy.
   317  	DNSConfig *corev1.PodDNSConfig `json:"dnsConfig,omitempty"`
   318  
   319  	// Optional: EnableDefaultNetworkPolicies enables deployment of default network policies like cluster isolation.
   320  	// Defaults to true.
   321  	EnableDefaultNetworkPolicies *bool `json:"enableDefaultNetworkPolicies,omitempty"`
   322  
   323  	// Optional: CustomNetworkPolicies allows to add some extra custom NetworkPolicies, that are deployed
   324  	// in the dedicated infra KubeVirt cluster. They are added to the defaults.
   325  	CustomNetworkPolicies []*CustomNetworkPolicy `json:"customNetworkPolicies,omitempty"`
   326  
   327  	// Images represents standard VM Image sources.
   328  	Images *KubeVirtImageSources `json:"images,omitempty"`
   329  
   330  	// Optional: InfraStorageClasses contains a list of KubeVirt infra cluster StorageClasses names
   331  	// that will be used to initialise StorageClasses in the tenant cluster.
   332  	// In the tenant cluster, the created StorageClass name will have as name:
   333  	// kubevirt-<infra-storageClass-name>
   334  	InfraStorageClasses []KubeVirtInfraStorageClass `json:"infraStorageClasses,omitempty"`
   335  }
   336  
   337  type KubeVirtInfraStorageClass struct {
   338  	Name string `json:"name"`
   339  	// Optional: IsDefaultClass. If true, the created StorageClass in the tenant cluster will be annotated with:
   340  	// storageclass.kubernetes.io/is-default-class : true
   341  	// If missing or false, annotation will be:
   342  	// storageclass.kubernetes.io/is-default-class : false
   343  	IsDefaultClass *bool `json:"isDefaultClass,omitempty"`
   344  }
   345  
   346  // CustomNetworkPolicy contains a name and the Spec of a NetworkPolicy.
   347  type CustomNetworkPolicy struct {
   348  	// Name is the name of the Custom Network Policy.
   349  	Name string `json:"name"`
   350  	// Spec is the Spec of the NetworkPolicy, using the standard type.
   351  	Spec networkingv1.NetworkPolicySpec `json:"spec"`
   352  }
   353  
   354  var (
   355  	SupportedKubeVirtOS = sets.New(
   356  		OperatingSystemCentOS,
   357  		OperatingSystemUbuntu,
   358  		OperatingSystemRHEL,
   359  		OperatingSystemFlatcar,
   360  		OperatingSystemRockyLinux,
   361  	)
   362  )
   363  
   364  // KubeVirtImageSources represents KubeVirt image sources.
   365  type KubeVirtImageSources struct {
   366  	// HTTP represents a http source.
   367  	HTTP *KubeVirtHTTPSource `json:"http,omitempty"`
   368  }
   369  
   370  // KubeVirtHTTPSource represents list of images and their versions that can be downloaded over HTTP.
   371  type KubeVirtHTTPSource struct {
   372  	// OperatingSystems represents list of supported operating-systems with their URLs.
   373  	OperatingSystems map[OperatingSystem]OSVersions `json:"operatingSystems"`
   374  }
   375  
   376  // DatacenterSpecNutanix describes a Nutanix datacenter.
   377  type DatacenterSpecNutanix struct {
   378  	// Endpoint to use for accessing Nutanix Prism Central. No protocol or port should be passed,
   379  	// for example "nutanix.example.com" or "10.0.0.1"
   380  	Endpoint string `json:"endpoint"`
   381  	// Optional: Port to use when connecting to the Nutanix Prism Central endpoint (defaults to 9440)
   382  	Port *int32 `json:"port,omitempty"`
   383  
   384  	// Optional: AllowInsecure allows to disable the TLS certificate check against the endpoint (defaults to false)
   385  	AllowInsecure bool `json:"allowInsecure,omitempty"`
   386  	// Images to use for each supported operating system
   387  	Images ImageList `json:"images"`
   388  }
   389  
   390  // DatacenterSpecAlibaba describes a alibaba datacenter.
   391  type DatacenterSpecAlibaba struct {
   392  	// Region to use, for a full list of regions see
   393  	// https://www.alibabacloud.com/help/doc-detail/40654.htm
   394  	Region string `json:"region"`
   395  }
   396  
   397  // DatacenterSpecAnexia describes a anexia datacenter.
   398  type DatacenterSpecAnexia struct {
   399  	// LocationID the location of the region
   400  	LocationID string `json:"locationID"`
   401  }
   402  
   403  // NodeSettings are node specific flags which can be configured on datacenter level.
   404  type NodeSettings struct {
   405  	// Optional: Proxy settings for the Nodes in this datacenter.
   406  	// Defaults to the Proxy settings of the seed.
   407  	ProxySettings `json:",inline"`
   408  	// Optional: These image registries will be configured as insecure
   409  	// on the container runtime.
   410  	InsecureRegistries []string `json:"insecureRegistries,omitempty"`
   411  	// Optional: These image registries will be configured as registry mirrors
   412  	// on the container runtime.
   413  	RegistryMirrors []string `json:"registryMirrors,omitempty"`
   414  	// Optional: Translates to --pod-infra-container-image on the kubelet.
   415  	// If not set, the kubelet will default it.
   416  	PauseImage string `json:"pauseImage,omitempty"`
   417  	// Optional: ContainerdRegistryMirrors configure registry mirrors endpoints. Can be used multiple times to specify multiple mirrors.
   418  	ContainerdRegistryMirrors *ContainerRuntimeContainerd `json:"containerdRegistryMirrors,omitempty"`
   419  }
   420  
   421  // ContainerRuntimeContainerd defines containerd container runtime registries configs.
   422  type ContainerRuntimeContainerd struct {
   423  	// A map of registries to use to render configs and mirrors for containerd registries
   424  	Registries map[string]ContainerdRegistry `json:"registries,omitempty"`
   425  }
   426  
   427  // ContainerdRegistry defines endpoints and security for given container registry.
   428  type ContainerdRegistry struct {
   429  	// List of registry mirrors to use
   430  	Mirrors []string `json:"mirrors,omitempty"`
   431  }
   432  
   433  // DatacenterStatus contains runtime information regarding the datacenter.
   434  type DatacenterStatus struct {
   435  	// +kubebuilder:default=0
   436  	// +kubebuilder:validation:Minimum:=0
   437  
   438  	// Clusters is the total number of user clusters that exist on this seed.
   439  	Clusters int `json:"clusters"`
   440  }
   441  
   442  // +kubebuilder:object:generate=true
   443  // +kubebuilder:object:root=true
   444  
   445  // DatacenterList is a list of datacenters.
   446  type DatacenterList struct {
   447  	metav1.TypeMeta `json:",inline"`
   448  	metav1.ListMeta `json:"metadata,omitempty"`
   449  
   450  	Items []Datacenter `json:"items"`
   451  }