Skip to content
This repository has been archived by the owner on Sep 4, 2021. It is now read-only.

kube-aws: validate that the key pair exists #362

Merged
merged 1 commit into from
Apr 12, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions multi-node/aws/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,5 @@
/assets
*~
/_gopath-kube-aws
/_gopath-vendor
/pkg/config/templates.go
11 changes: 6 additions & 5 deletions multi-node/aws/cmd/kube-aws/command_validate.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,13 @@ func runCmdValidate(cmd *cobra.Command, args []string) error {
return fmt.Errorf("Unable to load cluster config: %v", err)
}

//Validate cloudconfig userdata
fmt.Printf("Validating UserData...\n")
if err := cfg.ValidateUserData(stackTemplateOptions); err != nil {
return err
}
fmt.Printf("UserData is valid.\n\n")

fmt.Printf("UserData is valid\n")

//Validate stack template
fmt.Printf("Validating stack template...\n")
data, err := cfg.RenderStackTemplate(stackTemplateOptions)
if err != nil {
return fmt.Errorf("Failed to render stack template: %v", err)
Expand All @@ -54,8 +53,10 @@ func runCmdValidate(cmd *cobra.Command, args []string) error {
}

if err != nil {
return fmt.Errorf("Error creating cluster: %v", err)
return err
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was just leading to output like "Error creating cluster: Error: Key does not exist". I think the "Validating stack template..." output added in the validate command makes the extra messaging unnecessary.

fmt.Printf("stack template is valid.\n\n")

fmt.Printf("Validation OK!\n")
return nil
}
30 changes: 29 additions & 1 deletion multi-node/aws/pkg/cluster/cluster.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"time"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/aws/session"
"github.com/aws/aws-sdk-go/service/cloudformation"
"github.com/aws/aws-sdk-go/service/ec2"
Expand Down Expand Up @@ -72,6 +73,7 @@ func (c *Cluster) ValidateStack(stackBody string) (string, error) {
type ec2Service interface {
DescribeVpcs(*ec2.DescribeVpcsInput) (*ec2.DescribeVpcsOutput, error)
DescribeSubnets(*ec2.DescribeSubnetsInput) (*ec2.DescribeSubnetsOutput, error)
DescribeKeyPairs(*ec2.DescribeKeyPairsInput) (*ec2.DescribeKeyPairsOutput, error)
}

func (c *Cluster) validateExistingVPCState(ec2Svc ec2Service) error {
Expand Down Expand Up @@ -130,6 +132,11 @@ func (c *Cluster) validateExistingVPCState(ec2Svc ec2Service) error {

func (c *Cluster) Create(stackBody string) error {
ec2Svc := ec2.New(c.session)

if err := c.validateKeyPair(ec2Svc); err != nil {
return err
}

if err := c.validateExistingVPCState(ec2Svc); err != nil {
return err
}
Expand Down Expand Up @@ -163,7 +170,11 @@ func (c *Cluster) Create(stackBody string) error {
case cloudformation.ResourceStatusCreateComplete:
return nil
case cloudformation.ResourceStatusCreateFailed:
errMsg := fmt.Sprintf("Stack creation failed: %s : %s", statusString, aws.StringValue(resp.Stacks[0].StackStatusReason))
errMsg := fmt.Sprintf(
"Stack creation failed: %s : %s",
statusString,
aws.StringValue(resp.Stacks[0].StackStatusReason),
)
return errors.New(errMsg)
case cloudformation.ResourceStatusCreateInProgress:
time.Sleep(3 * time.Second)
Expand Down Expand Up @@ -256,3 +267,20 @@ func (c *Cluster) Destroy() error {
_, err := cfSvc.DeleteStack(dreq)
return err
}

func (c *Cluster) validateKeyPair(ec2Svc ec2Service) error {
_, err := ec2Svc.DescribeKeyPairs(&ec2.DescribeKeyPairsInput{
KeyNames: []*string{aws.String(c.KeyName)},
})

if err != nil {
if awsErr, ok := err.(awserr.Error); ok {
if awsErr.Code() == "InvalidKeyPair.NotFound" {
return fmt.Errorf("Key %s does not exist.", c.KeyName)
}
}
return err
}

return nil
}
103 changes: 76 additions & 27 deletions multi-node/aws/pkg/cluster/cluster_test.go
Original file line number Diff line number Diff line change
@@ -1,24 +1,40 @@
package cluster

import (
"errors"
"testing"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/aws/awserr"
"github.com/aws/aws-sdk-go/service/ec2"
"github.com/coreos/coreos-kubernetes/multi-node/aws/pkg/config"
)

type dummyEC2Service map[string]struct {
const minimalConfigYaml = `
externalDNSName: test-external-dns-name
keyName: test-key-name
region: us-west-1
availabilityZone: us-west-1c
clusterName: test-cluster-name
kmsKeyArn: "arn:aws:kms:us-west-1:xxxxxxxxx:key/xxxxxxxxxxxxxxxxxxx"
`

type VPC struct {
cidr string
subnetCidrs []string
}

type dummyEC2Service struct {
VPCs map[string]VPC
KeyPairs map[string]bool
}

func (svc dummyEC2Service) DescribeVpcs(input *ec2.DescribeVpcsInput) (*ec2.DescribeVpcsOutput, error) {
output := ec2.DescribeVpcsOutput{}
for _, vpcId := range input.VpcIds {
if vpc, ok := svc[*vpcId]; ok {
for _, vpcID := range input.VpcIds {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This capitalization makes golint happy, but it's inconsistent with the amazon's naming. I'd prefer to not propagate their deviancy, but I can change this back if we'd rather be consistent.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

golint is our source of truth in these matters.

if vpc, ok := svc.VPCs[*vpcID]; ok {
output.Vpcs = append(output.Vpcs, &ec2.Vpc{
VpcId: vpcId,
VpcId: vpcID,
CidrBlock: aws.String(vpc.cidr),
})
}
Expand All @@ -39,8 +55,8 @@ func (svc dummyEC2Service) DescribeSubnets(input *ec2.DescribeSubnetsInput) (*ec
}
}

for _, vpcId := range vpcIds {
if vpc, ok := svc[vpcId]; ok {
for _, vpcID := range vpcIds {
if vpc, ok := svc.VPCs[vpcID]; ok {
for _, subnetCidr := range vpc.subnetCidrs {
output.Subnets = append(
output.Subnets,
Expand All @@ -53,15 +69,23 @@ func (svc dummyEC2Service) DescribeSubnets(input *ec2.DescribeSubnetsInput) (*ec
return &output, nil
}

func (svc dummyEC2Service) DescribeKeyPairs(input *ec2.DescribeKeyPairsInput) (*ec2.DescribeKeyPairsOutput, error) {
output := &ec2.DescribeKeyPairsOutput{}

for _, keyName := range input.KeyNames {
if _, ok := svc.KeyPairs[*keyName]; ok {
output.KeyPairs = append(output.KeyPairs, &ec2.KeyPairInfo{
KeyName: keyName,
})
} else {
return nil, awserr.New("InvalidKeyPair.NotFound", "", errors.New(""))
}
}

return output, nil
}

func TestExistingVPCValidation(t *testing.T) {
minimalConfigYaml := `
externalDNSName: test-external-dns-name
keyName: test-key-name
region: us-west-1
availabilityZone: us-west-1c
clusterName: test-cluster-name
kmsKeyArn: "arn:aws:kms:us-west-1:xxxxxxxxx:key/xxxxxxxxxxxxxxxxxxx"
`

goodExistingVPCConfigs := []string{
``, //Tests default create VPC mode, which bypasses existing VPC validation
Expand Down Expand Up @@ -108,20 +132,22 @@ routeTableId: rtb-xxxxxx
}

ec2Service := dummyEC2Service{
"vpc-xxx1": {
cidr: "10.5.0.0/16",
subnetCidrs: []string{
"10.5.1.0/24",
"10.5.2.0/24",
"10.5.10.100/29",
VPCs: map[string]VPC{
"vpc-xxx1": {
cidr: "10.5.0.0/16",
subnetCidrs: []string{
"10.5.1.0/24",
"10.5.2.0/24",
"10.5.10.100/29",
},
},
},
"vpc-xxx2": {
cidr: "192.168.1.0/24",
subnetCidrs: []string{
"192.168.1.100/28",
"192.168.1.150/28",
"192.168.1.200/28",
"vpc-xxx2": {
cidr: "192.168.1.0/24",
subnetCidrs: []string{
"192.168.1.100/28",
"192.168.1.150/28",
"192.168.1.200/28",
},
},
},
}
Expand Down Expand Up @@ -152,5 +178,28 @@ routeTableId: rtb-xxxxxx
t.Errorf("Incorrect config tested valid, expected error:\n%s", networkConfig)
}
}
}

func TestValidateKeyPair(t *testing.T) {

clusterConfig, err := config.ClusterFromBytes([]byte(minimalConfigYaml))
if err != nil {
t.Errorf("could not get valid cluster config: %v", err)
}

c := &Cluster{Cluster: *clusterConfig}

ec2Svc := dummyEC2Service{}
ec2Svc.KeyPairs = map[string]bool{
c.KeyName: true,
}

if err := c.validateKeyPair(ec2Svc); err != nil {
t.Errorf("returned an error for valid key")
}

c.KeyName = "invalidKeyName"
if err := c.validateKeyPair(ec2Svc); err == nil {
t.Errorf("failed to catch invalid key \"%s\"", c.KeyName)
}
}