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