From 68baecafb6108ea1a8d35120329318390b58a85b Mon Sep 17 00:00:00 2001 From: Justin Santa Barbara Date: Sun, 18 Dec 2016 16:04:45 -0500 Subject: [PATCH] Simple test for securitygroups task --- cloudmock/aws/mockec2/api.go | 3 + cloudmock/aws/mockec2/securitygroups.go | 165 ++++++++++++++++++ cloudmock/aws/mockec2/tags.go | 4 + cloudmock/aws/mockec2/unimplemented.go | 72 -------- .../fi/cloudup/awstasks/securitygroup_test.go | 71 ++++++++ 5 files changed, 243 insertions(+), 72 deletions(-) create mode 100644 cloudmock/aws/mockec2/securitygroups.go diff --git a/cloudmock/aws/mockec2/api.go b/cloudmock/aws/mockec2/api.go index 238bfe96e3..e26c5c4025 100644 --- a/cloudmock/aws/mockec2/api.go +++ b/cloudmock/aws/mockec2/api.go @@ -29,6 +29,9 @@ type MockEC2 struct { Images []*ec2.Image + securityGroupNumber int + SecurityGroups []*ec2.SecurityGroup + subnetNumber int Subnets []*ec2.Subnet diff --git a/cloudmock/aws/mockec2/securitygroups.go b/cloudmock/aws/mockec2/securitygroups.go new file mode 100644 index 0000000000..fb3dfb6db5 --- /dev/null +++ b/cloudmock/aws/mockec2/securitygroups.go @@ -0,0 +1,165 @@ +/* +Copyright 2016 The Kubernetes Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package mockec2 + +import ( + "fmt" + "github.com/aws/aws-sdk-go/aws/request" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/golang/glog" + "strings" +) + +func (m *MockEC2) CreateSecurityGroupRequest(*ec2.CreateSecurityGroupInput) (*request.Request, *ec2.CreateSecurityGroupOutput) { + panic("MockEC2 CreateSecurityGroupRequest not implemented") + return nil, nil +} + +func (m *MockEC2) CreateSecurityGroup(request *ec2.CreateSecurityGroupInput) (*ec2.CreateSecurityGroupOutput, error) { + glog.Infof("CreateSecurityGroup: %v", request) + + m.securityGroupNumber++ + n := m.securityGroupNumber + + sg := &ec2.SecurityGroup{ + GroupName: request.GroupName, + GroupId: s(fmt.Sprintf("sg-%d", n)), + VpcId: request.VpcId, + Description: request.Description, + } + m.SecurityGroups = append(m.SecurityGroups, sg) + response := &ec2.CreateSecurityGroupOutput{ + GroupId: sg.GroupId, + } + return response, nil +} + +func (m *MockEC2) DeleteSecurityGroupRequest(*ec2.DeleteSecurityGroupInput) (*request.Request, *ec2.DeleteSecurityGroupOutput) { + panic("MockEC2 DeleteSecurityGroupRequest not implemented") + return nil, nil +} +func (m *MockEC2) DeleteSecurityGroup(*ec2.DeleteSecurityGroupInput) (*ec2.DeleteSecurityGroupOutput, error) { + panic("MockEC2 DeleteSecurityGroup not implemented") + return nil, nil +} + +func (m *MockEC2) DescribeSecurityGroupReferencesRequest(*ec2.DescribeSecurityGroupReferencesInput) (*request.Request, *ec2.DescribeSecurityGroupReferencesOutput) { + panic("Not implemented") + return nil, nil +} +func (m *MockEC2) DescribeSecurityGroupReferences(*ec2.DescribeSecurityGroupReferencesInput) (*ec2.DescribeSecurityGroupReferencesOutput, error) { + panic("Not implemented") + return nil, nil +} +func (m *MockEC2) DescribeSecurityGroupsRequest(*ec2.DescribeSecurityGroupsInput) (*request.Request, *ec2.DescribeSecurityGroupsOutput) { + panic("Not implemented") + return nil, nil +} +func (m *MockEC2) DescribeSecurityGroups(request *ec2.DescribeSecurityGroupsInput) (*ec2.DescribeSecurityGroupsOutput, error) { + glog.Infof("DescribeSecurityGroups: %v", request) + + var groups []*ec2.SecurityGroup + + for _, sg := range m.SecurityGroups { + allFiltersMatch := true + for _, filter := range request.Filters { + match := false + switch *filter.Name { + case "vpc-id": + for _, v := range filter.Values { + if sg.VpcId != nil && *sg.VpcId == *v { + match = true + } + } + + case "group-name": + for _, v := range filter.Values { + if sg.GroupName != nil && *sg.GroupName == *v { + match = true + } + } + + default: + if strings.HasPrefix(*filter.Name, "tag:") { + match = m.hasTag(ec2.ResourceTypeSecurityGroup, *sg.GroupId, filter) + } else { + return nil, fmt.Errorf("unknown filter name: %q", *filter.Name) + } + } + + if !match { + allFiltersMatch = false + break + } + } + + if !allFiltersMatch { + continue + } + + copy := *sg + copy.Tags = m.getTags(ec2.ResourceTypeSecurityGroup, *sg.GroupId) + groups = append(groups, ©) + } + + response := &ec2.DescribeSecurityGroupsOutput{ + SecurityGroups: groups, + } + + return response, nil +} + +func (m *MockEC2) DescribeStaleSecurityGroupsRequest(*ec2.DescribeStaleSecurityGroupsInput) (*request.Request, *ec2.DescribeStaleSecurityGroupsOutput) { + panic("Not implemented") + return nil, nil +} +func (m *MockEC2) DescribeStaleSecurityGroups(*ec2.DescribeStaleSecurityGroupsInput) (*ec2.DescribeStaleSecurityGroupsOutput, error) { + panic("Not implemented") + return nil, nil +} +func (m *MockEC2) RevokeSecurityGroupEgressRequest(*ec2.RevokeSecurityGroupEgressInput) (*request.Request, *ec2.RevokeSecurityGroupEgressOutput) { + panic("Not implemented") + return nil, nil +} +func (m *MockEC2) RevokeSecurityGroupEgress(*ec2.RevokeSecurityGroupEgressInput) (*ec2.RevokeSecurityGroupEgressOutput, error) { + panic("Not implemented") + return nil, nil +} +func (m *MockEC2) RevokeSecurityGroupIngressRequest(*ec2.RevokeSecurityGroupIngressInput) (*request.Request, *ec2.RevokeSecurityGroupIngressOutput) { + panic("Not implemented") + return nil, nil +} +func (m *MockEC2) RevokeSecurityGroupIngress(*ec2.RevokeSecurityGroupIngressInput) (*ec2.RevokeSecurityGroupIngressOutput, error) { + panic("Not implemented") + return nil, nil +} +func (m *MockEC2) AuthorizeSecurityGroupEgressRequest(*ec2.AuthorizeSecurityGroupEgressInput) (*request.Request, *ec2.AuthorizeSecurityGroupEgressOutput) { + panic("Not implemented") + return nil, nil +} +func (m *MockEC2) AuthorizeSecurityGroupEgress(*ec2.AuthorizeSecurityGroupEgressInput) (*ec2.AuthorizeSecurityGroupEgressOutput, error) { + panic("Not implemented") + return nil, nil +} +func (m *MockEC2) AuthorizeSecurityGroupIngressRequest(*ec2.AuthorizeSecurityGroupIngressInput) (*request.Request, *ec2.AuthorizeSecurityGroupIngressOutput) { + panic("Not implemented") + return nil, nil +} +func (m *MockEC2) AuthorizeSecurityGroupIngress(*ec2.AuthorizeSecurityGroupIngressInput) (*ec2.AuthorizeSecurityGroupIngressOutput, error) { + panic("Not implemented") + return nil, nil +} diff --git a/cloudmock/aws/mockec2/tags.go b/cloudmock/aws/mockec2/tags.go index 5f1a3e1887..6e0a464f55 100644 --- a/cloudmock/aws/mockec2/tags.go +++ b/cloudmock/aws/mockec2/tags.go @@ -39,6 +39,10 @@ func (m *MockEC2) CreateTags(request *ec2.CreateTagsInput) (*ec2.CreateTagsOutpu resourceType = ec2.ResourceTypeSubnet } else if strings.HasPrefix(resourceId, "vpc-") { resourceType = ec2.ResourceTypeVpc + } else if strings.HasPrefix(resourceId, "sg-") { + resourceType = ec2.ResourceTypeSecurityGroup + } else if strings.HasPrefix(resourceId, "vol-") { + resourceType = ec2.ResourceTypeVolume } else { glog.Fatalf("Unknown resource-type in create tags: %v", resourceId) } diff --git a/cloudmock/aws/mockec2/unimplemented.go b/cloudmock/aws/mockec2/unimplemented.go index 05fd968407..efcb102dc3 100644 --- a/cloudmock/aws/mockec2/unimplemented.go +++ b/cloudmock/aws/mockec2/unimplemented.go @@ -98,22 +98,6 @@ func (m *MockEC2) AttachVpnGateway(*ec2.AttachVpnGatewayInput) (*ec2.AttachVpnGa panic("Not implemented") return nil, nil } -func (m *MockEC2) AuthorizeSecurityGroupEgressRequest(*ec2.AuthorizeSecurityGroupEgressInput) (*request.Request, *ec2.AuthorizeSecurityGroupEgressOutput) { - panic("Not implemented") - return nil, nil -} -func (m *MockEC2) AuthorizeSecurityGroupEgress(*ec2.AuthorizeSecurityGroupEgressInput) (*ec2.AuthorizeSecurityGroupEgressOutput, error) { - panic("Not implemented") - return nil, nil -} -func (m *MockEC2) AuthorizeSecurityGroupIngressRequest(*ec2.AuthorizeSecurityGroupIngressInput) (*request.Request, *ec2.AuthorizeSecurityGroupIngressOutput) { - panic("Not implemented") - return nil, nil -} -func (m *MockEC2) AuthorizeSecurityGroupIngress(*ec2.AuthorizeSecurityGroupIngressInput) (*ec2.AuthorizeSecurityGroupIngressOutput, error) { - panic("Not implemented") - return nil, nil -} func (m *MockEC2) BundleInstanceRequest(*ec2.BundleInstanceInput) (*request.Request, *ec2.BundleInstanceOutput) { panic("Not implemented") return nil, nil @@ -322,14 +306,6 @@ func (m *MockEC2) CreateRouteTable(*ec2.CreateRouteTableInput) (*ec2.CreateRoute panic("Not implemented") return nil, nil } -func (m *MockEC2) CreateSecurityGroupRequest(*ec2.CreateSecurityGroupInput) (*request.Request, *ec2.CreateSecurityGroupOutput) { - panic("Not implemented") - return nil, nil -} -func (m *MockEC2) CreateSecurityGroup(*ec2.CreateSecurityGroupInput) (*ec2.CreateSecurityGroupOutput, error) { - panic("Not implemented") - return nil, nil -} func (m *MockEC2) CreateSnapshotRequest(*ec2.CreateSnapshotInput) (*request.Request, *ec2.Snapshot) { panic("Not implemented") return nil, nil @@ -490,14 +466,6 @@ func (m *MockEC2) DeleteRouteTable(*ec2.DeleteRouteTableInput) (*ec2.DeleteRoute panic("Not implemented") return nil, nil } -func (m *MockEC2) DeleteSecurityGroupRequest(*ec2.DeleteSecurityGroupInput) (*request.Request, *ec2.DeleteSecurityGroupOutput) { - panic("Not implemented") - return nil, nil -} -func (m *MockEC2) DeleteSecurityGroup(*ec2.DeleteSecurityGroupInput) (*ec2.DeleteSecurityGroupOutput, error) { - panic("Not implemented") - return nil, nil -} func (m *MockEC2) DeleteSnapshotRequest(*ec2.DeleteSnapshotInput) (*request.Request, *ec2.DeleteSnapshotOutput) { panic("Not implemented") return nil, nil @@ -866,22 +834,6 @@ func (m *MockEC2) DescribeScheduledInstances(*ec2.DescribeScheduledInstancesInpu panic("Not implemented") return nil, nil } -func (m *MockEC2) DescribeSecurityGroupReferencesRequest(*ec2.DescribeSecurityGroupReferencesInput) (*request.Request, *ec2.DescribeSecurityGroupReferencesOutput) { - panic("Not implemented") - return nil, nil -} -func (m *MockEC2) DescribeSecurityGroupReferences(*ec2.DescribeSecurityGroupReferencesInput) (*ec2.DescribeSecurityGroupReferencesOutput, error) { - panic("Not implemented") - return nil, nil -} -func (m *MockEC2) DescribeSecurityGroupsRequest(*ec2.DescribeSecurityGroupsInput) (*request.Request, *ec2.DescribeSecurityGroupsOutput) { - panic("Not implemented") - return nil, nil -} -func (m *MockEC2) DescribeSecurityGroups(*ec2.DescribeSecurityGroupsInput) (*ec2.DescribeSecurityGroupsOutput, error) { - panic("Not implemented") - return nil, nil -} func (m *MockEC2) DescribeSnapshotAttributeRequest(*ec2.DescribeSnapshotAttributeInput) (*request.Request, *ec2.DescribeSnapshotAttributeOutput) { panic("Not implemented") return nil, nil @@ -958,14 +910,6 @@ func (m *MockEC2) DescribeSpotPriceHistoryPages(*ec2.DescribeSpotPriceHistoryInp panic("Not implemented") return nil } -func (m *MockEC2) DescribeStaleSecurityGroupsRequest(*ec2.DescribeStaleSecurityGroupsInput) (*request.Request, *ec2.DescribeStaleSecurityGroupsOutput) { - panic("Not implemented") - return nil, nil -} -func (m *MockEC2) DescribeStaleSecurityGroups(*ec2.DescribeStaleSecurityGroupsInput) (*ec2.DescribeStaleSecurityGroupsOutput, error) { - panic("Not implemented") - return nil, nil -} func (m *MockEC2) DescribeVpcClassicLinkRequest(*ec2.DescribeVpcClassicLinkInput) (*request.Request, *ec2.DescribeVpcClassicLinkOutput) { panic("Not implemented") return nil, nil @@ -1478,22 +1422,6 @@ func (m *MockEC2) RestoreAddressToClassic(*ec2.RestoreAddressToClassicInput) (*e panic("Not implemented") return nil, nil } -func (m *MockEC2) RevokeSecurityGroupEgressRequest(*ec2.RevokeSecurityGroupEgressInput) (*request.Request, *ec2.RevokeSecurityGroupEgressOutput) { - panic("Not implemented") - return nil, nil -} -func (m *MockEC2) RevokeSecurityGroupEgress(*ec2.RevokeSecurityGroupEgressInput) (*ec2.RevokeSecurityGroupEgressOutput, error) { - panic("Not implemented") - return nil, nil -} -func (m *MockEC2) RevokeSecurityGroupIngressRequest(*ec2.RevokeSecurityGroupIngressInput) (*request.Request, *ec2.RevokeSecurityGroupIngressOutput) { - panic("Not implemented") - return nil, nil -} -func (m *MockEC2) RevokeSecurityGroupIngress(*ec2.RevokeSecurityGroupIngressInput) (*ec2.RevokeSecurityGroupIngressOutput, error) { - panic("Not implemented") - return nil, nil -} func (m *MockEC2) RunInstancesRequest(*ec2.RunInstancesInput) (*request.Request, *ec2.Reservation) { panic("Not implemented") return nil, nil diff --git a/upup/pkg/fi/cloudup/awstasks/securitygroup_test.go b/upup/pkg/fi/cloudup/awstasks/securitygroup_test.go index 3783e6571a..62d8561e56 100644 --- a/upup/pkg/fi/cloudup/awstasks/securitygroup_test.go +++ b/upup/pkg/fi/cloudup/awstasks/securitygroup_test.go @@ -19,6 +19,10 @@ package awstasks import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" + "k8s.io/kops/cloudmock/aws/mockec2" + "k8s.io/kops/upup/pkg/fi" + "k8s.io/kops/upup/pkg/fi/cloudup/awsup" + "reflect" "testing" ) @@ -87,3 +91,70 @@ func testNotMatches(t *testing.T, rule *PortRemovalRule, permission *ec2.IpPermi t.Fatalf("rule %q unexpectedly matched permission %q", rule, permission) } } + +func TestSecurityGroupCreate(t *testing.T) { + cloud := awsup.BuildMockAWSCloud("us-east-1", "abc") + c := &mockec2.MockEC2{} + cloud.MockEC2 = c + + // We define a function so we can rebuild the tasks, because we modify in-place when running + buildTasks := func() map[string]fi.Task { + vpc1 := &VPC{ + Name: s("vpc1"), + CIDR: s("172.20.0.0/16"), + } + sg1 := &SecurityGroup{ + Name: s("sg1"), + Description: s("Description"), + VPC: vpc1, + } + + return map[string]fi.Task{ + "sg1": sg1, + "vpc1": vpc1, + } + } + + { + allTasks := buildTasks() + sg1 := allTasks["sg1"].(*SecurityGroup) + vpc1 := allTasks["vpc1"].(*VPC) + + target := &awsup.AWSAPITarget{ + Cloud: cloud, + } + + context, err := fi.NewContext(target, cloud, nil, nil, nil, true, allTasks) + if err != nil { + t.Fatalf("error building context: %v", err) + } + + if err := context.RunTasks(defaultDeadline); err != nil { + t.Fatalf("unexpected error during Run: %v", err) + } + + if fi.StringValue(sg1.ID) == "" { + t.Fatalf("ID not set after create") + } + + if len(c.SecurityGroups) != 1 { + t.Fatalf("Expected exactly one SecurityGroup; found %v", c.SecurityGroups) + } + + expected := &ec2.SecurityGroup{ + Description: s("Description"), + GroupId: sg1.ID, + VpcId: vpc1.ID, + GroupName: s("sg1"), + } + actual := c.SecurityGroups[0] + if !reflect.DeepEqual(actual, expected) { + t.Fatalf("Unexpected SecurityGroup: expected=%v actual=%v", expected, actual) + } + } + + { + allTasks := buildTasks() + checkNoChanges(t, cloud, allTasks) + } +}