sigs.k8s.io/cluster-api@v1.7.1/cmd/clusterctl/client/config/providers_client.go (about) 1 /* 2 Copyright 2019 The Kubernetes Authors. 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 config 18 19 import ( 20 "net/url" 21 "os" 22 "sort" 23 "strings" 24 25 "github.com/drone/envsubst/v2" 26 "github.com/pkg/errors" 27 "k8s.io/apimachinery/pkg/util/validation" 28 29 clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3" 30 ) 31 32 // core providers. 33 const ( 34 // ClusterAPIProviderName is the name for the core provider. 35 ClusterAPIProviderName = "cluster-api" 36 ) 37 38 // Infra providers. 39 const ( 40 AWSProviderName = "aws" 41 AzureProviderName = "azure" 42 BYOHProviderName = "byoh" 43 CloudStackProviderName = "cloudstack" 44 DockerProviderName = "docker" 45 DOProviderName = "digitalocean" 46 GCPProviderName = "gcp" 47 HetznerProviderName = "hetzner" 48 HivelocityProviderName = "hivelocity-hivelocity" 49 OutscaleProviderName = "outscale" 50 IBMCloudProviderName = "ibmcloud" 51 InMemoryProviderName = "in-memory" 52 Metal3ProviderName = "metal3" 53 NestedProviderName = "nested" 54 NutanixProviderName = "nutanix" 55 OCIProviderName = "oci" 56 OpenStackProviderName = "openstack" 57 PacketProviderName = "packet" 58 SideroProviderName = "sidero" 59 VCloudDirectorProviderName = "vcd" 60 VSphereProviderName = "vsphere" 61 MAASProviderName = "maas" 62 KubevirtProviderName = "kubevirt" 63 KubeKeyProviderName = "kubekey" 64 VclusterProviderName = "vcluster" 65 VirtinkProviderName = "virtink" 66 CoxEdgeProviderName = "coxedge" 67 ProxmoxProviderName = "proxmox" 68 K0smotronProviderName = "k0sproject-k0smotron" 69 ) 70 71 // Bootstrap providers. 72 const ( 73 KubeadmBootstrapProviderName = "kubeadm" 74 TalosBootstrapProviderName = "talos" 75 MicroK8sBootstrapProviderName = "microk8s" 76 OracleCloudNativeBootstrapProviderName = "ocne" 77 KubeKeyK3sBootstrapProviderName = "kubekey-k3s" 78 RKE2BootstrapProviderName = "rke2" 79 K0smotronBootstrapProviderName = "k0sproject-k0smotron" 80 ) 81 82 // ControlPlane providers. 83 const ( 84 KubeadmControlPlaneProviderName = "kubeadm" 85 TalosControlPlaneProviderName = "talos" 86 MicroK8sControlPlaneProviderName = "microk8s" 87 NestedControlPlaneProviderName = "nested" 88 OracleCloudNativeControlPlaneProviderName = "ocne" 89 KubeKeyK3sControlPlaneProviderName = "kubekey-k3s" 90 KamajiControlPlaneProviderName = "kamaji" 91 RKE2ControlPlaneProviderName = "rke2" 92 K0smotronControlPlaneProviderName = "k0sproject-k0smotron" 93 ) 94 95 // IPAM providers. 96 const ( 97 InClusterIPAMProviderName = "in-cluster" 98 ) 99 100 // Add-on providers. 101 const ( 102 HelmAddonProviderName = "helm" 103 ) 104 105 // Other. 106 const ( 107 // ProvidersConfigKey is a constant for finding provider configurations with the ProvidersClient. 108 ProvidersConfigKey = "providers" 109 ) 110 111 // ProvidersClient has methods to work with provider configurations. 112 type ProvidersClient interface { 113 // List returns all the provider configurations, including provider configurations hard-coded in clusterctl 114 // and user-defined provider configurations read from the clusterctl configuration file. 115 // In case of conflict, user-defined provider override the hard-coded configurations. 116 List() ([]Provider, error) 117 118 // Get returns the configuration for the provider with a given name/type. 119 // In case the name/type does not correspond to any existing provider, an error is returned. 120 Get(name string, providerType clusterctlv1.ProviderType) (Provider, error) 121 } 122 123 // providersClient implements ProvidersClient. 124 type providersClient struct { 125 reader Reader 126 } 127 128 // ensure providersClient implements ProvidersClient. 129 var _ ProvidersClient = &providersClient{} 130 131 func newProvidersClient(reader Reader) *providersClient { 132 return &providersClient{ 133 reader: reader, 134 } 135 } 136 137 func (p *providersClient) defaults() []Provider { 138 // clusterctl includes a predefined list of Cluster API providers sponsored by SIG-cluster-lifecycle to provide users the simplest 139 // out-of-box experience. This is an opt-in feature; other providers can be added by using the clusterctl configuration file. 140 141 // if you are a developer of a SIG-cluster-lifecycle project, you can send a PR to extend the following list. 142 143 defaults := []Provider{ 144 // cluster API core provider 145 &provider{ 146 name: ClusterAPIProviderName, 147 url: "https://github.com/kubernetes-sigs/cluster-api/releases/latest/core-components.yaml", 148 providerType: clusterctlv1.CoreProviderType, 149 }, 150 151 // Infrastructure providers 152 &provider{ 153 name: AWSProviderName, 154 url: "https://github.com/kubernetes-sigs/cluster-api-provider-aws/releases/latest/infrastructure-components.yaml", 155 providerType: clusterctlv1.InfrastructureProviderType, 156 }, 157 &provider{ 158 name: AzureProviderName, 159 url: "https://github.com/kubernetes-sigs/cluster-api-provider-azure/releases/latest/infrastructure-components.yaml", 160 providerType: clusterctlv1.InfrastructureProviderType, 161 }, 162 &provider{ 163 // NB. The Docker provider is not designed for production use and is intended for development environments only. 164 name: DockerProviderName, 165 url: "https://github.com/kubernetes-sigs/cluster-api/releases/latest/infrastructure-components-development.yaml", 166 providerType: clusterctlv1.InfrastructureProviderType, 167 }, 168 &provider{ 169 name: CloudStackProviderName, 170 url: "https://github.com/kubernetes-sigs/cluster-api-provider-cloudstack/releases/latest/infrastructure-components.yaml", 171 providerType: clusterctlv1.InfrastructureProviderType, 172 }, 173 &provider{ 174 name: DOProviderName, 175 url: "https://github.com/kubernetes-sigs/cluster-api-provider-digitalocean/releases/latest/infrastructure-components.yaml", 176 providerType: clusterctlv1.InfrastructureProviderType, 177 }, 178 &provider{ 179 name: GCPProviderName, 180 url: "https://github.com/kubernetes-sigs/cluster-api-provider-gcp/releases/latest/infrastructure-components.yaml", 181 providerType: clusterctlv1.InfrastructureProviderType, 182 }, 183 &provider{ 184 name: PacketProviderName, 185 url: "https://github.com/kubernetes-sigs/cluster-api-provider-packet/releases/latest/infrastructure-components.yaml", 186 providerType: clusterctlv1.InfrastructureProviderType, 187 }, 188 &provider{ 189 name: Metal3ProviderName, 190 url: "https://github.com/metal3-io/cluster-api-provider-metal3/releases/latest/infrastructure-components.yaml", 191 providerType: clusterctlv1.InfrastructureProviderType, 192 }, 193 &provider{ 194 name: NestedProviderName, 195 url: "https://github.com/kubernetes-sigs/cluster-api-provider-nested/releases/latest/infrastructure-components.yaml", 196 providerType: clusterctlv1.InfrastructureProviderType, 197 }, 198 &provider{ 199 name: OCIProviderName, 200 url: "https://github.com/oracle/cluster-api-provider-oci/releases/latest/infrastructure-components.yaml", 201 providerType: clusterctlv1.InfrastructureProviderType, 202 }, 203 &provider{ 204 name: OpenStackProviderName, 205 url: "https://github.com/kubernetes-sigs/cluster-api-provider-openstack/releases/latest/infrastructure-components.yaml", 206 providerType: clusterctlv1.InfrastructureProviderType, 207 }, 208 &provider{ 209 name: SideroProviderName, 210 url: "https://github.com/siderolabs/sidero/releases/latest/infrastructure-components.yaml", 211 providerType: clusterctlv1.InfrastructureProviderType, 212 }, 213 &provider{ 214 name: VCloudDirectorProviderName, 215 url: "https://github.com/vmware/cluster-api-provider-cloud-director/releases/latest/infrastructure-components.yaml", 216 providerType: clusterctlv1.InfrastructureProviderType, 217 }, 218 &provider{ 219 name: VSphereProviderName, 220 url: "https://github.com/kubernetes-sigs/cluster-api-provider-vsphere/releases/latest/infrastructure-components.yaml", 221 providerType: clusterctlv1.InfrastructureProviderType, 222 }, 223 &provider{ 224 name: MAASProviderName, 225 url: "https://github.com/spectrocloud/cluster-api-provider-maas/releases/latest/infrastructure-components.yaml", 226 providerType: clusterctlv1.InfrastructureProviderType, 227 }, 228 &provider{ 229 name: CoxEdgeProviderName, 230 url: "https://github.com/coxedge/cluster-api-provider-coxedge/releases/latest/infrastructure-components.yaml", 231 providerType: clusterctlv1.InfrastructureProviderType, 232 }, 233 &provider{ 234 name: BYOHProviderName, 235 url: "https://github.com/vmware-tanzu/cluster-api-provider-bringyourownhost/releases/latest/infrastructure-components.yaml", 236 providerType: clusterctlv1.InfrastructureProviderType, 237 }, 238 &provider{ 239 name: HetznerProviderName, 240 url: "https://github.com/syself/cluster-api-provider-hetzner/releases/latest/infrastructure-components.yaml", 241 providerType: clusterctlv1.InfrastructureProviderType, 242 }, 243 &provider{ 244 name: HivelocityProviderName, 245 url: "https://github.com/hivelocity/cluster-api-provider-hivelocity/releases/latest/infrastructure-components.yaml", 246 providerType: clusterctlv1.InfrastructureProviderType, 247 }, 248 &provider{ 249 name: OutscaleProviderName, 250 url: "https://github.com/outscale/cluster-api-provider-outscale/releases/latest/infrastructure-components.yaml", 251 providerType: clusterctlv1.InfrastructureProviderType, 252 }, 253 &provider{ 254 name: IBMCloudProviderName, 255 url: "https://github.com/kubernetes-sigs/cluster-api-provider-ibmcloud/releases/latest/infrastructure-components.yaml", 256 providerType: clusterctlv1.InfrastructureProviderType, 257 }, 258 &provider{ 259 name: InMemoryProviderName, 260 url: "https://github.com/kubernetes-sigs/cluster-api/releases/latest/infrastructure-components-in-memory-development.yaml", 261 providerType: clusterctlv1.InfrastructureProviderType, 262 }, 263 &provider{ 264 name: NutanixProviderName, 265 url: "https://github.com/nutanix-cloud-native/cluster-api-provider-nutanix/releases/latest/infrastructure-components.yaml", 266 providerType: clusterctlv1.InfrastructureProviderType, 267 }, 268 &provider{ 269 name: KubeKeyProviderName, 270 url: "https://github.com/kubesphere/kubekey/releases/latest/infrastructure-components.yaml", 271 providerType: clusterctlv1.InfrastructureProviderType, 272 }, 273 &provider{ 274 name: KubevirtProviderName, 275 url: "https://github.com/kubernetes-sigs/cluster-api-provider-kubevirt/releases/latest/infrastructure-components.yaml", 276 providerType: clusterctlv1.InfrastructureProviderType, 277 }, 278 &provider{ 279 name: VclusterProviderName, 280 url: "https://github.com/loft-sh/cluster-api-provider-vcluster/releases/latest/infrastructure-components.yaml", 281 providerType: clusterctlv1.InfrastructureProviderType, 282 }, 283 &provider{ 284 name: VirtinkProviderName, 285 url: "https://github.com/smartxworks/cluster-api-provider-virtink/releases/latest/infrastructure-components.yaml", 286 providerType: clusterctlv1.InfrastructureProviderType, 287 }, 288 &provider{ 289 name: ProxmoxProviderName, 290 url: "https://github.com/ionos-cloud/cluster-api-provider-proxmox/releases/latest/infrastructure-components.yaml", 291 providerType: clusterctlv1.InfrastructureProviderType, 292 }, 293 &provider{ 294 name: K0smotronProviderName, 295 url: "https://github.com/k0sproject/k0smotron/releases/latest/infrastructure-components.yaml", 296 providerType: clusterctlv1.InfrastructureProviderType, 297 }, 298 299 // Bootstrap providers 300 &provider{ 301 name: KubeadmBootstrapProviderName, 302 url: "https://github.com/kubernetes-sigs/cluster-api/releases/latest/bootstrap-components.yaml", 303 providerType: clusterctlv1.BootstrapProviderType, 304 }, 305 &provider{ 306 name: KubeKeyK3sBootstrapProviderName, 307 url: "https://github.com/kubesphere/kubekey/releases/latest/bootstrap-components.yaml", 308 providerType: clusterctlv1.BootstrapProviderType, 309 }, 310 &provider{ 311 name: TalosBootstrapProviderName, 312 url: "https://github.com/siderolabs/cluster-api-bootstrap-provider-talos/releases/latest/bootstrap-components.yaml", 313 providerType: clusterctlv1.BootstrapProviderType, 314 }, 315 &provider{ 316 name: MicroK8sBootstrapProviderName, 317 url: "https://github.com/canonical/cluster-api-bootstrap-provider-microk8s/releases/latest/bootstrap-components.yaml", 318 providerType: clusterctlv1.BootstrapProviderType, 319 }, 320 &provider{ 321 name: OracleCloudNativeBootstrapProviderName, 322 url: "https://github.com/verrazzano/cluster-api-provider-ocne/releases/latest/bootstrap-components.yaml", 323 providerType: clusterctlv1.BootstrapProviderType, 324 }, 325 &provider{ 326 name: RKE2BootstrapProviderName, 327 url: "https://github.com/rancher-sandbox/cluster-api-provider-rke2/releases/latest/bootstrap-components.yaml", 328 providerType: clusterctlv1.BootstrapProviderType, 329 }, 330 &provider{ 331 name: K0smotronBootstrapProviderName, 332 url: "https://github.com/k0sproject/k0smotron/releases/latest/bootstrap-components.yaml", 333 providerType: clusterctlv1.BootstrapProviderType, 334 }, 335 336 // ControlPlane providers 337 &provider{ 338 name: KubeadmControlPlaneProviderName, 339 url: "https://github.com/kubernetes-sigs/cluster-api/releases/latest/control-plane-components.yaml", 340 providerType: clusterctlv1.ControlPlaneProviderType, 341 }, 342 &provider{ 343 name: KubeKeyK3sControlPlaneProviderName, 344 url: "https://github.com/kubesphere/kubekey/releases/latest/control-plane-components.yaml", 345 providerType: clusterctlv1.ControlPlaneProviderType, 346 }, 347 &provider{ 348 name: TalosControlPlaneProviderName, 349 url: "https://github.com/siderolabs/cluster-api-control-plane-provider-talos/releases/latest/control-plane-components.yaml", 350 providerType: clusterctlv1.ControlPlaneProviderType, 351 }, 352 &provider{ 353 name: MicroK8sControlPlaneProviderName, 354 url: "https://github.com/canonical/cluster-api-control-plane-provider-microk8s/releases/latest/control-plane-components.yaml", 355 providerType: clusterctlv1.ControlPlaneProviderType, 356 }, 357 &provider{ 358 name: NestedControlPlaneProviderName, 359 url: "https://github.com/kubernetes-sigs/cluster-api-provider-nested/releases/latest/control-plane-components.yaml", 360 providerType: clusterctlv1.ControlPlaneProviderType, 361 }, 362 &provider{ 363 name: OracleCloudNativeControlPlaneProviderName, 364 url: "https://github.com/verrazzano/cluster-api-provider-ocne/releases/latest/control-plane-components.yaml", 365 providerType: clusterctlv1.ControlPlaneProviderType, 366 }, 367 &provider{ 368 name: KamajiControlPlaneProviderName, 369 url: "https://github.com/clastix/cluster-api-control-plane-provider-kamaji/releases/latest/control-plane-components.yaml", 370 providerType: clusterctlv1.ControlPlaneProviderType, 371 }, 372 &provider{ 373 name: RKE2ControlPlaneProviderName, 374 url: "https://github.com/rancher-sandbox/cluster-api-provider-rke2/releases/latest/control-plane-components.yaml", 375 providerType: clusterctlv1.ControlPlaneProviderType, 376 }, 377 &provider{ 378 name: K0smotronControlPlaneProviderName, 379 url: "https://github.com/k0sproject/k0smotron/releases/latest/control-plane-components.yaml", 380 providerType: clusterctlv1.ControlPlaneProviderType, 381 }, 382 383 // IPAM providers 384 &provider{ 385 name: InClusterIPAMProviderName, 386 url: "https://github.com/kubernetes-sigs/cluster-api-ipam-provider-in-cluster/releases/latest/ipam-components.yaml", 387 providerType: clusterctlv1.IPAMProviderType, 388 }, 389 390 // Add-on providers 391 &provider{ 392 name: HelmAddonProviderName, 393 url: "https://github.com/kubernetes-sigs/cluster-api-addon-provider-helm/releases/latest/addon-components.yaml", 394 providerType: clusterctlv1.AddonProviderType, 395 }, 396 } 397 398 return defaults 399 } 400 401 // configProvider mirrors config.Provider interface and allows serialization of the corresponding info. 402 type configProvider struct { 403 Name string `json:"name,omitempty"` 404 URL string `json:"url,omitempty"` 405 Type clusterctlv1.ProviderType `json:"type,omitempty"` 406 } 407 408 func (p *providersClient) List() ([]Provider, error) { 409 // Creates a maps with all the defaults provider configurations 410 providers := p.defaults() 411 412 // Gets user defined provider configurations, validate them, and merges with 413 // hard-coded configurations handling conflicts (user defined take precedence on hard-coded) 414 415 userDefinedProviders := []configProvider{} 416 if err := p.reader.UnmarshalKey(ProvidersConfigKey, &userDefinedProviders); err != nil { 417 return nil, errors.Wrap(err, "failed to unmarshal providers from the clusterctl configuration file") 418 } 419 420 for _, u := range userDefinedProviders { 421 var err error 422 u.URL, err = envsubst.Eval(u.URL, os.Getenv) 423 if err != nil { 424 return nil, errors.Wrapf(err, "unable to evaluate url: %q", u.URL) 425 } 426 427 provider := NewProvider(u.Name, u.URL, u.Type) 428 if err := validateProvider(provider); err != nil { 429 return nil, errors.Wrapf(err, "error validating configuration for the %s with name %s. Please fix the providers value in clusterctl configuration file", provider.Type(), provider.Name()) 430 } 431 432 override := false 433 for i := range providers { 434 if providers[i].SameAs(provider) { 435 providers[i] = provider 436 override = true 437 } 438 } 439 440 if !override { 441 providers = append(providers, provider) 442 } 443 } 444 445 // ensure provider configurations are consistently sorted 446 sort.Slice(providers, func(i, j int) bool { 447 return providers[i].Less(providers[j]) 448 }) 449 450 return providers, nil 451 } 452 453 func (p *providersClient) Get(name string, providerType clusterctlv1.ProviderType) (Provider, error) { 454 l, err := p.List() 455 if err != nil { 456 return nil, err 457 } 458 459 provider := NewProvider(name, "", providerType) // NB. Having the url empty is fine because the url is not considered by SameAs. 460 for _, r := range l { 461 if r.SameAs(provider) { 462 return r, nil 463 } 464 } 465 466 return nil, errors.Errorf("failed to get configuration for the %s with name %s. Please check the provider name and/or add configuration for new providers using the .clusterctl config file", providerType, name) 467 } 468 469 func validateProvider(r Provider) error { 470 if r.Name() == "" { 471 return errors.New("name value cannot be empty") 472 } 473 474 if (r.Name() == ClusterAPIProviderName) != (r.Type() == clusterctlv1.CoreProviderType) { 475 return errors.Errorf("name %s must be used with the %s type (name: %s, type: %s)", ClusterAPIProviderName, clusterctlv1.CoreProviderType, r.Name(), r.Type()) 476 } 477 478 if errMsgs := validation.IsDNS1123Subdomain(r.Name()); len(errMsgs) != 0 { 479 return errors.Errorf("invalid provider name: %s", strings.Join(errMsgs, "; ")) 480 } 481 if r.URL() == "" { 482 return errors.New("provider URL value cannot be empty") 483 } 484 485 if _, err := url.Parse(r.URL()); err != nil { 486 return errors.Wrap(err, "error parsing provider URL") 487 } 488 489 switch r.Type() { 490 case clusterctlv1.CoreProviderType, 491 clusterctlv1.BootstrapProviderType, 492 clusterctlv1.InfrastructureProviderType, 493 clusterctlv1.ControlPlaneProviderType, 494 clusterctlv1.IPAMProviderType, 495 clusterctlv1.RuntimeExtensionProviderType, 496 clusterctlv1.AddonProviderType: 497 break 498 default: 499 return errors.Errorf("invalid provider type. Allowed values are [%s, %s, %s, %s, %s, %s, %s]", 500 clusterctlv1.CoreProviderType, 501 clusterctlv1.BootstrapProviderType, 502 clusterctlv1.InfrastructureProviderType, 503 clusterctlv1.ControlPlaneProviderType, 504 clusterctlv1.IPAMProviderType, 505 clusterctlv1.RuntimeExtensionProviderType, 506 clusterctlv1.AddonProviderType) 507 } 508 return nil 509 }