Skip to content

Commit

Permalink
Add logic to pick 3 AZs
Browse files Browse the repository at this point in the history
  • Loading branch information
errordeveloper committed Jul 17, 2018
1 parent b7c60b6 commit 3435db8
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 22 deletions.
70 changes: 57 additions & 13 deletions pkg/eks/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package eks

import (
"fmt"
"math/rand"
"os"
"sync"
"time"
Expand All @@ -25,8 +26,9 @@ import (
)

const (
ClusterNameTag = "eksctl.cluster.k8s.io/v1alpha1/cluster-name"
AWSDebugLevel = 5
ClusterNameTag = "eksctl.cluster.k8s.io/v1alpha1/cluster-name"
AWSDebugLevel = 5
RequiredAvailabilityZones = 3
)

var DefaultWaitTimeout = 20 * time.Minute
Expand All @@ -35,10 +37,9 @@ type ClusterProvider struct {
// core fields used for config and AWS APIs
cfg *ClusterConfig
svc *providerServices

// informative fields, i.e. used as outputs
iamRoleARN string
sessionCreds *credentials.Credentials
// TODO refactor this as ProviderStatus
status providerStatus
}

type providerServices struct {
Expand All @@ -48,6 +49,12 @@ type providerServices struct {
sts stsiface.STSAPI
}

type providerStatus struct {
iamRoleARN string
sessionCreds *credentials.Credentials
availabilityZones []string
}

// simple config, to be replaced with Cluster API
type ClusterConfig struct {
Region string
Expand Down Expand Up @@ -101,36 +108,38 @@ func New(clusterConfig *ClusterConfig) *ClusterProvider {
ec2: ec2.New(s),
sts: sts.New(s),
},
sessionCreds: s.Config.Credentials,
status: providerStatus{
sessionCreds: s.Config.Credentials,
},
}

// override sessions if any custom endpoints specified
if endpoint, ok := os.LookupEnv("AWS_CLOUDFORMATION_ENDPOINT"); ok {
logger.Debug("Setting CloudFormation endpoint to %s", endpoint)
s := newSession(clusterConfig, endpoint, c.sessionCreds)
s := newSession(clusterConfig, endpoint, c.status.sessionCreds)
c.svc.cfn = cloudformation.New(s)
}
if endpoint, ok := os.LookupEnv("AWS_EKS_ENDPOINT"); ok {
logger.Debug("Setting EKS endpoint to %s", endpoint)
s := newSession(clusterConfig, endpoint, c.sessionCreds)
s := newSession(clusterConfig, endpoint, c.status.sessionCreds)
c.svc.eks = eks.New(s)
}
if endpoint, ok := os.LookupEnv("AWS_EC2_ENDPOINT"); ok {
logger.Debug("Setting EC2 endpoint to %s", endpoint)
s := newSession(clusterConfig, endpoint, c.sessionCreds)
s := newSession(clusterConfig, endpoint, c.status.sessionCreds)
c.svc.ec2 = ec2.New(s)
}
if endpoint, ok := os.LookupEnv("AWS_STS_ENDPOINT"); ok {
logger.Debug("Setting STS endpoint to %s", endpoint)
s := newSession(clusterConfig, endpoint, c.sessionCreds)
s := newSession(clusterConfig, endpoint, c.status.sessionCreds)
c.svc.sts = sts.New(s)
}

return c
}

func (c *ClusterProvider) GetCredentialsEnv() ([]string, error) {
creds, err := c.sessionCreds.Get()
creds, err := c.status.sessionCreds.Get()
if err != nil {
return nil, errors.Wrap(err, "getting effective credentials")
}
Expand All @@ -148,8 +157,8 @@ func (c *ClusterProvider) CheckAuth() error {
if err != nil {
return errors.Wrap(err, "checking AWS STS access – cannot get role ARN for current session")
}
c.iamRoleARN = *output.Arn
logger.Debug("role ARN for the current session is %q", c.iamRoleARN)
c.status.iamRoleARN = *output.Arn
logger.Debug("role ARN for the current session is %q", c.status.iamRoleARN)
}
{
input := &cloudformation.ListStacksInput{}
Expand All @@ -160,6 +169,41 @@ func (c *ClusterProvider) CheckAuth() error {
return nil
}

func (c *ClusterProvider) SelectAvailabilityZones() error {
avoidZones := map[string]bool{
// well-known over-populated zones
"us-east1-a": true,
"us-east1-b": true,
}

input := &ec2.DescribeAvailabilityZonesInput{}
output, err := c.svc.ec2.DescribeAvailabilityZones(input)
if err != nil {
return errors.Wrapf(err, "getting availibility zones for %s", c.cfg.Region)
}

usableZones := []string{}
for _, zone := range output.AvailabilityZones {
_, avoidZone := avoidZones[*zone.ZoneName]
if !avoidZone && *zone.State == ec2.AvailabilityZoneStateAvailable {
usableZones = append(usableZones, *zone.ZoneName)
}
}

zones := []string{}
for len(zones) < RequiredAvailabilityZones {
rand := rand.New(rand.NewSource(time.Now().UnixNano()))
for _, r := range rand.Perm(len(usableZones)) {
zones = append(zones, usableZones[r])
if len(zones) == RequiredAvailabilityZones {
break
}
}
}
c.status.availabilityZones = zones
return nil
}

func (c *ClusterProvider) runCreateTask(tasks map[string]func(chan error) error, taskErrs chan error) {
wg := &sync.WaitGroup{}
wg.Add(len(tasks))
Expand Down
12 changes: 6 additions & 6 deletions pkg/eks/assets/1.10.3/2018-06-05/amazon-eks-vpc-sample.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ Parameters:
Default: 192.168.0.0/16
Description: The CIDR range for the VPC. This should be a valid private (RFC 1918) CIDR range.

AvailabilityZones:
Type: List<AWS::EC2::AvailabilityZone::Name>

Subnet01Block:
Type: String
Default: 192.168.64.0/18
Expand Down Expand Up @@ -82,8 +85,7 @@ Resources:
AvailabilityZone:
Fn::Select:
- '0'
- Fn::GetAZs:
Ref: AWS::Region
- !Ref AvailabilityZones
CidrBlock:
Ref: Subnet01Block
VpcId:
Expand All @@ -100,8 +102,7 @@ Resources:
AvailabilityZone:
Fn::Select:
- '1'
- Fn::GetAZs:
Ref: AWS::Region
- !Ref AvailabilityZones
CidrBlock:
Ref: Subnet02Block
VpcId:
Expand All @@ -118,8 +119,7 @@ Resources:
AvailabilityZone:
Fn::Select:
- '2'
- Fn::GetAZs:
Ref: AWS::Region
- !Ref AvailabilityZones
CidrBlock:
Ref: Subnet03Block
VpcId:
Expand Down
4 changes: 2 additions & 2 deletions pkg/eks/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ func (c *ClusterProvider) MaybeDeletePublicSSHKey() {
}

func (c *ClusterProvider) getUsername() string {
usernameParts := strings.Split(c.iamRoleARN, "/")
usernameParts := strings.Split(c.status.iamRoleARN, "/")
if len(usernameParts) > 1 {
return usernameParts[len(usernameParts)-1]
}
Expand Down Expand Up @@ -179,7 +179,7 @@ func (c *ClusterProvider) NewClientConfig() (*ClientConfig, error) {
},
ClusterName: clusterName,
ContextName: contextName,
roleARN: c.iamRoleARN,
roleARN: c.status.iamRoleARN,
sts: c.svc.sts,
}

Expand Down
9 changes: 8 additions & 1 deletion pkg/eks/cfn.go
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,13 @@ func (c *ClusterProvider) stackNameVPC() string {
return "EKS-" + c.cfg.ClusterName + "-VPC"
}

func (c *ClusterProvider) stackParamsVPC() map[string]string {
params := map[string]string{
"AvailabilityZones": strings.Join(c.status.availabilityZones, ","),
}
return params
}

func (c *ClusterProvider) createStackVPC(errs chan error) error {
name := c.stackNameVPC()
logger.Info("creating VPC stack %q", name)
Expand All @@ -162,7 +169,7 @@ func (c *ClusterProvider) createStackVPC(errs chan error) error {
stackChan := make(chan Stack)
taskErrs := make(chan error)

if err := c.CreateStack(name, templateBody, nil, false, stackChan, taskErrs); err != nil {
if err := c.CreateStack(name, templateBody, c.stackParamsVPC(), false, stackChan, taskErrs); err != nil {
return err
}

Expand Down

0 comments on commit 3435db8

Please sign in to comment.