Implement some completion for "kops create cluster"

This commit is contained in:
John Gardiner Myers 2021-07-05 15:57:00 -07:00
parent dbf4f23654
commit 6d16c13f24
7 changed files with 334 additions and 89 deletions

2
cmd/kops/BUILD.bazel generated
View File

@ -104,6 +104,8 @@ go_library(
"//vendor/github.com/aws/amazon-ec2-instance-selector/v2/pkg/cli:go_default_library",
"//vendor/github.com/aws/amazon-ec2-instance-selector/v2/pkg/selector:go_default_library",
"//vendor/github.com/blang/semver/v4:go_default_library",
"//vendor/github.com/google/go-containerregistry/pkg/name:go_default_library",
"//vendor/github.com/google/go-containerregistry/pkg/v1/remote:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/github.com/spf13/cobra/doc:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",

View File

@ -26,18 +26,24 @@ import (
"os"
"strings"
"github.com/google/go-containerregistry/pkg/name"
"github.com/google/go-containerregistry/pkg/v1/remote"
"github.com/spf13/cobra"
"github.com/spf13/pflag"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/klog/v2"
kopsbase "k8s.io/kops"
"k8s.io/kops/cmd/kops/util"
api "k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/apis/kops/registry"
kopsutil "k8s.io/kops/pkg/apis/kops/util"
"k8s.io/kops/pkg/apis/kops/validation"
"k8s.io/kops/pkg/assets"
"k8s.io/kops/pkg/clusteraddons"
"k8s.io/kops/pkg/commands"
"k8s.io/kops/pkg/commands/commandutils"
"k8s.io/kops/pkg/featureflag"
"k8s.io/kops/pkg/kubeconfig"
"k8s.io/kops/pkg/kubemanifest"
@ -106,7 +112,7 @@ func (o *CreateClusterOptions) InitDefaults() {
var (
createClusterLong = templates.LongDesc(i18n.T(`
Create a kubernetes cluster using command line flags.
Create a Kubernetes cluster using command line flags.
This command creates cloud based resources such as networks and virtual machines. Once
the infrastructure is in place Kubernetes is installed on the virtual machines.
@ -120,7 +126,7 @@ var (
--zones=us-east-1a \
--node-count=2
# Create a cluster in AWS with HA masters. This cluster
# Create a cluster in AWS with High Availability masters. This cluster
# has also been configured for private networking in a kops-managed VPC.
# The bastion flag is set to create an entrypoint for admins to SSH.
export KOPS_STATE_STORE="s3://my-state-store"
@ -138,12 +144,11 @@ var (
--bastion="true" \
--yes
# Create a cluster in GCE.
# Note: GCE support is not GA.
export KOPS_FEATURE_FLAGS=AlphaAllowGCE
export KOPS_STATE_STORE="gs://my-state-store"
export ZONES="us-east1-a,us-east1-b,us-east1-c"
# Create a cluster in Digital Ocean.
export KOPS_STATE_STORE="do://my-state-store"
export ZONES="NYC1"
kops create cluster k8s-cluster.example.com \
--cloud digitalocean \
--zones $ZONES \
--master-zones $ZONES \
--node-count 3 \
@ -171,12 +176,16 @@ func NewCmdCreateCluster(f *util.Factory, out io.Writer) *cobra.Command {
encryptEtcdStorage := false
cmd := &cobra.Command{
Use: "cluster",
Use: "cluster [CLUSTER]",
Short: createClusterShort,
Long: createClusterLong,
Example: createClusterExample,
Run: func(cmd *cobra.Command, args []string) {
ctx := context.TODO()
Args: rootCommand.clusterNameArgsNoKubeconfig(&options.ClusterName),
ValidArgsFunction: func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return nil, cobra.ShellCompDirectiveNoFileComp
},
RunE: func(cmd *cobra.Command, args []string) error {
var err error
if cmd.Flag("associate-public-ip").Changed {
options.AssociatePublicIP = &associatePublicIP
@ -186,106 +195,149 @@ func NewCmdCreateCluster(f *util.Factory, out io.Writer) *cobra.Command {
options.EncryptEtcdStorage = &encryptEtcdStorage
}
err := rootCommand.ProcessArgs(args)
if err != nil {
exitWithError(err)
return
}
options.ClusterName = rootCommand.clusterName
if sshPublicKey != "" {
options.SSHPublicKeys, err = loadSSHPublicKeys(sshPublicKey)
if err != nil {
exitWithError(fmt.Errorf("error reading SSH key file %q: %v", sshPublicKey, err))
return fmt.Errorf("error reading SSH key file %q: %v", sshPublicKey, err)
}
}
err = RunCreateCluster(ctx, f, out, options)
if err != nil {
exitWithError(err)
}
return RunCreateCluster(context.TODO(), f, out, options)
},
}
cmd.Flags().BoolVarP(&options.Yes, "yes", "y", options.Yes, "Specify --yes to immediately create the cluster")
cmd.Flags().StringVar(&options.Target, "target", options.Target, fmt.Sprintf("Valid targets: %s, %s, %s. Set this flag to %s if you want kOps to generate terraform", cloudup.TargetDirect, cloudup.TargetTerraform, cloudup.TargetCloudformation, cloudup.TargetTerraform))
cmd.RegisterFlagCompletionFunc("target", completeTarget)
// Configuration / state location
if featureflag.EnableSeparateConfigBase.Enabled() {
cmd.Flags().StringVar(&options.ConfigBase, "config-base", options.ConfigBase, "A cluster-readable location where we mirror configuration information, separate from the state store. Allows for a state store that is not accessible from the cluster.")
cmd.RegisterFlagCompletionFunc("config-base", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
// TODO complete vfs paths
return nil, cobra.ShellCompDirectiveNoFileComp
})
}
cmd.Flags().StringVar(&options.CloudProvider, "cloud", options.CloudProvider, "Cloud provider to use - gce, aws, openstack")
cmd.Flags().StringVar(&options.CloudProvider, "cloud", options.CloudProvider, fmt.Sprintf("Cloud provider to use - %s", strings.Join(cloudup.SupportedClouds(), ", ")))
cmd.RegisterFlagCompletionFunc("cloud", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return cloudup.SupportedClouds(), cobra.ShellCompDirectiveNoFileComp
})
cmd.Flags().StringSliceVar(&options.Zones, "zones", options.Zones, "Zones in which to run the cluster")
cmd.RegisterFlagCompletionFunc("zones", completeZone)
cmd.Flags().StringSliceVar(&options.MasterZones, "master-zones", options.MasterZones, "Zones in which to run masters (must be an odd number)")
cmd.RegisterFlagCompletionFunc("master-zones", completeZone)
if featureflag.ClusterAddons.Enabled() {
cmd.Flags().StringSliceVar(&options.AddonPaths, "add", options.AddonPaths, "Paths to addons we should add to the cluster")
// TODO complete VFS paths
}
cmd.Flags().StringVar(&options.KubernetesVersion, "kubernetes-version", options.KubernetesVersion, "Version of kubernetes to run (defaults to version in channel)")
cmd.RegisterFlagCompletionFunc("kubernetes-version", completeKubernetesVersion)
cmd.Flags().StringVar(&options.ContainerRuntime, "container-runtime", options.ContainerRuntime, "Container runtime to use: containerd, docker")
cmd.RegisterFlagCompletionFunc("container-runtime", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return []string{"containerd", "docker"}, cobra.ShellCompDirectiveNoFileComp
})
cmd.Flags().StringVar(&sshPublicKey, "ssh-public-key", sshPublicKey, "SSH public key to use (defaults to ~/.ssh/id_rsa.pub on AWS)")
cmd.RegisterFlagCompletionFunc("ssh-public-key", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return []string{"pub"}, cobra.ShellCompDirectiveFilterFileExt
})
cmd.Flags().Int32Var(&options.MasterCount, "master-count", options.MasterCount, "Set number of masters. Defaults to one master per master-zone")
cmd.Flags().Int32Var(&options.NodeCount, "node-count", options.NodeCount, "Set total number of nodes. Defaults to one node per zone")
cmd.Flags().Int32Var(&options.MasterCount, "master-count", options.MasterCount, "Number of masters. Defaults to one master per master-zone")
cmd.Flags().Int32Var(&options.NodeCount, "node-count", options.NodeCount, "Total number of worker nodes. Defaults to one node per zone")
cmd.Flags().StringVar(&options.Image, "image", options.Image, "Set image for all instances.")
cmd.Flags().StringVar(&options.NodeImage, "node-image", options.NodeImage, "Set image for nodes. Takes precedence over --image")
cmd.Flags().StringVar(&options.MasterImage, "master-image", options.MasterImage, "Set image for masters. Takes precedence over --image")
cmd.Flags().StringVar(&options.Image, "image", options.Image, "Machine image for all instances")
cmd.RegisterFlagCompletionFunc("image", completeInstanceImage)
cmd.Flags().StringVar(&options.NodeImage, "node-image", options.NodeImage, "Machine image for worker nodes. Takes precedence over --image")
cmd.RegisterFlagCompletionFunc("node-image", completeInstanceImage)
cmd.Flags().StringVar(&options.MasterImage, "master-image", options.MasterImage, "Machine image for masters. Takes precedence over --image")
cmd.RegisterFlagCompletionFunc("master-image", completeInstanceImage)
cmd.Flags().StringVar(&options.NodeSize, "node-size", options.NodeSize, "Set instance size for nodes")
cmd.Flags().StringVar(&options.MasterSize, "master-size", options.MasterSize, "Set instance size for masters")
cmd.Flags().StringVar(&options.NodeSize, "node-size", options.NodeSize, "Machine type for worker nodes")
cmd.RegisterFlagCompletionFunc("node-size", completeMachineType)
cmd.Flags().StringVar(&options.MasterSize, "master-size", options.MasterSize, "Machine type for masters")
cmd.RegisterFlagCompletionFunc("master-size", completeMachineType)
cmd.Flags().Int32Var(&options.MasterVolumeSize, "master-volume-size", options.MasterVolumeSize, "Set instance volume size (in GB) for masters")
cmd.Flags().Int32Var(&options.NodeVolumeSize, "node-volume-size", options.NodeVolumeSize, "Set instance volume size (in GB) for nodes")
cmd.Flags().Int32Var(&options.MasterVolumeSize, "master-volume-size", options.MasterVolumeSize, "Instance volume size (in GB) for masters")
cmd.Flags().Int32Var(&options.NodeVolumeSize, "node-volume-size", options.NodeVolumeSize, "Instance volume size (in GB) for worker nodes")
cmd.Flags().StringVar(&options.NetworkID, "vpc", options.NetworkID, "Set to use a shared VPC")
cmd.Flags().StringSliceVar(&options.SubnetIDs, "subnets", options.SubnetIDs, "Set to use shared subnets")
cmd.Flags().StringSliceVar(&options.UtilitySubnetIDs, "utility-subnets", options.UtilitySubnetIDs, "Set to use shared utility subnets")
cmd.Flags().StringVar(&options.NetworkCIDR, "network-cidr", options.NetworkCIDR, "Set to override the default network CIDR")
cmd.Flags().BoolVar(&options.DisableSubnetTags, "disable-subnet-tags", options.DisableSubnetTags, "Set to disable automatic subnet tagging")
cmd.Flags().StringVar(&options.NetworkID, "vpc", options.NetworkID, "Shared VPC to use")
cmd.RegisterFlagCompletionFunc("vpc", completeNetworkID)
cmd.Flags().StringSliceVar(&options.SubnetIDs, "subnets", options.SubnetIDs, "Shared subnets to use")
cmd.RegisterFlagCompletionFunc("subnets", completeSubnetID(options))
cmd.Flags().StringSliceVar(&options.UtilitySubnetIDs, "utility-subnets", options.UtilitySubnetIDs, "Shared utility subnets to use")
cmd.RegisterFlagCompletionFunc("utility-subnets", completeSubnetID(options))
cmd.Flags().StringVar(&options.NetworkCIDR, "network-cidr", options.NetworkCIDR, "Network CIDR to use")
cmd.RegisterFlagCompletionFunc("network-cidr", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return nil, cobra.ShellCompDirectiveNoFileComp
})
cmd.Flags().BoolVar(&options.DisableSubnetTags, "disable-subnet-tags", options.DisableSubnetTags, "Disable automatic subnet tagging")
cmd.Flags().BoolVar(&encryptEtcdStorage, "encrypt-etcd-storage", false, "Generate key in aws kms and use it for encrypt etcd volumes")
cmd.Flags().StringVar(&options.EtcdStorageType, "etcd-storage-type", options.EtcdStorageType, "The default storage type for etc members")
cmd.Flags().BoolVar(&encryptEtcdStorage, "encrypt-etcd-storage", false, "Generate key in AWS KMS and use it for encrypt etcd volumes")
cmd.Flags().StringVar(&options.EtcdStorageType, "etcd-storage-type", options.EtcdStorageType, "The default storage type for etcd members")
cmd.RegisterFlagCompletionFunc("etcd-storage-type", completeStorageType)
cmd.Flags().StringVar(&options.Networking, "networking", options.Networking, "Networking mode to use. kubenet, external, weave, flannel-vxlan (or flannel), flannel-udp, calico, canal, kube-router, amazonvpc, cilium, cilium-etcd, cni, lyftvpc.")
cmd.Flags().StringVar(&options.Networking, "networking", options.Networking, "Networking mode. kubenet, external, weave, flannel-vxlan (or flannel), flannel-udp, calico, canal, kube-router, amazonvpc, cilium, cilium-etcd, cni, lyftvpc.")
cmd.RegisterFlagCompletionFunc("networking", completeNetworking(options))
cmd.Flags().StringVar(&options.DNSZone, "dns-zone", options.DNSZone, "DNS hosted zone to use (defaults to longest matching zone)")
cmd.Flags().StringVar(&options.DNSZone, "dns-zone", options.DNSZone, "DNS hosted zone (defaults to longest matching zone)")
cmd.RegisterFlagCompletionFunc("dns-zone", completeDNSZone(options))
cmd.Flags().StringVar(&options.OutDir, "out", options.OutDir, "Path to write any local output")
cmd.MarkFlagDirname("out")
cmd.Flags().StringSliceVar(&options.AdminAccess, "admin-access", options.AdminAccess, "Restrict API access to this CIDR. If not set, access will not be restricted by IP.")
cmd.RegisterFlagCompletionFunc("admin-access", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return nil, cobra.ShellCompDirectiveNoFileComp
})
cmd.Flags().StringSliceVar(&options.SSHAccess, "ssh-access", options.SSHAccess, "Restrict SSH access to this CIDR. If not set, uses the value of the admin-access flag.")
cmd.RegisterFlagCompletionFunc("ssh-access", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return nil, cobra.ShellCompDirectiveNoFileComp
})
// TODO: Can we deprecate this flag - it is awkward?
cmd.Flags().BoolVar(&associatePublicIP, "associate-public-ip", false, "Specify --associate-public-ip=[true|false] to enable/disable association of public IP for master ASG and nodes. Default is 'true'.")
if featureflag.AWSIPv6.Enabled() {
cmd.Flags().BoolVar(&options.IPv6, "ipv6", false, "Allocate IPv6 CIDRs to sunets for clusters with public topology on AWS")
cmd.Flags().BoolVar(&options.IPv6, "ipv6", false, "Allocate IPv6 CIDRs to subnets for clusters with public topology (AWS only)")
}
cmd.Flags().StringSliceVar(&options.NodeSecurityGroups, "node-security-groups", options.NodeSecurityGroups, "Add precreated additional security groups to nodes.")
cmd.Flags().StringSliceVar(&options.MasterSecurityGroups, "master-security-groups", options.MasterSecurityGroups, "Add precreated additional security groups to masters.")
cmd.Flags().StringSliceVar(&options.NodeSecurityGroups, "node-security-groups", options.NodeSecurityGroups, "Additional precreated security groups to add to worker nodes.")
cmd.RegisterFlagCompletionFunc("node-security-groups", completeSecurityGroup(options))
cmd.Flags().StringSliceVar(&options.MasterSecurityGroups, "master-security-groups", options.MasterSecurityGroups, "Additional precreated security groups to add to masters.")
cmd.RegisterFlagCompletionFunc("master-security-groups", completeSecurityGroup(options))
cmd.Flags().StringVar(&options.Channel, "channel", options.Channel, "Channel for default versions and configuration to use")
cmd.RegisterFlagCompletionFunc("channel", completeChannel)
// Network topology
cmd.Flags().StringVarP(&options.Topology, "topology", "t", options.Topology, "Controls network topology for the cluster: public|private.")
cmd.Flags().StringVarP(&options.Topology, "topology", "t", options.Topology, "Network topology for the cluster: public or private.")
cmd.RegisterFlagCompletionFunc("topology", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return []string{api.TopologyPublic, api.TopologyPrivate}, cobra.ShellCompDirectiveNoFileComp
})
// Authorization
cmd.Flags().StringVar(&options.Authorization, "authorization", options.Authorization, "Authorization mode to use: "+cloudup.AuthorizationFlagAlwaysAllow+" or "+cloudup.AuthorizationFlagRBAC)
cmd.Flags().StringVar(&options.Authorization, "authorization", options.Authorization, "Authorization mode: "+cloudup.AuthorizationFlagAlwaysAllow+" or "+cloudup.AuthorizationFlagRBAC)
cmd.RegisterFlagCompletionFunc("authorization", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return []string{cloudup.AuthorizationFlagAlwaysAllow, cloudup.AuthorizationFlagRBAC}, cobra.ShellCompDirectiveNoFileComp
})
// DNS
cmd.Flags().StringVar(&options.DNSType, "dns", options.DNSType, "DNS hosted zone to use: public|private.")
cmd.Flags().StringVar(&options.DNSType, "dns", options.DNSType, "DNS type to use: public or private.")
cmd.RegisterFlagCompletionFunc("dns", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return []string{"public", "private"}, cobra.ShellCompDirectiveNoFileComp
})
// Bastion
cmd.Flags().BoolVar(&options.Bastion, "bastion", options.Bastion, "Pass the --bastion flag to enable a bastion instance group. Only applies to private topology.")
cmd.Flags().BoolVar(&options.Bastion, "bastion", options.Bastion, "Enable a bastion instance group. Only applies to private topology.")
// Allow custom tags from the CLI
cmd.Flags().StringVar(&options.CloudLabels, "cloud-labels", options.CloudLabels, "A list of key/value pairs used to tag all instance groups (for example \"Owner=John Doe,Team=Some Team\").")
cmd.RegisterFlagCompletionFunc("cloud-labels", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return nil, cobra.ShellCompDirectiveNoFileComp
})
// Master and Node Tenancy
cmd.Flags().StringVar(&options.MasterTenancy, "master-tenancy", options.MasterTenancy, "The tenancy of the master group on AWS. Can either be default or dedicated.")
@ -741,3 +793,141 @@ func loadSSHPublicKeys(sshPublicKey string) (map[string][]byte, error) {
}
return sshPublicKeys, nil
}
func completeZone(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
// TODO call into cloud provider(s) to get list of valid zones
return nil, cobra.ShellCompDirectiveNoFileComp
}
func completeKubernetesVersion(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
kopsVersion, err := kopsutil.ParseKubernetesVersion(kopsbase.KOPS_RELEASE_VERSION)
if err != nil {
commandutils.CompletionError("parsing kops version", err)
}
tooNewVersion := kopsVersion
tooNewVersion.Minor++
tooNewVersion.Pre = nil
tooNewVersion.Build = nil
repo, err := name.NewRepository("k8s.gcr.io/kube-apiserver")
if err != nil {
return commandutils.CompletionError("parsing kube-apiserver repo", err)
}
tags, err := remote.List(repo)
if err != nil {
return commandutils.CompletionError("listing kube-apiserver tags", err)
}
versions := sets.NewString()
for _, tag := range tags {
parsed, err := kopsutil.ParseKubernetesVersion(tag)
if err != nil {
continue
}
if kopsutil.IsKubernetesGTE(cloudup.OldestSupportedKubernetesVersion, *parsed) &&
!kopsutil.IsKubernetesGTE(tooNewVersion.String(), *parsed) {
versions.Insert(parsed.String())
}
}
// Remove pre-release versions that have a subsequent stable version.
for _, version := range versions.UnsortedList() {
split := strings.Split(version, "-")
if len(split) > 1 && versions.Has(split[0]) {
versions.Delete(version)
}
}
return versions.List(), cobra.ShellCompDirectiveNoFileComp
}
func completeInstanceImage(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
// TODO call into cloud provider(s) to get list of valid images
return nil, cobra.ShellCompDirectiveNoFileComp
}
func completeMachineType(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
// TODO call into cloud provider(s) to get list of valid machine types
return nil, cobra.ShellCompDirectiveNoFileComp
}
func completeNetworkID(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
// TODO call into cloud provider(s) to get list of valid VPCs
return nil, cobra.ShellCompDirectiveNoFileComp
}
func completeSubnetID(options *CreateClusterOptions) func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
// TODO call into cloud provider(s) to get list of valid Subnet IDs
return nil, cobra.ShellCompDirectiveNoFileComp
}
}
func completeStorageType(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
// TODO call into cloud provider(s) to get list of valid storage types
return nil, cobra.ShellCompDirectiveNoFileComp
}
func completeNetworking(options *CreateClusterOptions) func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
completions := []string{
"external",
"cni",
"calico",
"cilium",
"cilium-etcd",
}
if !options.IPv6 {
completions = append(completions,
"kubenet",
"kopeio",
"weave",
"flannel",
"canal",
"kube-router",
)
if options.CloudProvider == "aws" || options.CloudProvider == "" {
completions = append(completions, "amazonvpc", "lyftvpc")
}
if cloudup.AlphaAllowGCE.Enabled() && (options.CloudProvider == "gce" || options.CloudProvider == "") {
completions = append(completions, "gce")
}
}
return completions, cobra.ShellCompDirectiveNoFileComp
}
}
func completeDNSZone(options *CreateClusterOptions) func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
commandutils.ConfigureKlogForCompletion()
clusterName, completions, directive := GetClusterNameForCompletionNoKubeconfig(args)
if clusterName == "" {
return completions, directive
}
zone := clusterName
completions = nil
for {
split := strings.SplitN(zone, ".", 2)
if len(split) != 2 || !strings.Contains(split[1], ".") {
break
}
zone = split[1]
// TODO Verify the zone against the cloud's DNS provider?
completions = append(completions, zone)
}
return completions, cobra.ShellCompDirectiveNoFileComp
}
}
func completeSecurityGroup(options *CreateClusterOptions) func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
// TODO call into cloud provider(s) to get list of valid Security groups
return nil, cobra.ShellCompDirectiveNoFileComp
}
}

View File

@ -216,6 +216,21 @@ func (c *RootCmd) clusterNameArgs(clusterName *string) func(cmd *cobra.Command,
}
}
func (c *RootCmd) clusterNameArgsNoKubeconfig(clusterName *string) func(cmd *cobra.Command, args []string) error {
return func(cmd *cobra.Command, args []string) error {
if err := c.ProcessArgs(args); err != nil {
return err
}
*clusterName = c.clusterName
if *clusterName == "" {
return fmt.Errorf("--name is required")
}
return nil
}
}
// ProcessArgs will parse the positional args. It assumes one of these formats:
// * <no arguments at all>
// * <clustername> (and --name not specified)
@ -317,6 +332,19 @@ func GetCluster(ctx context.Context, factory commandutils.Factory, clusterName s
return cluster, nil
}
func GetClusterNameForCompletionNoKubeconfig(clusterArgs []string) (clusterName string, completions []string, directive cobra.ShellCompDirective) {
if len(clusterArgs) > 0 {
return clusterArgs[0], nil, 0
}
if rootCommand.clusterName != "" {
return rootCommand.clusterName, nil, 0
}
return "", []string{"--name"}, cobra.ShellCompDirectiveNoFileComp
}
func GetClusterForCompletion(ctx context.Context, factory commandutils.Factory, clusterArgs []string) (cluster *kopsapi.Cluster, clientSet simple.Clientset, completions []string, directive cobra.ShellCompDirective) {
clusterName := ""

View File

@ -115,9 +115,7 @@ func NewCmdUpdateCluster(f *util.Factory, out io.Writer) *cobra.Command {
cmd.Flags().BoolVarP(&options.Yes, "yes", "y", options.Yes, "Create cloud resources, without --yes update is in dry run mode")
cmd.Flags().StringVar(&options.Target, "target", options.Target, "Target - direct, terraform, cloudformation")
cmd.RegisterFlagCompletionFunc("target", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return []string{cloudup.TargetDirect, cloudup.TargetDryRun, cloudup.TargetTerraform, cloudup.TargetCloudformation}, cobra.ShellCompDirectiveNoFileComp
})
cmd.RegisterFlagCompletionFunc("target", completeTarget)
cmd.Flags().StringVar(&options.SSHPublicKey, "ssh-public-key", options.SSHPublicKey, "SSH public key to use (deprecated: use kops create secret instead)")
cmd.Flags().StringVar(&options.OutDir, "out", options.OutDir, "Path to write any local output")
cmd.MarkFlagDirname("out")
@ -470,6 +468,10 @@ func hasKubecfg(contextName string) (bool, error) {
return false, nil
}
func completeTarget(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return []string{cloudup.TargetDirect, cloudup.TargetDryRun, cloudup.TargetTerraform, cloudup.TargetCloudformation}, cobra.ShellCompDirectiveNoFileComp
}
func completeLifecycleOverrides(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
split := strings.SplitAfter(toComplete, "=")

View File

@ -80,10 +80,7 @@ func NewCmdUpgradeCluster(f *util.Factory, out io.Writer) *cobra.Command {
cmd.Flags().BoolVarP(&options.Yes, "yes", "y", false, "Apply update")
cmd.Flags().StringVar(&options.Channel, "channel", "", "Channel to use for upgrade")
cmd.RegisterFlagCompletionFunc("channel", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
// TODO implement completion against VFS
return []string{"alpha", "stable"}, cobra.ShellCompDirectiveNoFileComp
})
cmd.RegisterFlagCompletionFunc("channel", completeChannel)
return cmd
}
@ -298,3 +295,8 @@ func RunUpgradeCluster(ctx context.Context, f *util.Factory, out io.Writer, opti
return nil
}
func completeChannel(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
// TODO implement completion against VFS
return []string{"alpha", "stable"}, cobra.ShellCompDirectiveNoFileComp
}

View File

@ -7,12 +7,12 @@ Create a Kubernetes cluster.
### Synopsis
Create a kubernetes cluster using command line flags. This command creates cloud based resources such as networks and virtual machines. Once the infrastructure is in place Kubernetes is installed on the virtual machines.
Create a Kubernetes cluster using command line flags. This command creates cloud based resources such as networks and virtual machines. Once the infrastructure is in place Kubernetes is installed on the virtual machines.
These operations are done in parallel and rely on eventual consistency.
```
kops create cluster [flags]
kops create cluster [CLUSTER] [flags]
```
### Examples
@ -24,7 +24,7 @@ kops create cluster [flags]
--zones=us-east-1a \
--node-count=2
# Create a cluster in AWS with HA masters. This cluster
# Create a cluster in AWS with High Availability masters. This cluster
# has also been configured for private networking in a kops-managed VPC.
# The bastion flag is set to create an entrypoint for admins to SSH.
export KOPS_STATE_STORE="s3://my-state-store"
@ -42,12 +42,11 @@ kops create cluster [flags]
--bastion="true" \
--yes
# Create a cluster in GCE.
# Note: GCE support is not GA.
export KOPS_FEATURE_FLAGS=AlphaAllowGCE
export KOPS_STATE_STORE="gs://my-state-store"
export ZONES="us-east1-a,us-east1-b,us-east1-c"
# Create a cluster in Digital Ocean.
export KOPS_STATE_STORE="do://my-state-store"
export ZONES="NYC1"
kops create cluster k8s-cluster.example.com \
--cloud digitalocean \
--zones $ZONES \
--master-zones $ZONES \
--node-count 3 \
@ -71,38 +70,38 @@ kops create cluster [flags]
--api-loadbalancer-type string Sets the API loadbalancer type to either 'public' or 'internal'
--api-ssl-certificate string Currently only supported in AWS. Sets the ARN of the SSL Certificate to use for the API server loadbalancer.
--associate-public-ip Specify --associate-public-ip=[true|false] to enable/disable association of public IP for master ASG and nodes. Default is 'true'.
--authorization string Authorization mode to use: AlwaysAllow or RBAC (default "RBAC")
--bastion Pass the --bastion flag to enable a bastion instance group. Only applies to private topology.
--authorization string Authorization mode: AlwaysAllow or RBAC (default "RBAC")
--bastion Enable a bastion instance group. Only applies to private topology.
--channel string Channel for default versions and configuration to use (default "stable")
--cloud string Cloud provider to use - gce, aws, openstack
--cloud string Cloud provider to use - aws, digitalocean, openstack
--cloud-labels string A list of key/value pairs used to tag all instance groups (for example "Owner=John Doe,Team=Some Team").
--container-runtime string Container runtime to use: containerd, docker
--disable-subnet-tags Set to disable automatic subnet tagging
--dns string DNS hosted zone to use: public|private. (default "Public")
--dns-zone string DNS hosted zone to use (defaults to longest matching zone)
--disable-subnet-tags Disable automatic subnet tagging
--dns string DNS type to use: public or private. (default "Public")
--dns-zone string DNS hosted zone (defaults to longest matching zone)
--dry-run If true, only print the object that would be sent, without sending it. This flag can be used to create a cluster YAML or JSON manifest.
--encrypt-etcd-storage Generate key in aws kms and use it for encrypt etcd volumes
--etcd-storage-type string The default storage type for etc members
--encrypt-etcd-storage Generate key in AWS KMS and use it for encrypt etcd volumes
--etcd-storage-type string The default storage type for etcd members
--gce-service-account string Service account with which the GCE VM runs. Warning: if not set, VMs will run as default compute service account.
-h, --help help for cluster
--image string Set image for all instances.
--image string Machine image for all instances
--kubernetes-version string Version of kubernetes to run (defaults to version in channel)
--master-count int32 Set number of masters. Defaults to one master per master-zone
--master-image string Set image for masters. Takes precedence over --image
--master-count int32 Number of masters. Defaults to one master per master-zone
--master-image string Machine image for masters. Takes precedence over --image
--master-public-name string Sets the public master public name
--master-security-groups strings Add precreated additional security groups to masters.
--master-size string Set instance size for masters
--master-security-groups strings Additional precreated security groups to add to masters.
--master-size string Machine type for masters
--master-tenancy string The tenancy of the master group on AWS. Can either be default or dedicated.
--master-volume-size int32 Set instance volume size (in GB) for masters
--master-volume-size int32 Instance volume size (in GB) for masters
--master-zones strings Zones in which to run masters (must be an odd number)
--network-cidr string Set to override the default network CIDR
--networking string Networking mode to use. kubenet, external, weave, flannel-vxlan (or flannel), flannel-udp, calico, canal, kube-router, amazonvpc, cilium, cilium-etcd, cni, lyftvpc. (default "kubenet")
--node-count int32 Set total number of nodes. Defaults to one node per zone
--node-image string Set image for nodes. Takes precedence over --image
--node-security-groups strings Add precreated additional security groups to nodes.
--node-size string Set instance size for nodes
--network-cidr string Network CIDR to use
--networking string Networking mode. kubenet, external, weave, flannel-vxlan (or flannel), flannel-udp, calico, canal, kube-router, amazonvpc, cilium, cilium-etcd, cni, lyftvpc. (default "kubenet")
--node-count int32 Total number of worker nodes. Defaults to one node per zone
--node-image string Machine image for worker nodes. Takes precedence over --image
--node-security-groups strings Additional precreated security groups to add to worker nodes.
--node-size string Machine type for worker nodes
--node-tenancy string The tenancy of the node group on AWS. Can be either default or dedicated.
--node-volume-size int32 Set instance volume size (in GB) for nodes
--node-volume-size int32 Instance volume size (in GB) for worker nodes
--os-dns-servers string comma separated list of DNS Servers which is used in network
--os-ext-net string The name of the external network to use with the openstack router
--os-ext-subnet string The name of the external floating subnet to use with the openstack router
@ -115,11 +114,11 @@ kops create cluster [flags]
--project string Project to use (must be set on GCE)
--ssh-access strings Restrict SSH access to this CIDR. If not set, uses the value of the admin-access flag.
--ssh-public-key string SSH public key to use (defaults to ~/.ssh/id_rsa.pub on AWS)
--subnets strings Set to use shared subnets
--subnets strings Shared subnets to use
--target string Valid targets: direct, terraform, cloudformation. Set this flag to terraform if you want kOps to generate terraform (default "direct")
-t, --topology string Controls network topology for the cluster: public|private. (default "public")
--utility-subnets strings Set to use shared utility subnets
--vpc string Set to use a shared VPC
-t, --topology string Network topology for the cluster: public or private. (default "public")
--utility-subnets strings Shared utility subnets to use
--vpc string Shared VPC to use
-y, --yes Specify --yes to immediately create the cluster
--zones strings Zones in which to run the cluster
```

View File

@ -18,12 +18,14 @@ package cloudup
import (
"fmt"
"sort"
"strings"
"k8s.io/klog/v2"
"k8s.io/kops/dnsprovider/pkg/dnsprovider"
"k8s.io/kops/dnsprovider/pkg/dnsprovider/providers/aws/route53"
"k8s.io/kops/pkg/apis/kops"
"k8s.io/kops/pkg/featureflag"
"k8s.io/kops/upup/pkg/fi"
"k8s.io/kops/upup/pkg/fi/cloudup/aliup"
"k8s.io/kops/upup/pkg/fi/cloudup/awsup"
@ -168,6 +170,26 @@ func BuildCloud(cluster *kops.Cluster) (fi.Cloud, error) {
return cloud, nil
}
func SupportedClouds() []string {
clouds := []string{
string(kops.CloudProviderAWS),
string(kops.CloudProviderDO),
string(kops.CloudProviderOpenstack),
}
if AlphaAllowALI.Enabled() {
clouds = append(clouds, string(kops.CloudProviderALI))
}
if featureflag.Azure.Enabled() {
clouds = append(clouds, string(kops.CloudProviderAzure))
}
if AlphaAllowGCE.Enabled() {
clouds = append(clouds, string(kops.CloudProviderGCE))
}
sort.Strings(clouds)
return clouds
}
func FindDNSHostedZone(dns dnsprovider.Interface, clusterDNSName string, dnsType kops.DNSType) (string, error) {
klog.V(2).Infof("Querying for all DNS zones to find match for %q", clusterDNSName)