mirror of https://github.com/kubernetes/kops.git
Merge pull request #9490 from johngmyers/newcluster-4
Move more cluster creation code to NewCluster()
This commit is contained in:
commit
222756b35d
|
@ -73,7 +73,6 @@ go_library(
|
||||||
"//pkg/instancegroups:go_default_library",
|
"//pkg/instancegroups:go_default_library",
|
||||||
"//pkg/kopscodecs:go_default_library",
|
"//pkg/kopscodecs:go_default_library",
|
||||||
"//pkg/kubeconfig:go_default_library",
|
"//pkg/kubeconfig:go_default_library",
|
||||||
"//pkg/model/components:go_default_library",
|
|
||||||
"//pkg/pki:go_default_library",
|
"//pkg/pki:go_default_library",
|
||||||
"//pkg/pretty:go_default_library",
|
"//pkg/pretty:go_default_library",
|
||||||
"//pkg/resources:go_default_library",
|
"//pkg/resources:go_default_library",
|
||||||
|
@ -85,8 +84,6 @@ go_library(
|
||||||
"//upup/pkg/fi:go_default_library",
|
"//upup/pkg/fi:go_default_library",
|
||||||
"//upup/pkg/fi/cloudup:go_default_library",
|
"//upup/pkg/fi/cloudup:go_default_library",
|
||||||
"//upup/pkg/fi/cloudup/awsup:go_default_library",
|
"//upup/pkg/fi/cloudup/awsup:go_default_library",
|
||||||
"//upup/pkg/fi/cloudup/gce:go_default_library",
|
|
||||||
"//upup/pkg/fi/cloudup/openstack:go_default_library",
|
|
||||||
"//upup/pkg/fi/utils:go_default_library",
|
"//upup/pkg/fi/utils:go_default_library",
|
||||||
"//upup/pkg/kutil:go_default_library",
|
"//upup/pkg/kutil:go_default_library",
|
||||||
"//util/pkg/tables:go_default_library",
|
"//util/pkg/tables:go_default_library",
|
||||||
|
|
|
@ -26,27 +26,20 @@ import (
|
||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/blang/semver/v4"
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
"k8s.io/apimachinery/pkg/runtime"
|
||||||
"k8s.io/apimachinery/pkg/util/validation/field"
|
|
||||||
"k8s.io/klog"
|
"k8s.io/klog"
|
||||||
"k8s.io/kops/cmd/kops/util"
|
"k8s.io/kops/cmd/kops/util"
|
||||||
api "k8s.io/kops/pkg/apis/kops"
|
api "k8s.io/kops/pkg/apis/kops"
|
||||||
"k8s.io/kops/pkg/apis/kops/registry"
|
"k8s.io/kops/pkg/apis/kops/registry"
|
||||||
version "k8s.io/kops/pkg/apis/kops/util"
|
|
||||||
"k8s.io/kops/pkg/apis/kops/validation"
|
"k8s.io/kops/pkg/apis/kops/validation"
|
||||||
"k8s.io/kops/pkg/assets"
|
"k8s.io/kops/pkg/assets"
|
||||||
"k8s.io/kops/pkg/commands"
|
"k8s.io/kops/pkg/commands"
|
||||||
"k8s.io/kops/pkg/dns"
|
"k8s.io/kops/pkg/dns"
|
||||||
"k8s.io/kops/pkg/featureflag"
|
"k8s.io/kops/pkg/featureflag"
|
||||||
"k8s.io/kops/pkg/model/components"
|
|
||||||
"k8s.io/kops/upup/pkg/fi"
|
"k8s.io/kops/upup/pkg/fi"
|
||||||
"k8s.io/kops/upup/pkg/fi/cloudup"
|
"k8s.io/kops/upup/pkg/fi/cloudup"
|
||||||
"k8s.io/kops/upup/pkg/fi/cloudup/awsup"
|
|
||||||
"k8s.io/kops/upup/pkg/fi/cloudup/gce"
|
|
||||||
"k8s.io/kops/upup/pkg/fi/cloudup/openstack"
|
|
||||||
"k8s.io/kops/upup/pkg/fi/utils"
|
"k8s.io/kops/upup/pkg/fi/utils"
|
||||||
"k8s.io/kubectl/pkg/util/i18n"
|
"k8s.io/kubectl/pkg/util/i18n"
|
||||||
"k8s.io/kubectl/pkg/util/templates"
|
"k8s.io/kubectl/pkg/util/templates"
|
||||||
|
@ -60,20 +53,16 @@ type CreateClusterOptions struct {
|
||||||
MasterSize string
|
MasterSize string
|
||||||
MasterVolumeSize int32
|
MasterVolumeSize int32
|
||||||
NodeVolumeSize int32
|
NodeVolumeSize int32
|
||||||
Project string
|
|
||||||
KubernetesVersion string
|
|
||||||
ContainerRuntime string
|
ContainerRuntime string
|
||||||
OutDir string
|
OutDir string
|
||||||
Image string
|
Image string
|
||||||
NodeImage string
|
NodeImage string
|
||||||
MasterImage string
|
MasterImage string
|
||||||
UtilitySubnetIDs []string
|
|
||||||
DisableSubnetTags bool
|
DisableSubnetTags bool
|
||||||
NetworkCIDR string
|
NetworkCIDR string
|
||||||
DNSZone string
|
DNSZone string
|
||||||
AdminAccess []string
|
AdminAccess []string
|
||||||
SSHAccess []string
|
SSHAccess []string
|
||||||
Networking string
|
|
||||||
NodeSecurityGroups []string
|
NodeSecurityGroups []string
|
||||||
MasterSecurityGroups []string
|
MasterSecurityGroups []string
|
||||||
AssociatePublicIP *bool
|
AssociatePublicIP *bool
|
||||||
|
@ -84,15 +73,6 @@ type CreateClusterOptions struct {
|
||||||
// Overrides allows settings values direct in the spec
|
// Overrides allows settings values direct in the spec
|
||||||
Overrides []string
|
Overrides []string
|
||||||
|
|
||||||
// The network topology to use
|
|
||||||
Topology string
|
|
||||||
|
|
||||||
// The DNS type to use (public/private)
|
|
||||||
DNSType string
|
|
||||||
|
|
||||||
// Enable/Disable Bastion Host complete setup
|
|
||||||
Bastion bool
|
|
||||||
|
|
||||||
// Specify tags for AWS instance groups
|
// Specify tags for AWS instance groups
|
||||||
CloudLabels string
|
CloudLabels string
|
||||||
|
|
||||||
|
@ -109,15 +89,8 @@ type CreateClusterOptions struct {
|
||||||
// Allow custom public master name
|
// Allow custom public master name
|
||||||
MasterPublicName string
|
MasterPublicName string
|
||||||
|
|
||||||
// Spotinst options
|
|
||||||
SpotinstProduct string
|
|
||||||
SpotinstOrientation string
|
|
||||||
|
|
||||||
OpenstackNetworkID string
|
OpenstackNetworkID string
|
||||||
|
|
||||||
// GCEServiceAccount specifies the service account with which the GCE VM runs
|
|
||||||
GCEServiceAccount string
|
|
||||||
|
|
||||||
// DryRun mode output a cluster manifest of Output type.
|
// DryRun mode output a cluster manifest of Output type.
|
||||||
DryRun bool
|
DryRun bool
|
||||||
// Output type during a DryRun
|
// Output type during a DryRun
|
||||||
|
@ -129,10 +102,6 @@ func (o *CreateClusterOptions) InitDefaults() {
|
||||||
|
|
||||||
o.Yes = false
|
o.Yes = false
|
||||||
o.Target = cloudup.TargetDirect
|
o.Target = cloudup.TargetDirect
|
||||||
o.Networking = "kubenet"
|
|
||||||
o.Topology = api.TopologyPublic
|
|
||||||
o.DNSType = string(api.DNSTypePublic)
|
|
||||||
o.Bastion = false
|
|
||||||
|
|
||||||
// Default to open API & SSH access
|
// Default to open API & SSH access
|
||||||
o.AdminAccess = []string{"0.0.0.0/0"}
|
o.AdminAccess = []string{"0.0.0.0/0"}
|
||||||
|
@ -508,265 +477,23 @@ func RunCreateCluster(ctx context.Context, f *util.Factory, out io.Writer, c *Cr
|
||||||
cluster.Spec.DNSZone = c.DNSZone
|
cluster.Spec.DNSZone = c.DNSZone
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: push more of the following logic into cloudup.NewCluster()
|
|
||||||
channel := clusterResult.Channel
|
|
||||||
allZones := clusterResult.AllZones
|
|
||||||
|
|
||||||
if c.CloudProvider != "" {
|
|
||||||
if featureflag.Spotinst.Enabled() {
|
|
||||||
if cluster.Spec.CloudConfig == nil {
|
|
||||||
cluster.Spec.CloudConfig = &api.CloudConfiguration{}
|
|
||||||
}
|
|
||||||
if c.SpotinstProduct != "" {
|
|
||||||
cluster.Spec.CloudConfig.SpotinstProduct = fi.String(c.SpotinstProduct)
|
|
||||||
}
|
|
||||||
if c.SpotinstOrientation != "" {
|
|
||||||
cluster.Spec.CloudConfig.SpotinstOrientation = fi.String(c.SpotinstOrientation)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Populate project
|
|
||||||
if c.Project != "" {
|
|
||||||
cluster.Spec.Project = c.Project
|
|
||||||
}
|
|
||||||
if api.CloudProviderID(cluster.Spec.CloudProvider) == api.CloudProviderGCE {
|
|
||||||
if cluster.Spec.CloudConfig == nil {
|
|
||||||
cluster.Spec.CloudConfig = &api.CloudConfiguration{}
|
|
||||||
}
|
|
||||||
if cluster.Spec.Project == "" {
|
|
||||||
project, err := gce.DefaultProject()
|
|
||||||
if err != nil {
|
|
||||||
klog.Warningf("unable to get default google cloud project: %v", err)
|
|
||||||
} else if project == "" {
|
|
||||||
klog.Warningf("default google cloud project not set (try `gcloud config set project <name>`")
|
|
||||||
} else {
|
|
||||||
klog.Infof("using google cloud project: %s", project)
|
|
||||||
}
|
|
||||||
cluster.Spec.Project = project
|
|
||||||
}
|
|
||||||
if c.GCEServiceAccount != "" {
|
|
||||||
klog.Infof("VMs will be configured to use specified Service Account: %v", c.GCEServiceAccount)
|
|
||||||
cluster.Spec.CloudConfig.GCEServiceAccount = c.GCEServiceAccount
|
|
||||||
} else {
|
|
||||||
klog.Warning("VMs will be configured to use the GCE default compute Service Account! This is an anti-pattern")
|
|
||||||
klog.Warning("Use a pre-created Service Account with the flag: --gce-service-account=account@projectname.iam.gserviceaccount.com")
|
|
||||||
cluster.Spec.CloudConfig.GCEServiceAccount = "default"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.KubernetesVersion != "" {
|
|
||||||
cluster.Spec.KubernetesVersion = c.KubernetesVersion
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.ContainerRuntime != "" {
|
if c.ContainerRuntime != "" {
|
||||||
cluster.Spec.ContainerRuntime = c.ContainerRuntime
|
cluster.Spec.ContainerRuntime = c.ContainerRuntime
|
||||||
}
|
}
|
||||||
|
|
||||||
cluster.Spec.Networking = &api.NetworkingSpec{}
|
|
||||||
switch c.Networking {
|
|
||||||
case "kubenet":
|
|
||||||
cluster.Spec.Networking.Kubenet = &api.KubenetNetworkingSpec{}
|
|
||||||
case "external":
|
|
||||||
cluster.Spec.Networking.External = &api.ExternalNetworkingSpec{}
|
|
||||||
case "cni":
|
|
||||||
cluster.Spec.Networking.CNI = &api.CNINetworkingSpec{}
|
|
||||||
case "kopeio-vxlan", "kopeio":
|
|
||||||
cluster.Spec.Networking.Kopeio = &api.KopeioNetworkingSpec{}
|
|
||||||
case "weave":
|
|
||||||
cluster.Spec.Networking.Weave = &api.WeaveNetworkingSpec{}
|
|
||||||
|
|
||||||
if cluster.Spec.CloudProvider == "aws" {
|
|
||||||
// AWS supports "jumbo frames" of 9001 bytes and weave adds up to 87 bytes overhead
|
|
||||||
// sets the default to the largest number that leaves enough overhead and is divisible by 4
|
|
||||||
jumboFrameMTUSize := int32(8912)
|
|
||||||
cluster.Spec.Networking.Weave.MTU = &jumboFrameMTUSize
|
|
||||||
}
|
|
||||||
case "flannel", "flannel-vxlan":
|
|
||||||
cluster.Spec.Networking.Flannel = &api.FlannelNetworkingSpec{
|
|
||||||
Backend: "vxlan",
|
|
||||||
}
|
|
||||||
case "flannel-udp":
|
|
||||||
klog.Warningf("flannel UDP mode is not recommended; consider flannel-vxlan instead")
|
|
||||||
cluster.Spec.Networking.Flannel = &api.FlannelNetworkingSpec{
|
|
||||||
Backend: "udp",
|
|
||||||
}
|
|
||||||
case "calico":
|
|
||||||
cluster.Spec.Networking.Calico = &api.CalicoNetworkingSpec{
|
|
||||||
MajorVersion: "v3",
|
|
||||||
}
|
|
||||||
// Validate to check if etcd clusters have an acceptable version
|
|
||||||
if errList := validation.ValidateEtcdVersionForCalicoV3(cluster.Spec.EtcdClusters[0], cluster.Spec.Networking.Calico.MajorVersion, field.NewPath("spec", "networking", "calico")); len(errList) != 0 {
|
|
||||||
|
|
||||||
// This is not a special version but simply of the 3 series
|
|
||||||
for _, etcd := range cluster.Spec.EtcdClusters {
|
|
||||||
etcd.Version = components.DefaultEtcd3Version_1_11
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case "canal":
|
|
||||||
cluster.Spec.Networking.Canal = &api.CanalNetworkingSpec{}
|
|
||||||
case "kube-router":
|
|
||||||
cluster.Spec.Networking.Kuberouter = &api.KuberouterNetworkingSpec{}
|
|
||||||
if cluster.Spec.KubeProxy == nil {
|
|
||||||
cluster.Spec.KubeProxy = &api.KubeProxyConfig{}
|
|
||||||
}
|
|
||||||
enabled := false
|
|
||||||
cluster.Spec.KubeProxy.Enabled = &enabled
|
|
||||||
case "amazonvpc", "amazon-vpc-routed-eni":
|
|
||||||
cluster.Spec.Networking.AmazonVPC = &api.AmazonVPCNetworkingSpec{}
|
|
||||||
case "cilium":
|
|
||||||
cilium := &api.CiliumNetworkingSpec{}
|
|
||||||
cluster.Spec.Networking.Cilium = cilium
|
|
||||||
nodeport := false
|
|
||||||
if c.KubernetesVersion == "" {
|
|
||||||
nodeport = true
|
|
||||||
} else {
|
|
||||||
k8sVersion, err := semver.ParseTolerant(c.KubernetesVersion)
|
|
||||||
if err == nil {
|
|
||||||
if version.IsKubernetesGTE("1.12", k8sVersion) {
|
|
||||||
nodeport = true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if nodeport {
|
|
||||||
cilium.EnableNodePort = true
|
|
||||||
if cluster.Spec.KubeProxy == nil {
|
|
||||||
cluster.Spec.KubeProxy = &api.KubeProxyConfig{}
|
|
||||||
}
|
|
||||||
enabled := false
|
|
||||||
cluster.Spec.KubeProxy.Enabled = &enabled
|
|
||||||
}
|
|
||||||
case "lyftvpc":
|
|
||||||
cluster.Spec.Networking.LyftVPC = &api.LyftVPCNetworkingSpec{}
|
|
||||||
case "gce":
|
|
||||||
cluster.Spec.Networking.GCE = &api.GCENetworkingSpec{}
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unknown networking mode %q", c.Networking)
|
|
||||||
}
|
|
||||||
|
|
||||||
klog.V(4).Infof("networking mode=%s => %s", c.Networking, fi.DebugAsJsonString(cluster.Spec.Networking))
|
|
||||||
|
|
||||||
if c.NetworkCIDR != "" {
|
if c.NetworkCIDR != "" {
|
||||||
cluster.Spec.NetworkCIDR = c.NetworkCIDR
|
cluster.Spec.NetworkCIDR = c.NetworkCIDR
|
||||||
}
|
}
|
||||||
|
|
||||||
// Network Topology
|
|
||||||
if c.Topology == "" {
|
|
||||||
// The flag default should have set this, but we might be being called as a library
|
|
||||||
klog.Infof("Empty topology. Defaulting to public topology")
|
|
||||||
c.Topology = api.TopologyPublic
|
|
||||||
}
|
|
||||||
|
|
||||||
cluster.Spec.DisableSubnetTags = c.DisableSubnetTags
|
cluster.Spec.DisableSubnetTags = c.DisableSubnetTags
|
||||||
|
|
||||||
switch c.Topology {
|
|
||||||
case api.TopologyPublic:
|
|
||||||
cluster.Spec.Topology = &api.TopologySpec{
|
|
||||||
Masters: api.TopologyPublic,
|
|
||||||
Nodes: api.TopologyPublic,
|
|
||||||
//Bastion: &api.BastionSpec{Enable: c.Bastion},
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Bastion {
|
|
||||||
return fmt.Errorf("Bastion supports --topology='private' only.")
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range cluster.Spec.Subnets {
|
|
||||||
cluster.Spec.Subnets[i].Type = api.SubnetTypePublic
|
|
||||||
}
|
|
||||||
|
|
||||||
case api.TopologyPrivate:
|
|
||||||
if cluster.Spec.Networking.Kubenet != nil {
|
|
||||||
return fmt.Errorf("invalid networking option %s. Kubenet does not support private topology", c.Networking)
|
|
||||||
}
|
|
||||||
cluster.Spec.Topology = &api.TopologySpec{
|
|
||||||
Masters: api.TopologyPrivate,
|
|
||||||
Nodes: api.TopologyPrivate,
|
|
||||||
}
|
|
||||||
|
|
||||||
for i := range cluster.Spec.Subnets {
|
|
||||||
cluster.Spec.Subnets[i].Type = api.SubnetTypePrivate
|
|
||||||
}
|
|
||||||
|
|
||||||
var utilitySubnets []api.ClusterSubnetSpec
|
|
||||||
|
|
||||||
var zoneToSubnetProviderID map[string]string
|
|
||||||
if len(c.Zones) > 0 && len(c.UtilitySubnetIDs) > 0 {
|
|
||||||
if api.CloudProviderID(cluster.Spec.CloudProvider) == api.CloudProviderAWS {
|
|
||||||
zoneToSubnetProviderID, err = getZoneToSubnetProviderID(cluster.Spec.NetworkID, c.Zones[0][:len(c.Zones[0])-1], c.UtilitySubnetIDs)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
} else if api.CloudProviderID(cluster.Spec.CloudProvider) == api.CloudProviderOpenstack {
|
|
||||||
tags := make(map[string]string)
|
|
||||||
tags[openstack.TagClusterName] = c.ClusterName
|
|
||||||
zoneToSubnetProviderID, err = getSubnetProviderID(&cluster.Spec, allZones.List(), c.UtilitySubnetIDs, tags)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, s := range cluster.Spec.Subnets {
|
|
||||||
if s.Type == api.SubnetTypeUtility {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
subnet := api.ClusterSubnetSpec{
|
|
||||||
Name: "utility-" + s.Name,
|
|
||||||
Zone: s.Zone,
|
|
||||||
Type: api.SubnetTypeUtility,
|
|
||||||
}
|
|
||||||
if subnetID, ok := zoneToSubnetProviderID[s.Zone]; ok {
|
|
||||||
subnet.ProviderID = subnetID
|
|
||||||
}
|
|
||||||
utilitySubnets = append(utilitySubnets, subnet)
|
|
||||||
}
|
|
||||||
cluster.Spec.Subnets = append(cluster.Spec.Subnets, utilitySubnets...)
|
|
||||||
|
|
||||||
if c.Bastion {
|
|
||||||
bastionGroup := &api.InstanceGroup{}
|
|
||||||
bastionGroup.Spec.Role = api.InstanceGroupRoleBastion
|
|
||||||
bastionGroup.ObjectMeta.Name = "bastions"
|
|
||||||
bastionGroup.Spec.Image = c.Image
|
|
||||||
instanceGroups = append(instanceGroups, bastionGroup)
|
|
||||||
|
|
||||||
if !dns.IsGossipHostname(cluster.Name) {
|
|
||||||
cluster.Spec.Topology.Bastion = &api.BastionSpec{
|
|
||||||
BastionPublicName: "bastion." + cluster.Name,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("Invalid topology %s.", c.Topology)
|
|
||||||
}
|
|
||||||
|
|
||||||
// DNS
|
|
||||||
if c.DNSType == "" {
|
|
||||||
// The flag default should have set this, but we might be being called as a library
|
|
||||||
klog.Infof("Empty DNS. Defaulting to public DNS")
|
|
||||||
c.DNSType = string(api.DNSTypePublic)
|
|
||||||
}
|
|
||||||
|
|
||||||
if cluster.Spec.Topology == nil {
|
|
||||||
cluster.Spec.Topology = &api.TopologySpec{}
|
|
||||||
}
|
|
||||||
if cluster.Spec.Topology.DNS == nil {
|
|
||||||
cluster.Spec.Topology.DNS = &api.DNSSpec{}
|
|
||||||
}
|
|
||||||
switch strings.ToLower(c.DNSType) {
|
|
||||||
case "public":
|
|
||||||
cluster.Spec.Topology.DNS.Type = api.DNSTypePublic
|
|
||||||
case "private":
|
|
||||||
cluster.Spec.Topology.DNS.Type = api.DNSTypePrivate
|
|
||||||
default:
|
|
||||||
return fmt.Errorf("unknown DNSType: %q", c.DNSType)
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.MasterPublicName != "" {
|
if c.MasterPublicName != "" {
|
||||||
cluster.Spec.MasterPublicName = c.MasterPublicName
|
cluster.Spec.MasterPublicName = c.MasterPublicName
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: push more of the following logic into cloudup.NewCluster()
|
||||||
|
channel := clusterResult.Channel
|
||||||
|
|
||||||
// check if we should set anonymousAuth to false
|
// check if we should set anonymousAuth to false
|
||||||
{
|
{
|
||||||
if cluster.Spec.Kubelet == nil {
|
if cluster.Spec.Kubelet == nil {
|
||||||
|
@ -1065,74 +792,6 @@ func initializeOpenstackAPI(c *CreateClusterOptions, cluster *api.Cluster) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO dedup or remove
|
|
||||||
func getZoneToSubnetProviderID(VPCID string, region string, subnetIDs []string) (map[string]string, error) {
|
|
||||||
res := make(map[string]string)
|
|
||||||
cloudTags := map[string]string{}
|
|
||||||
awsCloud, err := awsup.NewAWSCloud(region, cloudTags)
|
|
||||||
if err != nil {
|
|
||||||
return res, fmt.Errorf("error loading cloud: %v", err)
|
|
||||||
}
|
|
||||||
vpcInfo, err := awsCloud.FindVPCInfo(VPCID)
|
|
||||||
if err != nil {
|
|
||||||
return res, fmt.Errorf("error describing VPC: %v", err)
|
|
||||||
}
|
|
||||||
if vpcInfo == nil {
|
|
||||||
return res, fmt.Errorf("VPC %q not found", VPCID)
|
|
||||||
}
|
|
||||||
subnetByID := make(map[string]*fi.SubnetInfo)
|
|
||||||
for _, subnetInfo := range vpcInfo.Subnets {
|
|
||||||
subnetByID[subnetInfo.ID] = subnetInfo
|
|
||||||
}
|
|
||||||
for _, subnetID := range subnetIDs {
|
|
||||||
subnet, ok := subnetByID[subnetID]
|
|
||||||
if !ok {
|
|
||||||
return res, fmt.Errorf("subnet %s not found in VPC %s", subnetID, VPCID)
|
|
||||||
}
|
|
||||||
if res[subnet.Zone] != "" {
|
|
||||||
return res, fmt.Errorf("subnet %s and %s have the same zone", subnetID, res[subnet.Zone])
|
|
||||||
}
|
|
||||||
res[subnet.Zone] = subnetID
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO dedup or remove
|
|
||||||
func getSubnetProviderID(spec *api.ClusterSpec, zones []string, subnetIDs []string, tags map[string]string) (map[string]string, error) {
|
|
||||||
res := make(map[string]string)
|
|
||||||
osCloud, err := openstack.NewOpenstackCloud(tags, spec)
|
|
||||||
if err != nil {
|
|
||||||
return res, fmt.Errorf("error loading cloud: %v", err)
|
|
||||||
}
|
|
||||||
osCloud.UseZones(zones)
|
|
||||||
|
|
||||||
networkInfo, err := osCloud.FindVPCInfo(spec.NetworkID)
|
|
||||||
if err != nil {
|
|
||||||
return res, fmt.Errorf("error describing Network: %v", err)
|
|
||||||
}
|
|
||||||
if networkInfo == nil {
|
|
||||||
return res, fmt.Errorf("network %q not found", spec.NetworkID)
|
|
||||||
}
|
|
||||||
|
|
||||||
subnetByID := make(map[string]*fi.SubnetInfo)
|
|
||||||
for _, subnetInfo := range networkInfo.Subnets {
|
|
||||||
subnetByID[subnetInfo.ID] = subnetInfo
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, subnetID := range subnetIDs {
|
|
||||||
subnet, ok := subnetByID[subnetID]
|
|
||||||
if !ok {
|
|
||||||
return res, fmt.Errorf("subnet %s not found in network %s", subnetID, spec.NetworkID)
|
|
||||||
}
|
|
||||||
|
|
||||||
if res[subnet.Zone] != "" {
|
|
||||||
return res, fmt.Errorf("subnet %s and %s have the same zone", subnetID, res[subnet.Zone])
|
|
||||||
}
|
|
||||||
res[subnet.Zone] = subnetID
|
|
||||||
}
|
|
||||||
return res, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadSSHPublicKeys(sshPublicKey string) (map[string][]byte, error) {
|
func loadSSHPublicKeys(sshPublicKey string) (map[string][]byte, error) {
|
||||||
sshPublicKeys := make(map[string][]byte)
|
sshPublicKeys := make(map[string][]byte)
|
||||||
if sshPublicKey != "" {
|
if sshPublicKey != "" {
|
||||||
|
|
|
@ -84,6 +84,7 @@ go_library(
|
||||||
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/api/resource:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/apis/meta/v1:go_default_library",
|
||||||
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
"//vendor/k8s.io/apimachinery/pkg/util/sets:go_default_library",
|
||||||
|
"//vendor/k8s.io/apimachinery/pkg/util/validation/field:go_default_library",
|
||||||
"//vendor/k8s.io/klog:go_default_library",
|
"//vendor/k8s.io/klog:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
@ -23,14 +23,21 @@ import (
|
||||||
|
|
||||||
"github.com/aws/aws-sdk-go/aws"
|
"github.com/aws/aws-sdk-go/aws"
|
||||||
"github.com/aws/aws-sdk-go/service/ec2"
|
"github.com/aws/aws-sdk-go/service/ec2"
|
||||||
|
"github.com/blang/semver/v4"
|
||||||
"k8s.io/apimachinery/pkg/api/resource"
|
"k8s.io/apimachinery/pkg/api/resource"
|
||||||
"k8s.io/apimachinery/pkg/apis/meta/v1"
|
"k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/util/sets"
|
"k8s.io/apimachinery/pkg/util/sets"
|
||||||
|
"k8s.io/apimachinery/pkg/util/validation/field"
|
||||||
"k8s.io/klog"
|
"k8s.io/klog"
|
||||||
"k8s.io/kops"
|
"k8s.io/kops"
|
||||||
api "k8s.io/kops/pkg/apis/kops"
|
api "k8s.io/kops/pkg/apis/kops"
|
||||||
"k8s.io/kops/pkg/apis/kops/model"
|
"k8s.io/kops/pkg/apis/kops/model"
|
||||||
|
version "k8s.io/kops/pkg/apis/kops/util"
|
||||||
|
"k8s.io/kops/pkg/apis/kops/validation"
|
||||||
"k8s.io/kops/pkg/client/simple"
|
"k8s.io/kops/pkg/client/simple"
|
||||||
|
"k8s.io/kops/pkg/dns"
|
||||||
|
"k8s.io/kops/pkg/featureflag"
|
||||||
|
"k8s.io/kops/pkg/model/components"
|
||||||
"k8s.io/kops/upup/pkg/fi"
|
"k8s.io/kops/upup/pkg/fi"
|
||||||
"k8s.io/kops/upup/pkg/fi/cloudup/aliup"
|
"k8s.io/kops/upup/pkg/fi/cloudup/aliup"
|
||||||
"k8s.io/kops/upup/pkg/fi/cloudup/awsup"
|
"k8s.io/kops/upup/pkg/fi/cloudup/awsup"
|
||||||
|
@ -53,6 +60,8 @@ type NewClusterOptions struct {
|
||||||
Channel string
|
Channel string
|
||||||
// ConfigBase is the location where we will store the configuration. It defaults to the state store.
|
// ConfigBase is the location where we will store the configuration. It defaults to the state store.
|
||||||
ConfigBase string
|
ConfigBase string
|
||||||
|
// KubernetesVersion is the version of Kubernetes to deploy. It defaults to the version recommended by the channel.
|
||||||
|
KubernetesVersion string
|
||||||
|
|
||||||
// CloudProvider is the name of the cloud provider. The default is to guess based on the Zones name.
|
// CloudProvider is the name of the cloud provider. The default is to guess based on the Zones name.
|
||||||
CloudProvider string
|
CloudProvider string
|
||||||
|
@ -61,12 +70,24 @@ type NewClusterOptions struct {
|
||||||
// MasterZones are the availability zones in which to run the masters. Defaults to the list in the Zones field.
|
// MasterZones are the availability zones in which to run the masters. Defaults to the list in the Zones field.
|
||||||
MasterZones []string
|
MasterZones []string
|
||||||
|
|
||||||
|
// Project is the cluster's GCE project.
|
||||||
|
Project string
|
||||||
|
// GCEServiceAccount specifies the service account with which the GCE VM runs.
|
||||||
|
GCEServiceAccount string
|
||||||
|
|
||||||
|
// Spotinst options
|
||||||
|
SpotinstProduct string
|
||||||
|
SpotinstOrientation string
|
||||||
|
|
||||||
// NetworkID is the ID of the shared network (VPC).
|
// NetworkID is the ID of the shared network (VPC).
|
||||||
// If empty, SubnetIDs are not empty, and on AWS or OpenStack, determines network ID from the first SubnetID.
|
// If empty, SubnetIDs are not empty, and on AWS or OpenStack, determines network ID from the first SubnetID.
|
||||||
// If empty otherwise, creates a new network/VPC to be owned by the cluster.
|
// If empty otherwise, creates a new network/VPC to be owned by the cluster.
|
||||||
NetworkID string
|
NetworkID string
|
||||||
// SubnetIDs are the IDs of the shared subnets. If empty, creates new subnets to be owned by the cluster.
|
// SubnetIDs are the IDs of the shared subnets.
|
||||||
|
// If empty, creates new subnets to be owned by the cluster.
|
||||||
SubnetIDs []string
|
SubnetIDs []string
|
||||||
|
// UtilitySubnetIDs are the IDs of the shared utility subnets. If empty and the topology is "private", creates new subnets to be owned by the cluster.
|
||||||
|
UtilitySubnetIDs []string
|
||||||
// Egress defines the method of traffic egress for subnets.
|
// Egress defines the method of traffic egress for subnets.
|
||||||
Egress string
|
Egress string
|
||||||
|
|
||||||
|
@ -90,11 +111,23 @@ type NewClusterOptions struct {
|
||||||
// NodeCount is the number of nodes to create. Defaults to leaving the count unspecified
|
// NodeCount is the number of nodes to create. Defaults to leaving the count unspecified
|
||||||
// on the InstanceGroup, which results in a count of 2.
|
// on the InstanceGroup, which results in a count of 2.
|
||||||
NodeCount int32
|
NodeCount int32
|
||||||
|
// Bastion enables the creation of a Bastion instance.
|
||||||
|
Bastion bool
|
||||||
|
|
||||||
|
// Networking is the networking provider/node to use.
|
||||||
|
Networking string
|
||||||
|
// Topology is the network topology to use. Defaults to "public".
|
||||||
|
Topology string
|
||||||
|
// DNSType is the DNS type to use; "public" or "private". Defaults to "public".
|
||||||
|
DNSType string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *NewClusterOptions) InitDefaults() {
|
func (o *NewClusterOptions) InitDefaults() {
|
||||||
o.Channel = api.DefaultChannel
|
o.Channel = api.DefaultChannel
|
||||||
o.Authorization = AuthorizationFlagRBAC
|
o.Authorization = AuthorizationFlagRBAC
|
||||||
|
o.Networking = "kubenet"
|
||||||
|
o.Topology = api.TopologyPublic
|
||||||
|
o.DNSType = string(api.DNSTypePublic)
|
||||||
}
|
}
|
||||||
|
|
||||||
type NewClusterResult struct {
|
type NewClusterResult struct {
|
||||||
|
@ -105,7 +138,6 @@ type NewClusterResult struct {
|
||||||
|
|
||||||
// TODO remove after more create_cluster logic refactored in
|
// TODO remove after more create_cluster logic refactored in
|
||||||
Channel *api.Channel
|
Channel *api.Channel
|
||||||
AllZones sets.String
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewCluster initializes cluster and instance groups specifications as
|
// NewCluster initializes cluster and instance groups specifications as
|
||||||
|
@ -138,6 +170,9 @@ func NewCluster(opt *NewClusterOptions, clientset simple.Clientset) (*NewCluster
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cluster.Spec.Channel = opt.Channel
|
cluster.Spec.Channel = opt.Channel
|
||||||
|
if opt.KubernetesVersion != "" {
|
||||||
|
cluster.Spec.KubernetesVersion = opt.KubernetesVersion
|
||||||
|
}
|
||||||
|
|
||||||
cluster.Spec.ConfigBase = opt.ConfigBase
|
cluster.Spec.ConfigBase = opt.ConfigBase
|
||||||
configBase, err := clientset.ConfigBaseFor(&cluster)
|
configBase, err := clientset.ConfigBaseFor(&cluster)
|
||||||
|
@ -197,14 +232,24 @@ func NewCluster(opt *NewClusterOptions, clientset simple.Clientset) (*NewCluster
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = setupNetworking(opt, &cluster)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
bastions, err := setupTopology(opt, &cluster, allZones)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
instanceGroups := append([]*api.InstanceGroup(nil), masters...)
|
instanceGroups := append([]*api.InstanceGroup(nil), masters...)
|
||||||
instanceGroups = append(instanceGroups, nodes...)
|
instanceGroups = append(instanceGroups, nodes...)
|
||||||
|
instanceGroups = append(instanceGroups, bastions...)
|
||||||
|
|
||||||
result := NewClusterResult{
|
result := NewClusterResult{
|
||||||
Cluster: &cluster,
|
Cluster: &cluster,
|
||||||
InstanceGroups: instanceGroups,
|
InstanceGroups: instanceGroups,
|
||||||
Channel: channel,
|
Channel: channel,
|
||||||
AllZones: allZones,
|
|
||||||
}
|
}
|
||||||
return &result, nil
|
return &result, nil
|
||||||
}
|
}
|
||||||
|
@ -232,6 +277,32 @@ func setupVPC(opt *NewClusterOptions, cluster *api.Cluster) error {
|
||||||
cluster.Spec.NetworkID = *res.Subnets[0].VpcId
|
cluster.Spec.NetworkID = *res.Subnets[0].VpcId
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case api.CloudProviderGCE:
|
||||||
|
if cluster.Spec.CloudConfig == nil {
|
||||||
|
cluster.Spec.CloudConfig = &api.CloudConfiguration{}
|
||||||
|
}
|
||||||
|
cluster.Spec.Project = opt.Project
|
||||||
|
if cluster.Spec.Project == "" {
|
||||||
|
project, err := gce.DefaultProject()
|
||||||
|
if err != nil {
|
||||||
|
klog.Warningf("unable to get default google cloud project: %v", err)
|
||||||
|
} else if project == "" {
|
||||||
|
klog.Warningf("default google cloud project not set (try `gcloud config set project <name>`")
|
||||||
|
} else {
|
||||||
|
klog.Infof("using google cloud project: %s", project)
|
||||||
|
}
|
||||||
|
cluster.Spec.Project = project
|
||||||
|
}
|
||||||
|
if opt.GCEServiceAccount != "" {
|
||||||
|
// TODO remove this logging?
|
||||||
|
klog.Infof("VMs will be configured to use specified Service Account: %v", opt.GCEServiceAccount)
|
||||||
|
cluster.Spec.CloudConfig.GCEServiceAccount = opt.GCEServiceAccount
|
||||||
|
} else {
|
||||||
|
klog.Warning("VMs will be configured to use the GCE default compute Service Account! This is an anti-pattern")
|
||||||
|
klog.Warning("Use a pre-created Service Account with the flag: --gce-service-account=account@projectname.iam.gserviceaccount.com")
|
||||||
|
cluster.Spec.CloudConfig.GCEServiceAccount = "default"
|
||||||
|
}
|
||||||
|
|
||||||
case api.CloudProviderOpenstack:
|
case api.CloudProviderOpenstack:
|
||||||
if cluster.Spec.CloudConfig == nil {
|
if cluster.Spec.CloudConfig == nil {
|
||||||
cluster.Spec.CloudConfig = &api.CloudConfiguration{}
|
cluster.Spec.CloudConfig = &api.CloudConfiguration{}
|
||||||
|
@ -253,7 +324,7 @@ func setupVPC(opt *NewClusterOptions, cluster *api.Cluster) error {
|
||||||
|
|
||||||
if cluster.Spec.NetworkID == "" && len(opt.SubnetIDs) > 0 {
|
if cluster.Spec.NetworkID == "" && len(opt.SubnetIDs) > 0 {
|
||||||
tags := make(map[string]string)
|
tags := make(map[string]string)
|
||||||
tags[openstack.TagClusterName] = opt.ClusterName
|
tags[openstack.TagClusterName] = cluster.Name
|
||||||
osCloud, err := openstack.NewOpenstackCloud(tags, &cluster.Spec)
|
osCloud, err := openstack.NewOpenstackCloud(tags, &cluster.Spec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error loading cloud: %v", err)
|
return fmt.Errorf("error loading cloud: %v", err)
|
||||||
|
@ -274,6 +345,18 @@ func setupVPC(opt *NewClusterOptions, cluster *api.Cluster) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if featureflag.Spotinst.Enabled() {
|
||||||
|
if cluster.Spec.CloudConfig == nil {
|
||||||
|
cluster.Spec.CloudConfig = &api.CloudConfiguration{}
|
||||||
|
}
|
||||||
|
if opt.SpotinstProduct != "" {
|
||||||
|
cluster.Spec.CloudConfig.SpotinstProduct = fi.String(opt.SpotinstProduct)
|
||||||
|
}
|
||||||
|
if opt.SpotinstOrientation != "" {
|
||||||
|
cluster.Spec.CloudConfig.SpotinstOrientation = fi.String(opt.SpotinstOrientation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -345,7 +428,7 @@ func setupZones(opt *NewClusterOptions, cluster *api.Cluster, allZones sets.Stri
|
||||||
|
|
||||||
case api.CloudProviderAWS:
|
case api.CloudProviderAWS:
|
||||||
if len(opt.Zones) > 0 && len(opt.SubnetIDs) > 0 {
|
if len(opt.Zones) > 0 && len(opt.SubnetIDs) > 0 {
|
||||||
zoneToSubnetProviderID, err = getZoneToSubnetProviderID(cluster.Spec.NetworkID, opt.Zones[0][:len(opt.Zones[0])-1], opt.SubnetIDs)
|
zoneToSubnetProviderID, err = getAWSZoneToSubnetProviderID(cluster.Spec.NetworkID, opt.Zones[0][:len(opt.Zones[0])-1], opt.SubnetIDs)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -354,8 +437,8 @@ func setupZones(opt *NewClusterOptions, cluster *api.Cluster, allZones sets.Stri
|
||||||
case api.CloudProviderOpenstack:
|
case api.CloudProviderOpenstack:
|
||||||
if len(opt.Zones) > 0 && len(opt.SubnetIDs) > 0 {
|
if len(opt.Zones) > 0 && len(opt.SubnetIDs) > 0 {
|
||||||
tags := make(map[string]string)
|
tags := make(map[string]string)
|
||||||
tags[openstack.TagClusterName] = opt.ClusterName
|
tags[openstack.TagClusterName] = cluster.Name
|
||||||
zoneToSubnetProviderID, err = getSubnetProviderID(&cluster.Spec, allZones.List(), opt.SubnetIDs, tags)
|
zoneToSubnetProviderID, err = getOpenstackZoneToSubnetProviderID(&cluster.Spec, allZones.List(), opt.SubnetIDs, tags)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -384,8 +467,7 @@ func setupZones(opt *NewClusterOptions, cluster *api.Cluster, allZones sets.Stri
|
||||||
return zoneToSubnetMap, nil
|
return zoneToSubnetMap, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO rename to getAWSZoneToSubnetProviderID
|
func getAWSZoneToSubnetProviderID(VPCID string, region string, subnetIDs []string) (map[string]string, error) {
|
||||||
func getZoneToSubnetProviderID(VPCID string, region string, subnetIDs []string) (map[string]string, error) {
|
|
||||||
res := make(map[string]string)
|
res := make(map[string]string)
|
||||||
cloudTags := map[string]string{}
|
cloudTags := map[string]string{}
|
||||||
awsCloud, err := awsup.NewAWSCloud(region, cloudTags)
|
awsCloud, err := awsup.NewAWSCloud(region, cloudTags)
|
||||||
|
@ -416,8 +498,7 @@ func getZoneToSubnetProviderID(VPCID string, region string, subnetIDs []string)
|
||||||
return res, nil
|
return res, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO rename to getOpenstackZoneToSubnetProviderID
|
func getOpenstackZoneToSubnetProviderID(spec *api.ClusterSpec, zones []string, subnetIDs []string, tags map[string]string) (map[string]string, error) {
|
||||||
func getSubnetProviderID(spec *api.ClusterSpec, zones []string, subnetIDs []string, tags map[string]string) (map[string]string, error) {
|
|
||||||
res := make(map[string]string)
|
res := make(map[string]string)
|
||||||
osCloud, err := openstack.NewOpenstackCloud(tags, spec)
|
osCloud, err := openstack.NewOpenstackCloud(tags, spec)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -644,3 +725,189 @@ func setupNodes(opt *NewClusterOptions, cluster *api.Cluster, zoneToSubnetMap ma
|
||||||
|
|
||||||
return nodes, nil
|
return nodes, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setupNetworking(opt *NewClusterOptions, cluster *api.Cluster) error {
|
||||||
|
cluster.Spec.Networking = &api.NetworkingSpec{}
|
||||||
|
switch opt.Networking {
|
||||||
|
case "kubenet", "":
|
||||||
|
cluster.Spec.Networking.Kubenet = &api.KubenetNetworkingSpec{}
|
||||||
|
case "external":
|
||||||
|
cluster.Spec.Networking.External = &api.ExternalNetworkingSpec{}
|
||||||
|
case "cni":
|
||||||
|
cluster.Spec.Networking.CNI = &api.CNINetworkingSpec{}
|
||||||
|
case "kopeio-vxlan", "kopeio":
|
||||||
|
cluster.Spec.Networking.Kopeio = &api.KopeioNetworkingSpec{}
|
||||||
|
case "weave":
|
||||||
|
cluster.Spec.Networking.Weave = &api.WeaveNetworkingSpec{}
|
||||||
|
|
||||||
|
if cluster.Spec.CloudProvider == "aws" {
|
||||||
|
// AWS supports "jumbo frames" of 9001 bytes and weave adds up to 87 bytes overhead
|
||||||
|
// sets the default to the largest number that leaves enough overhead and is divisible by 4
|
||||||
|
jumboFrameMTUSize := int32(8912)
|
||||||
|
cluster.Spec.Networking.Weave.MTU = &jumboFrameMTUSize
|
||||||
|
}
|
||||||
|
case "flannel", "flannel-vxlan":
|
||||||
|
cluster.Spec.Networking.Flannel = &api.FlannelNetworkingSpec{
|
||||||
|
Backend: "vxlan",
|
||||||
|
}
|
||||||
|
case "flannel-udp":
|
||||||
|
klog.Warningf("flannel UDP mode is not recommended; consider flannel-vxlan instead")
|
||||||
|
cluster.Spec.Networking.Flannel = &api.FlannelNetworkingSpec{
|
||||||
|
Backend: "udp",
|
||||||
|
}
|
||||||
|
case "calico":
|
||||||
|
cluster.Spec.Networking.Calico = &api.CalicoNetworkingSpec{
|
||||||
|
MajorVersion: "v3",
|
||||||
|
}
|
||||||
|
// Validate to check if etcd clusters have an acceptable version
|
||||||
|
if errList := validation.ValidateEtcdVersionForCalicoV3(cluster.Spec.EtcdClusters[0], cluster.Spec.Networking.Calico.MajorVersion, field.NewPath("spec", "networking", "calico")); len(errList) != 0 {
|
||||||
|
|
||||||
|
// This is not a special version but simply of the 3 series
|
||||||
|
for _, etcd := range cluster.Spec.EtcdClusters {
|
||||||
|
etcd.Version = components.DefaultEtcd3Version_1_11
|
||||||
|
}
|
||||||
|
}
|
||||||
|
case "canal":
|
||||||
|
cluster.Spec.Networking.Canal = &api.CanalNetworkingSpec{}
|
||||||
|
case "kube-router":
|
||||||
|
cluster.Spec.Networking.Kuberouter = &api.KuberouterNetworkingSpec{}
|
||||||
|
if cluster.Spec.KubeProxy == nil {
|
||||||
|
cluster.Spec.KubeProxy = &api.KubeProxyConfig{}
|
||||||
|
}
|
||||||
|
enabled := false
|
||||||
|
cluster.Spec.KubeProxy.Enabled = &enabled
|
||||||
|
case "amazonvpc", "amazon-vpc-routed-eni":
|
||||||
|
cluster.Spec.Networking.AmazonVPC = &api.AmazonVPCNetworkingSpec{}
|
||||||
|
case "cilium":
|
||||||
|
cilium := &api.CiliumNetworkingSpec{}
|
||||||
|
cluster.Spec.Networking.Cilium = cilium
|
||||||
|
nodeport := false
|
||||||
|
if cluster.Spec.KubernetesVersion == "" {
|
||||||
|
nodeport = true
|
||||||
|
} else {
|
||||||
|
k8sVersion, err := semver.ParseTolerant(cluster.Spec.KubernetesVersion)
|
||||||
|
if err == nil {
|
||||||
|
if version.IsKubernetesGTE("1.12", k8sVersion) {
|
||||||
|
nodeport = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if nodeport {
|
||||||
|
cilium.EnableNodePort = true
|
||||||
|
if cluster.Spec.KubeProxy == nil {
|
||||||
|
cluster.Spec.KubeProxy = &api.KubeProxyConfig{}
|
||||||
|
}
|
||||||
|
enabled := false
|
||||||
|
cluster.Spec.KubeProxy.Enabled = &enabled
|
||||||
|
}
|
||||||
|
case "lyftvpc":
|
||||||
|
cluster.Spec.Networking.LyftVPC = &api.LyftVPCNetworkingSpec{}
|
||||||
|
case "gce":
|
||||||
|
cluster.Spec.Networking.GCE = &api.GCENetworkingSpec{}
|
||||||
|
default:
|
||||||
|
return fmt.Errorf("unknown networking mode %q", opt.Networking)
|
||||||
|
}
|
||||||
|
|
||||||
|
klog.V(4).Infof("networking mode=%s => %s", opt.Networking, fi.DebugAsJsonString(cluster.Spec.Networking))
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupTopology(opt *NewClusterOptions, cluster *api.Cluster, allZones sets.String) ([]*api.InstanceGroup, error) {
|
||||||
|
var bastions []*api.InstanceGroup
|
||||||
|
|
||||||
|
switch opt.Topology {
|
||||||
|
case api.TopologyPublic, "":
|
||||||
|
cluster.Spec.Topology = &api.TopologySpec{
|
||||||
|
Masters: api.TopologyPublic,
|
||||||
|
Nodes: api.TopologyPublic,
|
||||||
|
//Bastion: &api.BastionSpec{Enable: c.Bastion},
|
||||||
|
}
|
||||||
|
|
||||||
|
if opt.Bastion {
|
||||||
|
return nil, fmt.Errorf("bastion supports --topology='private' only")
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range cluster.Spec.Subnets {
|
||||||
|
cluster.Spec.Subnets[i].Type = api.SubnetTypePublic
|
||||||
|
}
|
||||||
|
|
||||||
|
case api.TopologyPrivate:
|
||||||
|
if cluster.Spec.Networking.Kubenet != nil {
|
||||||
|
return nil, fmt.Errorf("invalid networking option %s. Kubenet does not support private topology", opt.Networking)
|
||||||
|
}
|
||||||
|
cluster.Spec.Topology = &api.TopologySpec{
|
||||||
|
Masters: api.TopologyPrivate,
|
||||||
|
Nodes: api.TopologyPrivate,
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range cluster.Spec.Subnets {
|
||||||
|
cluster.Spec.Subnets[i].Type = api.SubnetTypePrivate
|
||||||
|
}
|
||||||
|
|
||||||
|
var utilitySubnets []api.ClusterSubnetSpec
|
||||||
|
|
||||||
|
var zoneToSubnetProviderID map[string]string
|
||||||
|
var err error
|
||||||
|
if len(opt.Zones) > 0 && len(opt.UtilitySubnetIDs) > 0 {
|
||||||
|
switch api.CloudProviderID(cluster.Spec.CloudProvider) {
|
||||||
|
case api.CloudProviderAWS:
|
||||||
|
zoneToSubnetProviderID, err = getAWSZoneToSubnetProviderID(cluster.Spec.NetworkID, opt.Zones[0][:len(opt.Zones[0])-1], opt.UtilitySubnetIDs)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
case api.CloudProviderOpenstack:
|
||||||
|
tags := make(map[string]string)
|
||||||
|
tags[openstack.TagClusterName] = cluster.Name
|
||||||
|
zoneToSubnetProviderID, err = getOpenstackZoneToSubnetProviderID(&cluster.Spec, allZones.List(), opt.UtilitySubnetIDs, tags)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, s := range cluster.Spec.Subnets {
|
||||||
|
if s.Type == api.SubnetTypeUtility {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
subnet := api.ClusterSubnetSpec{
|
||||||
|
Name: "utility-" + s.Name,
|
||||||
|
Zone: s.Zone,
|
||||||
|
Type: api.SubnetTypeUtility,
|
||||||
|
}
|
||||||
|
if subnetID, ok := zoneToSubnetProviderID[s.Zone]; ok {
|
||||||
|
subnet.ProviderID = subnetID
|
||||||
|
}
|
||||||
|
utilitySubnets = append(utilitySubnets, subnet)
|
||||||
|
}
|
||||||
|
cluster.Spec.Subnets = append(cluster.Spec.Subnets, utilitySubnets...)
|
||||||
|
|
||||||
|
if opt.Bastion {
|
||||||
|
bastionGroup := &api.InstanceGroup{}
|
||||||
|
bastionGroup.Spec.Role = api.InstanceGroupRoleBastion
|
||||||
|
bastionGroup.ObjectMeta.Name = "bastions"
|
||||||
|
bastions = append(bastions, bastionGroup)
|
||||||
|
|
||||||
|
if !dns.IsGossipHostname(cluster.Name) {
|
||||||
|
cluster.Spec.Topology.Bastion = &api.BastionSpec{
|
||||||
|
BastionPublicName: "bastion." + cluster.Name,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("invalid topology %s", opt.Topology)
|
||||||
|
}
|
||||||
|
|
||||||
|
cluster.Spec.Topology.DNS = &api.DNSSpec{}
|
||||||
|
switch strings.ToLower(opt.DNSType) {
|
||||||
|
case "public", "":
|
||||||
|
cluster.Spec.Topology.DNS.Type = api.DNSTypePublic
|
||||||
|
case "private":
|
||||||
|
cluster.Spec.Topology.DNS.Type = api.DNSTypePrivate
|
||||||
|
default:
|
||||||
|
return nil, fmt.Errorf("unknown DNSType: %q", opt.DNSType)
|
||||||
|
}
|
||||||
|
|
||||||
|
return bastions, nil
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue