Merge pull request #1444 from tsupertramp/allow-adding-existing-security-groups

Allow adding existing security groups
This commit is contained in:
Justin Santa Barbara 2017-01-31 00:27:40 -05:00 committed by GitHub
commit 37bfe29406
12 changed files with 117 additions and 74 deletions

View File

@ -37,27 +37,29 @@ import (
) )
type CreateClusterOptions struct { type CreateClusterOptions struct {
ClusterName string ClusterName string
Yes bool Yes bool
Target string Target string
Models string Models string
Cloud string Cloud string
Zones string Zones []string
MasterZones string MasterZones []string
NodeSize string NodeSize string
MasterSize string MasterSize string
NodeCount int32 NodeCount int32
Project string Project string
KubernetesVersion string KubernetesVersion string
OutDir string OutDir string
Image string Image string
SSHPublicKey string SSHPublicKey string
VPCID string VPCID string
NetworkCIDR string NetworkCIDR string
DNSZone string DNSZone string
AdminAccess []string AdminAccess []string
Networking string Networking string
AssociatePublicIP *bool NodeSecurityGroups []string
MasterSecurityGroups []string
AssociatePublicIP *bool
// Channel is the location of the api.Channel to use for our defaults // Channel is the location of the api.Channel to use for our defaults
Channel string Channel string
@ -126,8 +128,8 @@ func NewCmdCreateCluster(f *util.Factory, out io.Writer) *cobra.Command {
cmd.Flags().StringVar(&options.Cloud, "cloud", options.Cloud, "Cloud provider to use - gce, aws") cmd.Flags().StringVar(&options.Cloud, "cloud", options.Cloud, "Cloud provider to use - gce, aws")
cmd.Flags().StringVar(&options.Zones, "zones", options.Zones, "Zones in which to run the cluster") cmd.Flags().StringSliceVar(&options.Zones, "zones", options.Zones, "Zones in which to run the cluster")
cmd.Flags().StringVar(&options.MasterZones, "master-zones", options.MasterZones, "Zones in which to run masters (must be an odd number)") cmd.Flags().StringSliceVar(&options.MasterZones, "master-zones", options.MasterZones, "Zones in which to run masters (must be an odd number)")
cmd.Flags().StringVar(&options.Project, "project", options.Project, "Project to use (must be set on GCE)") cmd.Flags().StringVar(&options.Project, "project", options.Project, "Project to use (must be set on GCE)")
cmd.Flags().StringVar(&options.KubernetesVersion, "kubernetes-version", options.KubernetesVersion, "Version of kubernetes to run (defaults to version in channel)") cmd.Flags().StringVar(&options.KubernetesVersion, "kubernetes-version", options.KubernetesVersion, "Version of kubernetes to run (defaults to version in channel)")
@ -154,6 +156,9 @@ func NewCmdCreateCluster(f *util.Factory, out io.Writer) *cobra.Command {
// TODO: Can we deprecate this flag - it is awkward? // 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'.") 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'.")
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().StringVar(&options.Channel, "channel", options.Channel, "Channel for default versions and configuration to use") cmd.Flags().StringVar(&options.Channel, "channel", options.Channel, "Channel for default versions and configuration to use")
// Network topology // Network topology
@ -251,13 +256,13 @@ func RunCreateCluster(f *util.Factory, out io.Writer, c *CreateClusterOptions) e
glog.V(4).Infof("networking mode=%s => %s", c.Networking, fi.DebugAsJsonString(cluster.Spec.Networking)) glog.V(4).Infof("networking mode=%s => %s", c.Networking, fi.DebugAsJsonString(cluster.Spec.Networking))
if c.Zones != "" { if len(c.Zones) != 0 {
existingSubnets := make(map[string]*api.ClusterSubnetSpec) existingSubnets := make(map[string]*api.ClusterSubnetSpec)
for i := range cluster.Spec.Subnets { for i := range cluster.Spec.Subnets {
subnet := &cluster.Spec.Subnets[i] subnet := &cluster.Spec.Subnets[i]
existingSubnets[subnet.Name] = subnet existingSubnets[subnet.Name] = subnet
} }
for _, zoneName := range parseZoneList(c.Zones) { for _, zoneName := range c.Zones {
// We create default subnets named the same as the zones // We create default subnets named the same as the zones
subnetName := zoneName subnetName := zoneName
if existingSubnets[subnetName] == nil { if existingSubnets[subnetName] == nil {
@ -278,7 +283,7 @@ func RunCreateCluster(f *util.Factory, out io.Writer, c *CreateClusterOptions) e
var nodes []*api.InstanceGroup var nodes []*api.InstanceGroup
var instanceGroups []*api.InstanceGroup var instanceGroups []*api.InstanceGroup
if c.MasterZones == "" { if len(c.MasterZones) == 0 {
if len(masters) == 0 { if len(masters) == 0 {
// We default to single-master (not HA), unless the user explicitly specifies it // We default to single-master (not HA), unless the user explicitly specifies it
// HA master is a little slower, not as well tested yet, and requires more resources // HA master is a little slower, not as well tested yet, and requires more resources
@ -300,7 +305,7 @@ func RunCreateCluster(f *util.Factory, out io.Writer, c *CreateClusterOptions) e
} else { } else {
if len(masters) == 0 { if len(masters) == 0 {
// Use the specified master zones (this is how the user gets HA master) // Use the specified master zones (this is how the user gets HA master)
for _, subnetName := range parseZoneList(c.MasterZones) { for _, subnetName := range c.MasterZones {
g := &api.InstanceGroup{} g := &api.InstanceGroup{}
g.Spec.Role = api.InstanceGroupRoleMaster g.Spec.Role = api.InstanceGroupRoleMaster
g.Spec.Subnets = []string{subnetName} g.Spec.Subnets = []string{subnetName}
@ -370,6 +375,7 @@ func RunCreateCluster(f *util.Factory, out io.Writer, c *CreateClusterOptions) e
if len(nodes) == 0 { if len(nodes) == 0 {
g := &api.InstanceGroup{} g := &api.InstanceGroup{}
g.Spec.Role = api.InstanceGroupRoleNode g.Spec.Role = api.InstanceGroupRoleNode
g.ObjectMeta.Name = "nodes" g.ObjectMeta.Name = "nodes"
instanceGroups = append(instanceGroups, g) instanceGroups = append(instanceGroups, g)
nodes = append(nodes, g) nodes = append(nodes, g)
@ -400,6 +406,18 @@ func RunCreateCluster(f *util.Factory, out io.Writer, c *CreateClusterOptions) e
} }
} }
if len(c.NodeSecurityGroups) > 0 {
for _, group := range nodes {
group.Spec.AdditionalSecurityGroups = c.NodeSecurityGroups
}
}
if len(c.MasterSecurityGroups) > 0 {
for _, group := range masters {
group.Spec.AdditionalSecurityGroups = c.MasterSecurityGroups
}
}
if c.MasterSize != "" { if c.MasterSize != "" {
for _, group := range masters { for _, group := range masters {
group.Spec.MachineType = c.MasterSize group.Spec.MachineType = c.MasterSize
@ -684,19 +702,6 @@ func RunCreateCluster(f *util.Factory, out io.Writer, c *CreateClusterOptions) e
return nil return nil
} }
func parseZoneList(s string) []string {
var filtered []string
for _, v := range strings.Split(s, ",") {
v = strings.TrimSpace(v)
if v == "" {
continue
}
v = strings.ToLower(v)
filtered = append(filtered, v)
}
return filtered
}
func supportsPrivateTopology(n *api.NetworkingSpec) bool { func supportsPrivateTopology(n *api.NetworkingSpec) bool {
if n.CNI != nil || n.Kopeio != nil || n.Weave != nil || n.Calico != nil { if n.CNI != nil || n.Kopeio != nil || n.Weave != nil || n.Calico != nil {

View File

@ -10,8 +10,10 @@ kops create cluster \
--dns-zone kubernetes.com \ --dns-zone kubernetes.com \
--node-size t2.medium \ --node-size t2.medium \
--master-size t2.medium \ --master-size t2.medium \
--node-security-groups i-123456 \
--master-security-groups i-123456,i-123457 \
--topology private \ --topology private \
--networking weave \ --networking weave \
--image 293135079892/k8s-1.4-debian-jessie-amd64-hvm-ebs-2016-11-16 \ --image 293135079892/k8s-1.4-debian-jessie-amd64-hvm-ebs-2016-11-16 \
${NAME} ${NAME}
``` ```

View File

@ -14,29 +14,31 @@ kops create cluster
### Options ### Options
``` ```
--admin-access string Restrict access to admin endpoints (SSH, HTTPS) to this CIDR. If not set, access will not be restricted by IP. --admin-access string Restrict access to admin endpoints (SSH, HTTPS) to this CIDR. If not set, access will not be restricted by IP.
--associate-public-ip Specify --associate-public-ip=[true|false] to enable/disable association of public IP for master ASG and nodes. Default is 'true'. (default true) --associate-public-ip Specify --associate-public-ip=[true|false] to enable/disable association of public IP for master ASG and nodes. Default is 'true'. (default true)
--bastion Pass the --bastion flag to enable a bastion instance group. Only applies to private topology. --bastion Pass the --bastion flag to enable a bastion instance group. Only applies to private topology.
--channel string Channel for default versions and configuration to use (default "stable") --channel string Channel for default versions and configuration to use (default "stable")
--cloud string Cloud provider to use - gce, aws --cloud string Cloud provider to use - gce, aws
--dns-zone string DNS hosted zone to use (defaults to longest matching zone) --dns-zone string DNS hosted zone to use (defaults to longest matching zone)
--image string Image to use --image string Image to use
--kubernetes-version string Version of kubernetes to run (defaults to version in channel) --kubernetes-version string Version of kubernetes to run (defaults to version in channel)
--master-size string Set instance size for masters --master-security-groups string Add precreated additional security groups to masters.
--master-zones string Zones in which to run masters (must be an odd number) --master-size string Set instance size for masters
--model string Models to apply (separate multiple models with commas) (default "config,proto,cloudup") --master-zones string Zones in which to run masters (must be an odd number)
--network-cidr string Set to override the default network CIDR --model string Models to apply (separate multiple models with commas) (default "config,proto,cloudup")
--networking string Networking mode to use. kubenet (default), classic, external, cni, kopeio-vxlan, weave, calico. (default "kubenet") --network-cidr string Set to override the default network CIDR
--node-count int Set the number of nodes --networking string Networking mode to use. kubenet (default), classic, external, cni, kopeio-vxlan, weave, calico. (default "kubenet")
--node-size string Set instance size for nodes --node-count int Set the number of nodes
--out string Path to write any local output --node-security-groups string Add precreated additional security groups to nodes.
--project string Project to use (must be set on GCE) --node-size string Set instance size for nodes
--ssh-public-key string SSH public key to use (default "~/.ssh/id_rsa.pub") --out string Path to write any local output
--target string Target - direct, terraform (default "direct") --project string Project to use (must be set on GCE)
-t, --topology string Controls network topology for the cluster. public|private. Default is 'public'. (default "public") --ssh-public-key string SSH public key to use (default "~/.ssh/id_rsa.pub")
--vpc string Set to use a shared VPC --target string Target - direct, terraform (default "direct")
--yes Specify --yes to immediately create the cluster -t, --topology string Controls network topology for the cluster. public|private. Default is 'public'. (default "public")
--zones string Zones in which to run the cluster --vpc string Set to use a shared VPC
--yes Specify --yes to immediately create the cluster
--zones string Zones in which to run the cluster
``` ```
### Options inherited from parent commands ### Options inherited from parent commands

View File

@ -81,6 +81,9 @@ type InstanceGroupSpec struct {
// AssociatePublicIP is true if we want instances to have a public IP // AssociatePublicIP is true if we want instances to have a public IP
AssociatePublicIP *bool `json:"associatePublicIp,omitempty"` AssociatePublicIP *bool `json:"associatePublicIp,omitempty"`
// AdditionalSecurityGroups attaches additional security groups (e.g. i-123456)
AdditionalSecurityGroups []string `json:"additionalSecurityGroups,omitempty"`
// CloudLabels indicates the labels for instances in this group, at the AWS level // CloudLabels indicates the labels for instances in this group, at the AWS level
CloudLabels map[string]string `json:"cloudLabels,omitempty"` CloudLabels map[string]string `json:"cloudLabels,omitempty"`

View File

@ -69,6 +69,9 @@ type InstanceGroupSpec struct {
// AssociatePublicIP is true if we want instances to have a public IP // AssociatePublicIP is true if we want instances to have a public IP
AssociatePublicIP *bool `json:"associatePublicIp,omitempty"` AssociatePublicIP *bool `json:"associatePublicIp,omitempty"`
// AdditionalSecurityGroups attaches additional security groups (e.g. i-123456)
AdditionalSecurityGroups []string `json:"additionalSecurityGroups,omitempty"`
// CloudLabels indicates the labels for instances in this group, at the AWS level // CloudLabels indicates the labels for instances in this group, at the AWS level
CloudLabels map[string]string `json:"cloudLabels,omitempty"` CloudLabels map[string]string `json:"cloudLabels,omitempty"`

View File

@ -899,6 +899,7 @@ func autoConvert_v1alpha1_InstanceGroupSpec_To_kops_InstanceGroupSpec(in *Instan
// WARNING: in.Zones requires manual conversion: does not exist in peer-type // WARNING: in.Zones requires manual conversion: does not exist in peer-type
out.MaxPrice = in.MaxPrice out.MaxPrice = in.MaxPrice
out.AssociatePublicIP = in.AssociatePublicIP out.AssociatePublicIP = in.AssociatePublicIP
out.AdditionalSecurityGroups = in.AdditionalSecurityGroups
out.CloudLabels = in.CloudLabels out.CloudLabels = in.CloudLabels
out.NodeLabels = in.NodeLabels out.NodeLabels = in.NodeLabels
return nil return nil
@ -915,6 +916,7 @@ func autoConvert_kops_InstanceGroupSpec_To_v1alpha1_InstanceGroupSpec(in *kops.I
// WARNING: in.Subnets requires manual conversion: does not exist in peer-type // WARNING: in.Subnets requires manual conversion: does not exist in peer-type
out.MaxPrice = in.MaxPrice out.MaxPrice = in.MaxPrice
out.AssociatePublicIP = in.AssociatePublicIP out.AssociatePublicIP = in.AssociatePublicIP
out.AdditionalSecurityGroups = in.AdditionalSecurityGroups
out.CloudLabels = in.CloudLabels out.CloudLabels = in.CloudLabels
out.NodeLabels = in.NodeLabels out.NodeLabels = in.NodeLabels
return nil return nil

View File

@ -76,6 +76,9 @@ type InstanceGroupSpec struct {
// AssociatePublicIP is true if we want instances to have a public IP // AssociatePublicIP is true if we want instances to have a public IP
AssociatePublicIP *bool `json:"associatePublicIp,omitempty"` AssociatePublicIP *bool `json:"associatePublicIp,omitempty"`
// AdditionalSecurityGroups attaches additional security groups (e.g. i-123456)
AdditionalSecurityGroups []string `json:"additionalSecurityGroups,omitempty"`
// CloudLabels indicates the labels for instances in this group, at the AWS level // CloudLabels indicates the labels for instances in this group, at the AWS level
CloudLabels map[string]string `json:"cloudLabels,omitempty"` CloudLabels map[string]string `json:"cloudLabels,omitempty"`

View File

@ -66,9 +66,10 @@ func (b *AutoscalingGroupModelBuilder) Build(c *fi.ModelBuilderContext) error {
SecurityGroups: []*awstasks.SecurityGroup{ SecurityGroups: []*awstasks.SecurityGroup{
b.LinkToSecurityGroup(ig.Spec.Role), b.LinkToSecurityGroup(ig.Spec.Role),
}, },
IAMInstanceProfile: b.LinkToIAMInstanceProfile(ig), AdditionalSecurityGroupIDs: ig.Spec.AdditionalSecurityGroups,
ImageID: s(ig.Spec.Image), IAMInstanceProfile: b.LinkToIAMInstanceProfile(ig),
InstanceType: s(ig.Spec.MachineType), ImageID: s(ig.Spec.Image),
InstanceType: s(ig.Spec.MachineType),
RootVolumeSize: i64(int64(volumeSize)), RootVolumeSize: i64(int64(volumeSize)),
RootVolumeType: s(volumeType), RootVolumeType: s(volumeType),

View File

@ -68,6 +68,9 @@ metadata:
kops.k8s.io/cluster: private.example.com kops.k8s.io/cluster: private.example.com
name: master-us-test-1a name: master-us-test-1a
spec: spec:
additionalSecurityGroups:
- i-exampleid3
- i-exampleid4
image: kope.io/k8s-1.4-debian-jessie-amd64-hvm-ebs-2016-10-21 image: kope.io/k8s-1.4-debian-jessie-amd64-hvm-ebs-2016-10-21
machineType: m3.medium machineType: m3.medium
maxSize: 1 maxSize: 1
@ -86,6 +89,9 @@ metadata:
kops.k8s.io/cluster: private.example.com kops.k8s.io/cluster: private.example.com
name: nodes name: nodes
spec: spec:
additionalSecurityGroups:
- i-exampleid
- i-exampleid2
image: kope.io/k8s-1.4-debian-jessie-amd64-hvm-ebs-2016-10-21 image: kope.io/k8s-1.4-debian-jessie-amd64-hvm-ebs-2016-10-21
machineType: t2.medium machineType: t2.medium
maxSize: 2 maxSize: 2

View File

@ -74,6 +74,9 @@ metadata:
kops.k8s.io/cluster: private.example.com kops.k8s.io/cluster: private.example.com
name: master-us-test-1a name: master-us-test-1a
spec: spec:
additionalSecurityGroups:
- i-exampleid3
- i-exampleid4
image: kope.io/k8s-1.4-debian-jessie-amd64-hvm-ebs-2016-10-21 image: kope.io/k8s-1.4-debian-jessie-amd64-hvm-ebs-2016-10-21
machineType: m3.medium machineType: m3.medium
maxSize: 1 maxSize: 1
@ -92,6 +95,9 @@ metadata:
kops.k8s.io/cluster: private.example.com kops.k8s.io/cluster: private.example.com
name: nodes name: nodes
spec: spec:
additionalSecurityGroups:
- i-exampleid
- i-exampleid2
image: kope.io/k8s-1.4-debian-jessie-amd64-hvm-ebs-2016-10-21 image: kope.io/k8s-1.4-debian-jessie-amd64-hvm-ebs-2016-10-21
machineType: t2.medium machineType: t2.medium
maxSize: 2 maxSize: 2

View File

@ -3,4 +3,6 @@ Zones: us-test-1a
Cloud: aws Cloud: aws
Topology: private Topology: private
Networking: kopeio-vxlan Networking: kopeio-vxlan
Bastion: true Bastion: true
NodeSecurityGroupIDs: i-exampleid, i-exampleid2
MasterSecurityGroupIDs: i-exampleid3, i-exampleid4

View File

@ -36,12 +36,13 @@ type LaunchConfiguration struct {
UserData *fi.ResourceHolder UserData *fi.ResourceHolder
ImageID *string ImageID *string
InstanceType *string InstanceType *string
SSHKey *SSHKey SSHKey *SSHKey
SecurityGroups []*SecurityGroup SecurityGroups []*SecurityGroup
AssociatePublicIP *bool AdditionalSecurityGroupIDs []string
IAMInstanceProfile *IAMInstanceProfile AssociatePublicIP *bool
IAMInstanceProfile *IAMInstanceProfile
// RootVolumeSize is the size of the EBS root volume to use, in GB // RootVolumeSize is the size of the EBS root volume to use, in GB
RootVolumeSize *int64 RootVolumeSize *int64
@ -227,13 +228,20 @@ func (_ *LaunchConfiguration) RenderAWS(t *awsup.AWSAPITarget, a, e, changes *La
request.LaunchConfigurationName = &launchConfigurationName request.LaunchConfigurationName = &launchConfigurationName
request.ImageId = image.ImageId request.ImageId = image.ImageId
request.InstanceType = e.InstanceType request.InstanceType = e.InstanceType
if e.SSHKey != nil { if e.SSHKey != nil {
request.KeyName = e.SSHKey.Name request.KeyName = e.SSHKey.Name
} }
securityGroupIDs := []*string{} securityGroupIDs := []*string{}
for _, sg := range e.SecurityGroups { for _, sg := range e.SecurityGroups {
securityGroupIDs = append(securityGroupIDs, sg.ID) securityGroupIDs = append(securityGroupIDs, sg.ID)
} }
for i := range e.AdditionalSecurityGroupIDs {
securityGroupIDs = append(securityGroupIDs, &e.AdditionalSecurityGroupIDs[i])
}
request.SecurityGroups = securityGroupIDs request.SecurityGroups = securityGroupIDs
request.AssociatePublicIpAddress = e.AssociatePublicIP request.AssociatePublicIpAddress = e.AssociatePublicIP
if e.SpotPrice != "" { if e.SpotPrice != "" {