// ensureGroup returns the security group with name and perms. // If a group with name does not exist, one will be created. // If it exists, its permissions are set to perms. func (e *environ) ensureGroup(name string, perms []ec2.IPPerm) (g ec2.SecurityGroup, err error) { ec2inst := e.ec2() resp, err := ec2inst.CreateSecurityGroup(name, "juju group") if err != nil && ec2ErrCode(err) != "InvalidGroup.Duplicate" { return zeroGroup, err } var have permSet if err == nil { g = resp.SecurityGroup } else { resp, err := ec2inst.SecurityGroups(ec2.SecurityGroupNames(name), nil) if err != nil { return zeroGroup, err } info := resp.Groups[0] // It's possible that the old group has the wrong // description here, but if it does it's probably due // to something deliberately playing games with juju, // so we ignore it. have = newPermSet(info.IPPerms) g = info.SecurityGroup } want := newPermSet(perms) revoke := make(permSet) for p := range have { if !want[p] { revoke[p] = true } } if len(revoke) > 0 { _, err := ec2inst.RevokeSecurityGroup(g, revoke.ipPerms()) if err != nil { return zeroGroup, fmt.Errorf("cannot revoke security group: %v", err) } } add := make(permSet) for p := range want { if !have[p] { add[p] = true } } if len(add) > 0 { _, err := ec2inst.AuthorizeSecurityGroup(g, add.ipPerms()) if err != nil { return zeroGroup, fmt.Errorf("cannot authorize securityGroup: %v", err) } } return g, nil }
// Cost: 0.00 USD func (s *ClientTests) TestSecurityGroups(c *C) { name := "goamz-test" descr := "goamz security group for tests" // Clean it up, if a previous test left it around and avoid leaving it around. s.ec2.DeleteSecurityGroup(ec2.SecurityGroup{Name: name}) defer s.ec2.DeleteSecurityGroup(ec2.SecurityGroup{Name: name}) resp1, err := s.ec2.CreateSecurityGroup(name, descr) c.Assert(err, IsNil) c.Assert(resp1.RequestId, Matches, ".+") c.Assert(resp1.Name, Equals, name) c.Assert(resp1.Id, Matches, ".+") resp1, err = s.ec2.CreateSecurityGroup(name, descr) ec2err, _ := err.(*ec2.Error) c.Assert(resp1, IsNil) c.Assert(ec2err, NotNil) c.Assert(ec2err.Code, Equals, "InvalidGroup.Duplicate") perms := []ec2.IPPerm{{ Protocol: "tcp", FromPort: 0, ToPort: 1024, SourceIPs: []string{"127.0.0.1/24"}, }} resp2, err := s.ec2.AuthorizeSecurityGroup(ec2.SecurityGroup{Name: name}, perms) c.Assert(err, IsNil) c.Assert(resp2.RequestId, Matches, ".+") resp3, err := s.ec2.SecurityGroups(ec2.SecurityGroupNames(name), nil) c.Assert(err, IsNil) c.Assert(resp3.RequestId, Matches, ".+") c.Assert(resp3.Groups, HasLen, 1) g0 := resp3.Groups[0] c.Assert(g0.Name, Equals, name) c.Assert(g0.Description, Equals, descr) c.Assert(g0.IPPerms, HasLen, 1) c.Assert(g0.IPPerms[0].Protocol, Equals, "tcp") c.Assert(g0.IPPerms[0].FromPort, Equals, 0) c.Assert(g0.IPPerms[0].ToPort, Equals, 1024) c.Assert(g0.IPPerms[0].SourceIPs, DeepEquals, []string{"127.0.0.1/24"}) resp2, err = s.ec2.DeleteSecurityGroup(ec2.SecurityGroup{Name: name}) c.Assert(err, IsNil) c.Assert(resp2.RequestId, Matches, ".+") }
// 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 *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, IsNil) gi := gresp.Groups[0] if len(gi.IPPerms) > 0 { _, err = ec2conn.RevokeSecurityGroup(gi.SecurityGroup, gi.IPPerms) c.Assert(err, IsNil) } return gi.SecurityGroup }
func (t *LiveTests) TestInstanceGroups(c *C) { 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, IsNil) inst0, _ := testing.StartInstance(c, t.Env, "98") defer t.Env.StopInstances([]instance.Instance{inst0}) // 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.StartInstance(c, t.Env, "99") defer t.Env.StopInstances([]instance.Instance{inst1}) groupsResp, err := ec2conn.SecurityGroups(groups, nil) c.Assert(err, IsNil) c.Assert(groupsResp.Groups, 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, 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, HasLen, 6) checkPortAllowed(c, perms, 22) // SSH checkPortAllowed(c, perms, 37017) // MongoDB checkPortAllowed(c, perms, 17070) // API checkSecurityGroupAllowed(c, perms, groups[0]) // The old machine group should have been reused also. c.Check(groups[2].Id, 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, IsNil) c.Assert(resp.Reservations, HasLen, 2) for _, r := range resp.Reservations { c.Assert(r.Instances, HasLen, 1) // each instance must be part of the general juju group. msg := Commentf("reservation %#v", r) c.Assert(hasSecurityGroup(r, groups[0]), Equals, true, msg) inst := r.Instances[0] switch instance.Id(inst.InstanceId) { case inst0.Id(): c.Assert(hasSecurityGroup(r, groups[1]), Equals, true, msg) c.Assert(hasSecurityGroup(r, groups[2]), Equals, false, msg) case inst1.Id(): c.Assert(hasSecurityGroup(r, groups[2]), Equals, true, msg) c.Assert(hasSecurityGroup(r, groups[1]), Equals, false, msg) default: c.Errorf("unknown instance found: %v", inst) } } }
func (t *LiveTests) TestInstanceGroups(c *gc.C) { t.BootstrapOnce(c) allInsts, err := t.Env.AllInstances() c.Assert(err, gc.IsNil) 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, gc.IsNil) 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, gc.IsNil) 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, gc.IsNil) 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, gc.IsNil) c.Assert(instIds, jc.SameContents, idsFromInsts(insts)) allInsts, err = t.Env.AllInstances() c.Assert(err, gc.IsNil) // 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)) }