~fwereade/pyjuju/go-cmd-jujup

« back to all changes in this revision

Viewing changes to environs/ec2/live_test.go

ec2: avoid deleting security groups if we can.

It takes ages to delete a security group if an
instance has been using it, so this change
adjusts the old group to have the required
permissions instead.

R=fwereade, niemeyer
CC=
https://codereview.appspot.com/5671086

Show diffs side-by-side

added added

removed removed

Lines of Context:
43
43
        if err != nil {
44
44
                panic(fmt.Errorf("cannot parse amazon tests config data: %v", err))
45
45
        }
46
 
        if err != nil {
47
 
                panic(fmt.Errorf("cannot parse integration tests config data: %v", err))
48
 
        }
49
46
        for _, name := range envs.Names() {
50
47
                Suite(&LiveTests{
51
48
                        jujutest.LiveTests{
72
69
        )
73
70
        info := make([]amzec2.SecurityGroupInfo, len(groups))
74
71
 
75
 
        c.Logf("start instance 98")
 
72
        // Create a group with the same name as the juju group
 
73
        // but with different permissions, to check that it's deleted
 
74
        // and recreated correctly.
 
75
        oldJujuGroup := createGroup(c, ec2conn, groups[0].Name, "old juju group")
 
76
 
 
77
        // Add two permissions: one is required and should be left alone;
 
78
        // the other is not and should be deleted.
 
79
        // N.B. this is unfortunately sensitive to the actual set of permissions used.
 
80
        _, err := ec2conn.AuthorizeSecurityGroup(oldJujuGroup,
 
81
                []amzec2.IPPerm{
 
82
                        {
 
83
                                Protocol:  "tcp",
 
84
                                FromPort:  22,
 
85
                                ToPort:    22,
 
86
                                SourceIPs: []string{"0.0.0.0/0"},
 
87
                        },
 
88
                        {
 
89
                                Protocol:  "udp",
 
90
                                FromPort:  4321,
 
91
                                ToPort:    4322,
 
92
                                SourceIPs: []string{"3.4.5.6/32"},
 
93
                        },
 
94
                })
 
95
        c.Assert(err, IsNil)
 
96
 
76
97
        inst0, err := t.Env.StartInstance(98, jujutest.InvalidStateInfo)
77
98
        c.Assert(err, IsNil)
78
99
        defer t.Env.StopInstances([]environs.Instance{inst0})
79
100
 
80
101
        // Create a same-named group for the second instance
81
 
        // before starting it, to check that it's deleted and
82
 
        // recreated correctly.
83
 
        oldGroup := ensureGroupExists(c, ec2conn, groups[2].Name, "old group")
 
102
        // before starting it, to check that it's reused correctly.
 
103
        oldMachineGroup := createGroup(c, ec2conn, groups[2].Name, "old machine group")
84
104
 
85
 
        c.Logf("start instance 99")
86
105
        inst1, err := t.Env.StartInstance(99, jujutest.InvalidStateInfo)
87
106
        c.Assert(err, IsNil)
88
107
        defer t.Env.StopInstances([]environs.Instance{inst1})
89
108
 
90
 
        // Go behind the scenes to check the machines have
91
 
        // been put into the correct groups.
92
 
 
93
 
        // First check that the old group has been deleted...
94
 
        f := amzec2.NewFilter()
95
 
        f.Add("group-name", oldGroup.Name)
96
 
        f.Add("group-id", oldGroup.Id)
97
 
        groupsResp, err := ec2conn.SecurityGroups(nil, f)
98
 
        c.Assert(err, IsNil)
99
 
        c.Check(len(groupsResp.Groups), Equals, 0)
100
 
 
101
 
        // ... then check that the groups have been created.
102
 
        groupsResp, err = ec2conn.SecurityGroups(groups, nil)
 
109
        groupsResp, err := ec2conn.SecurityGroups(groups, nil)
103
110
        c.Assert(err, IsNil)
104
111
        c.Assert(len(groupsResp.Groups), Equals, len(groups))
105
112
 
119
126
                }
120
127
        }
121
128
 
 
129
        // The old juju group should have been reused.
 
130
        c.Check(groups[0].Id, Equals, oldJujuGroup.Id)
 
131
 
 
132
        // Check that it authorizes the correct ports and there
 
133
        // are no extra permissions (in particular we are checking
 
134
        // that the unneeded permission that we added earlier
 
135
        // has been deleted).
122
136
        perms := info[0].IPPerms
123
 
 
124
 
        // check that the juju group authorizes SSH for anyone.
125
137
        c.Assert(len(perms), Equals, 2, Bug("got security groups %#v", perms))
126
138
        checkPortAllowed(c, perms, 22)
127
139
        checkPortAllowed(c, perms, 2181)
128
140
 
129
 
        c.Logf("checking that each insance is part of the correct groups")
 
141
        // The old machine group should have been reused also.
 
142
        c.Check(groups[2].Id, Equals, oldMachineGroup.Id)
 
143
 
130
144
        // Check that each instance is part of the correct groups.
131
145
        resp, err := ec2conn.Instances([]string{inst0.Id(), inst1.Id()}, nil)
132
146
        c.Assert(err, IsNil)
143
157
                        c.Assert(hasSecurityGroup(r, groups[2]), Equals, false, msg)
144
158
                case inst1.Id():
145
159
                        c.Assert(hasSecurityGroup(r, groups[2]), Equals, true, msg)
146
 
 
147
 
                        // check that the id of the second machine's group
148
 
                        // has changed - this implies that StartInstance
149
 
                        // has correctly deleted and re-created the group.
150
 
                        c.Assert(groups[2].Id, Not(Equals), oldGroup.Id)
151
160
                        c.Assert(hasSecurityGroup(r, groups[1]), Equals, false, msg)
152
161
                default:
153
162
                        c.Errorf("unknown instance found: %v", inst)
188
197
        c.Check(len(insts), Equals, 0)
189
198
}
190
199
 
191
 
// ensureGroupExists creates a new EC2 group if it doesn't already
192
 
// exist, and returns full SecurityGroup.
193
 
func ensureGroupExists(c *C, ec2conn *amzec2.EC2, groupName string, descr string) amzec2.SecurityGroup {
194
 
        f := amzec2.NewFilter()
195
 
        f.Add("group-name", groupName)
196
 
        groups, err := ec2conn.SecurityGroups(nil, f)
197
 
        c.Assert(err, IsNil)
198
 
        if len(groups.Groups) > 0 {
199
 
                return groups.Groups[0].SecurityGroup
200
 
        }
201
 
 
202
 
        resp, err := ec2conn.CreateSecurityGroup(groupName, descr)
203
 
        c.Assert(err, IsNil)
204
 
 
205
 
        return resp.SecurityGroup
 
200
// createGroup creates a new EC2 group and returns it. If it already exists,
 
201
// it revokes all its permissions and returns the existing group.
 
202
func createGroup(c *C, ec2conn *amzec2.EC2, name, descr string) amzec2.SecurityGroup {
 
203
        resp, err := ec2conn.CreateSecurityGroup(name, descr)
 
204
        if err == nil {
 
205
                return resp.SecurityGroup
 
206
        }
 
207
        if err.(*amzec2.Error).Code != "InvalidGroup.Duplicate" {
 
208
                c.Fatalf("cannot make group %q: %v", name, err)
 
209
        }
 
210
 
 
211
        // Found duplicate group, so revoke its permissions and return it.
 
212
        gresp, err := ec2conn.SecurityGroups(amzec2.SecurityGroupNames(name), nil)
 
213
        c.Assert(err, IsNil)
 
214
 
 
215
        gi := gresp.Groups[0]
 
216
        _, err = ec2conn.RevokeSecurityGroup(gi.SecurityGroup, gi.IPPerms)
 
217
        c.Assert(err, IsNil)
 
218
        return gi.SecurityGroup
206
219
}
207
220
 
208
221
func hasSecurityGroup(r amzec2.Reservation, g amzec2.SecurityGroup) bool {