diff --git a/pkg/apis/kops/validation/legacy.go b/pkg/apis/kops/validation/legacy.go index f8fd19360e..8cb96ff81d 100644 --- a/pkg/apis/kops/validation/legacy.go +++ b/pkg/apis/kops/validation/legacy.go @@ -249,28 +249,40 @@ func ValidateCluster(c *kops.Cluster, strict bool) *field.Error { // Check CloudProvider { - cloudProvider := c.Spec.CloudProvider - if cloudProvider == "" { - return field.Required(fieldSpec.Child("CloudProvider"), "") + var k8sCloudProvider string + switch kops.CloudProviderID(c.Spec.CloudProvider) { + case kops.CloudProviderAWS: + k8sCloudProvider = "aws" + case kops.CloudProviderGCE: + k8sCloudProvider = "gce" + case kops.CloudProviderDO: + k8sCloudProvider = "external" + case kops.CloudProviderVSphere: + k8sCloudProvider = "vsphere" + case kops.CloudProviderBareMetal: + k8sCloudProvider = "" + default: + return field.Invalid(fieldSpec.Child("CloudProvider"), c.Spec.CloudProvider, "unknown cloudprovider") } + if c.Spec.Kubelet != nil && (strict || c.Spec.Kubelet.CloudProvider != "") { - if cloudProvider != c.Spec.Kubelet.CloudProvider && c.Spec.Kubelet.CloudProvider != "external" { + if k8sCloudProvider != c.Spec.Kubelet.CloudProvider { return field.Invalid(fieldSpec.Child("Kubelet", "CloudProvider"), c.Spec.Kubelet.CloudProvider, "Did not match cluster CloudProvider") } } if c.Spec.MasterKubelet != nil && (strict || c.Spec.MasterKubelet.CloudProvider != "") { - if cloudProvider != c.Spec.MasterKubelet.CloudProvider && c.Spec.MasterKubelet.CloudProvider != "external" { + if k8sCloudProvider != c.Spec.MasterKubelet.CloudProvider { return field.Invalid(fieldSpec.Child("MasterKubelet", "CloudProvider"), c.Spec.MasterKubelet.CloudProvider, "Did not match cluster CloudProvider") } } if c.Spec.KubeAPIServer != nil && (strict || c.Spec.KubeAPIServer.CloudProvider != "") { - if cloudProvider != c.Spec.KubeAPIServer.CloudProvider && c.Spec.KubeAPIServer.CloudProvider != "external" { + if k8sCloudProvider != c.Spec.KubeAPIServer.CloudProvider { return field.Invalid(fieldSpec.Child("KubeAPIServer", "CloudProvider"), c.Spec.KubeAPIServer.CloudProvider, "Did not match cluster CloudProvider") } } if c.Spec.KubeControllerManager != nil && (strict || c.Spec.KubeControllerManager.CloudProvider != "") { - if cloudProvider != c.Spec.KubeControllerManager.CloudProvider && c.Spec.KubeControllerManager.CloudProvider != "external" { + if k8sCloudProvider != c.Spec.KubeControllerManager.CloudProvider { return field.Invalid(fieldSpec.Child("KubeControllerManager", "CloudProvider"), c.Spec.KubeControllerManager.CloudProvider, "Did not match cluster CloudProvider") } } diff --git a/pkg/model/components/apiserver.go b/pkg/model/components/apiserver.go index a4aec7a0c1..2ad1a5db5e 100644 --- a/pkg/model/components/apiserver.go +++ b/pkg/model/components/apiserver.go @@ -109,8 +109,10 @@ func (b *KubeAPIServerOptionsBuilder) BuildOptions(o interface{}) error { c.CloudProvider = "external" case kops.CloudProviderVSphere: c.CloudProvider = "vsphere" + case kops.CloudProviderBareMetal: + // for baremetal, we don't specify a cloudprovider to apiserver default: - return fmt.Errorf("unknown cloud provider %q", clusterSpec.CloudProvider) + return fmt.Errorf("unknown cloudprovider %q", clusterSpec.CloudProvider) } c.LogLevel = 2 diff --git a/pkg/model/components/kubecontrollermanager.go b/pkg/model/components/kubecontrollermanager.go index 965af3ff7a..4c477a5769 100644 --- a/pkg/model/components/kubecontrollermanager.go +++ b/pkg/model/components/kubecontrollermanager.go @@ -110,8 +110,11 @@ func (b *KubeControllerManagerOptionsBuilder) BuildOptions(o interface{}) error case kops.CloudProviderVSphere: kcm.CloudProvider = "vsphere" + case kops.CloudProviderBareMetal: + // No cloudprovider + default: - return fmt.Errorf("unknown cloud provider %q", clusterSpec.CloudProvider) + return fmt.Errorf("unknown cloudprovider %q", clusterSpec.CloudProvider) } if kcm.Master == "" { diff --git a/pkg/model/master_volumes.go b/pkg/model/master_volumes.go index e6b1183c63..303f252521 100644 --- a/pkg/model/master_volumes.go +++ b/pkg/model/master_volumes.go @@ -21,6 +21,7 @@ import ( "sort" "strings" + "github.com/golang/glog" "k8s.io/kops/pkg/apis/kops" "k8s.io/kops/upup/pkg/fi" "k8s.io/kops/upup/pkg/fi/cloudup/awstasks" @@ -95,6 +96,8 @@ func (b *MasterVolumeBuilder) Build(c *fi.ModelBuilderContext) error { b.addGCEVolume(c, name, volumeSize, subnet, etcd, m, allMembers) case kops.CloudProviderVSphere: b.addVSphereVolume(c, name, volumeSize, subnet, etcd, m, allMembers) + case kops.CloudProviderBareMetal: + glog.Fatalf("BareMetal not implemented") default: return fmt.Errorf("unknown cloudprovider %q", b.Cluster.Spec.CloudProvider) } diff --git a/upup/pkg/fi/cloudup/apply_cluster.go b/upup/pkg/fi/cloudup/apply_cluster.go index 1ab6561183..e4a9c4f11c 100644 --- a/upup/pkg/fi/cloudup/apply_cluster.go +++ b/upup/pkg/fi/cloudup/apply_cluster.go @@ -67,6 +67,8 @@ const ( ) var ( + // AlphaAllowBareMetal is a feature flag that gates BareMetal support while it is alpha + AlphaAllowBareMetal = featureflag.New("AlphaAllowBareMetal", featureflag.Bool(false)) // AlphaAllowDO is a feature flag that gates DigitalOcean support while it is alpha AlphaAllowDO = featureflag.New("AlphaAllowDO", featureflag.Bool(false)) // AlphaAllowGCE is a feature flag that gates GCE support while it is alpha @@ -409,6 +411,15 @@ func (c *ApplyClusterCmd) Run() error { }) } + case kops.CloudProviderBareMetal: + { + if !AlphaAllowBareMetal.Enabled() { + return fmt.Errorf("BareMetal support is currently (very) alpha and is feature-gated. export KOPS_FEATURE_FLAGS=AlphaAllowBareMetal to enable it") + } + + // No additional tasks (yet) + } + default: return fmt.Errorf("unknown CloudProvider %q", cluster.Spec.CloudProvider) } diff --git a/upup/pkg/fi/cloudup/tagbuilder.go b/upup/pkg/fi/cloudup/tagbuilder.go index 95c0cf66da..0346732ba6 100644 --- a/upup/pkg/fi/cloudup/tagbuilder.go +++ b/upup/pkg/fi/cloudup/tagbuilder.go @@ -56,25 +56,28 @@ func buildCloudupTags(cluster *api.Cluster) (sets.String, error) { return nil, fmt.Errorf("no networking mode set") } - switch cluster.Spec.CloudProvider { - case "gce": + switch api.CloudProviderID(cluster.Spec.CloudProvider) { + case api.CloudProviderGCE: { tags.Insert("_gce") } - case "aws": + case api.CloudProviderAWS: { tags.Insert("_aws") } - case "digitalocean": + case api.CloudProviderDO: { tags.Insert("_do") } - case "vsphere": + case api.CloudProviderVSphere: { tags.Insert("_vsphere") } + case api.CloudProviderBareMetal: + // No tags + default: return nil, fmt.Errorf("unknown CloudProvider %q", cluster.Spec.CloudProvider) } diff --git a/upup/pkg/fi/cloudup/utils.go b/upup/pkg/fi/cloudup/utils.go index 1088220989..0ad8d2d305 100644 --- a/upup/pkg/fi/cloudup/utils.go +++ b/upup/pkg/fi/cloudup/utils.go @@ -37,8 +37,8 @@ func BuildCloud(cluster *kops.Cluster) (fi.Cloud, error) { region := "" project := "" - switch cluster.Spec.CloudProvider { - case "gce": + switch kops.CloudProviderID(cluster.Spec.CloudProvider) { + case kops.CloudProviderGCE: { nodeZones := make(map[string]bool) for _, subnet := range cluster.Spec.Subnets { @@ -71,7 +71,7 @@ func BuildCloud(cluster *kops.Cluster) (fi.Cloud, error) { cloud = gceCloud } - case "aws": + case kops.CloudProviderAWS: { region, err := awsup.FindRegion(cluster) if err != nil { @@ -100,7 +100,7 @@ func BuildCloud(cluster *kops.Cluster) (fi.Cloud, error) { } cloud = awsCloud } - case "vsphere": + case kops.CloudProviderVSphere: { vsphereCloud, err := vsphere.NewVSphereCloud(&cluster.Spec) if err != nil { @@ -108,7 +108,7 @@ func BuildCloud(cluster *kops.Cluster) (fi.Cloud, error) { } cloud = vsphereCloud } - case "digitalocean": + case kops.CloudProviderDO: { // for development purposes we're going to assume // single region setups for DO. Reconsider this logic @@ -122,7 +122,7 @@ func BuildCloud(cluster *kops.Cluster) (fi.Cloud, error) { cloud = doCloud } - case string(kops.CloudProviderBareMetal): + case kops.CloudProviderBareMetal: { // TODO: Allow dns provider to be specified dns, err := dnsprovider.GetDnsProvider(route53.ProviderName, nil)