// createGroup creates a new EC2 group and returns it. If it already exists, // it revokes all its permissions and returns the existing group. func createGroup(c *gc.C, ec2conn *amzec2.EC2, name, descr string) amzec2.SecurityGroup { resp, err := ec2conn.CreateSecurityGroup("", name, descr) if err == nil { return resp.SecurityGroup } if err.(*amzec2.Error).Code != "InvalidGroup.Duplicate" { c.Fatalf("cannot make group %q: %v", name, err) } // Found duplicate group, so revoke its permissions and return it. gresp, err := ec2conn.SecurityGroups(amzec2.SecurityGroupNames(name), nil) c.Assert(err, jc.ErrorIsNil) gi := gresp.Groups[0] if len(gi.IPPerms) > 0 { _, err = ec2conn.RevokeSecurityGroup(gi.SecurityGroup, gi.IPPerms) c.Assert(err, jc.ErrorIsNil) } return gi.SecurityGroup }
func (t *LiveTests) TestInstanceGroups(c *gc.C) { t.BootstrapOnce(c) allInsts, err := t.Env.AllInstances() c.Assert(err, jc.ErrorIsNil) c.Assert(allInsts, gc.HasLen, 1) // bootstrap instance bootstrapInstId := allInsts[0].Id() ec2conn := ec2.EnvironEC2(t.Env) groups := amzec2.SecurityGroupNames( ec2.JujuGroupName(t.Env), ec2.MachineGroupName(t.Env, "98"), ec2.MachineGroupName(t.Env, "99"), ) info := make([]amzec2.SecurityGroupInfo, len(groups)) // Create a group with the same name as the juju group // but with different permissions, to check that it's deleted // and recreated correctly. oldJujuGroup := createGroup(c, ec2conn, groups[0].Name, "old juju group") // Add two permissions: one is required and should be left alone; // the other is not and should be deleted. // N.B. this is unfortunately sensitive to the actual set of permissions used. _, err = ec2conn.AuthorizeSecurityGroup(oldJujuGroup, []amzec2.IPPerm{ { Protocol: "tcp", FromPort: 22, ToPort: 22, SourceIPs: []string{"0.0.0.0/0"}, }, { Protocol: "udp", FromPort: 4321, ToPort: 4322, SourceIPs: []string{"3.4.5.6/32"}, }, }) c.Assert(err, jc.ErrorIsNil) inst0, _ := testing.AssertStartInstance(c, t.Env, "98") defer t.Env.StopInstances(inst0.Id()) // Create a same-named group for the second instance // before starting it, to check that it's reused correctly. oldMachineGroup := createGroup(c, ec2conn, groups[2].Name, "old machine group") inst1, _ := testing.AssertStartInstance(c, t.Env, "99") defer t.Env.StopInstances(inst1.Id()) groupsResp, err := ec2conn.SecurityGroups(groups, nil) c.Assert(err, jc.ErrorIsNil) c.Assert(groupsResp.Groups, gc.HasLen, len(groups)) // For each group, check that it exists and record its id. for i, group := range groups { found := false for _, g := range groupsResp.Groups { if g.Name == group.Name { groups[i].Id = g.Id info[i] = g found = true break } } if !found { c.Fatalf("group %q not found", group.Name) } } // The old juju group should have been reused. c.Check(groups[0].Id, gc.Equals, oldJujuGroup.Id) // Check that it authorizes the correct ports and there // are no extra permissions (in particular we are checking // that the unneeded permission that we added earlier // has been deleted). perms := info[0].IPPerms c.Assert(perms, gc.HasLen, 5) checkPortAllowed(c, perms, 22) // SSH checkPortAllowed(c, perms, coretesting.FakeConfig()["api-port"].(int)) checkSecurityGroupAllowed(c, perms, groups[0]) // The old machine group should have been reused also. c.Check(groups[2].Id, gc.Equals, oldMachineGroup.Id) // Check that each instance is part of the correct groups. resp, err := ec2conn.Instances([]string{string(inst0.Id()), string(inst1.Id())}, nil) c.Assert(err, jc.ErrorIsNil) c.Assert(resp.Reservations, gc.HasLen, 2) for _, r := range resp.Reservations { c.Assert(r.Instances, gc.HasLen, 1) // each instance must be part of the general juju group. inst := r.Instances[0] msg := gc.Commentf("instance %#v", inst) c.Assert(hasSecurityGroup(inst, groups[0]), gc.Equals, true, msg) switch instance.Id(inst.InstanceId) { case inst0.Id(): c.Assert(hasSecurityGroup(inst, groups[1]), gc.Equals, true, msg) c.Assert(hasSecurityGroup(inst, groups[2]), gc.Equals, false, msg) case inst1.Id(): c.Assert(hasSecurityGroup(inst, groups[2]), gc.Equals, true, msg) c.Assert(hasSecurityGroup(inst, groups[1]), gc.Equals, false, msg) default: c.Errorf("unknown instance found: %v", inst) } } // Check that listing those instances finds them using the groups instIds := []instance.Id{inst0.Id(), inst1.Id()} idsFromInsts := func(insts []instance.Instance) (ids []instance.Id) { for _, inst := range insts { ids = append(ids, inst.Id()) } return ids } insts, err := t.Env.Instances(instIds) c.Assert(err, jc.ErrorIsNil) c.Assert(instIds, jc.SameContents, idsFromInsts(insts)) allInsts, err = t.Env.AllInstances() c.Assert(err, jc.ErrorIsNil) // ignore the bootstrap instance for i, inst := range allInsts { if inst.Id() == bootstrapInstId { if i+1 < len(allInsts) { copy(allInsts[i:], allInsts[i+1:]) } allInsts = allInsts[:len(allInsts)-1] break } } c.Assert(instIds, jc.SameContents, idsFromInsts(allInsts)) }