func (s *subnetSuite) TestNewSubnetTag(c *gc.C) { cidr := "10.20.0.0/16" tag := names.NewSubnetTag(cidr) parsed, err := names.ParseSubnetTag(tag.String()) c.Assert(err, gc.IsNil) c.Assert(parsed.Kind(), gc.Equals, names.SubnetTagKind) c.Assert(parsed.Id(), gc.Equals, cidr) c.Assert(parsed.String(), gc.Equals, names.SubnetTagKind+"-"+cidr) f := func() { tag = names.NewSubnetTag("foo") } c.Assert(f, gc.PanicMatches, "foo is not a valid subnet CIDR") }
func makeCreateSubnetsArgs(cidr, space string, zones []string, isPublic bool) apitesting.CheckArgs { spaceTag := names.NewSpaceTag(space).String() subnetTag := names.NewSubnetTag(cidr).String() expectArgs := params.CreateSubnetsParams{ Subnets: []params.CreateSubnetParams{{ SpaceTag: spaceTag, SubnetTag: subnetTag, Zones: zones, IsPublic: isPublic, }}} expectResults := params.ErrorResults{ Results: []params.ErrorResult{{}}, } args := apitesting.CheckArgs{ Facade: "Subnets", Method: "CreateSubnets", Args: expectArgs, Results: expectResults, } return args }
func makeArgs(name string, subnets []string) (string, []string, apitesting.CheckArgs) { spaceTag := names.NewSpaceTag(name).String() subnetTags := []string{} for _, s := range subnets { subnetTags = append(subnetTags, names.NewSubnetTag(s).String()) } expectArgs := params.CreateSpacesParams{ Spaces: []params.CreateSpaceParams{ params.CreateSpaceParams{ SpaceTag: spaceTag, SubnetTags: subnetTags, Public: true, }}} expectResults := params.ErrorResults{ Results: []params.ErrorResult{{}}, } args := apitesting.CheckArgs{ Facade: "Spaces", Method: "CreateSpaces", Args: expectArgs, Results: expectResults, } return name, subnets, args }
func (s *firewallerSuite) TestGetMachineActiveSubnets(c *gc.C) { s.openPorts(c) subnetTag := names.NewSubnetTag("10.20.30.0/24").String() args := addFakeEntities(params.Entities{Entities: []params.Entity{ {Tag: s.machines[0].Tag().String()}, {Tag: s.machines[1].Tag().String()}, {Tag: s.machines[2].Tag().String()}, {Tag: s.service.Tag().String()}, {Tag: s.units[0].Tag().String()}, }}) expectResultsMachine0 := []string{subnetTag, ""} expectResultsMachine2 := []string{""} result, err := s.firewaller.GetMachineActiveSubnets(args) c.Assert(err, jc.ErrorIsNil) c.Assert(result, jc.DeepEquals, params.StringsResults{ Results: []params.StringsResult{ {Result: expectResultsMachine0}, {Result: nil, Error: nil}, {Result: expectResultsMachine2}, {Error: apiservertesting.ServerError(`"service-wordpress" is not a valid machine tag`)}, {Error: apiservertesting.ServerError(`"unit-wordpress-0" is not a valid machine tag`)}, {Error: apiservertesting.NotFoundError("machine 42")}, {Error: apiservertesting.ServerError(`"unit-foo-0" is not a valid machine tag`)}, {Error: apiservertesting.ServerError(`"service-bar" is not a valid machine tag`)}, {Error: apiservertesting.ServerError(`"user-foo" is not a valid machine tag`)}, {Error: apiservertesting.ServerError(`"foo-bar" is not a valid tag`)}, {Error: apiservertesting.ServerError(`"" is not a valid tag`)}, }, }) }
func makeAddSubnetsArgs(cidr, providerId, space string, zones []string) apitesting.CheckArgs { spaceTag := names.NewSpaceTag(space).String() subnetTag := names.NewSubnetTag(cidr).String() if providerId != "" { subnetTag = "" } expectArgs := params.AddSubnetsParams{ Subnets: []params.AddSubnetParams{{ SpaceTag: spaceTag, SubnetTag: subnetTag, SubnetProviderId: providerId, Zones: zones, }}} expectResults := params.ErrorResults{ Results: []params.ErrorResult{{}}, } args := apitesting.CheckArgs{ Facade: "Subnets", Method: "AddSubnets", Args: expectArgs, Results: expectResults, } return args }
func (s *RemoveSuite) TestRunWithIPv6CIDRSucceeds(c *gc.C) { s.AssertRunSucceeds(c, `marked subnet "2001:db8::/32" for removal\n`, "", // empty stdout. "2001:db8::/32", ) s.api.CheckCallNames(c, "RemoveSubnet", "Close") s.api.CheckCall(c, 0, "RemoveSubnet", names.NewSubnetTag("2001:db8::/32")) }
func (s *RemoveSuite) TestRunWithIPv4CIDRSucceeds(c *gc.C) { s.AssertRunSucceeds(c, `marked subnet "10.20.0.0/16" for removal\n`, "", // empty stdout. "10.20.0.0/16", ) s.api.CheckCallNames(c, "RemoveSubnet", "Close") s.api.CheckCall(c, 0, "RemoveSubnet", names.NewSubnetTag("10.20.0.0/16")) }
func (s *RemoveSuite) TestRunWithSubnetInUseFails(c *gc.C) { s.api.SetErrors(errors.Errorf("subnet %q is still in use", "10.10.0.0/24")) s.AssertRunFails(c, `cannot remove subnet "10.10.0.0/24": subnet "10.10.0.0/24" is still in use`, "10.10.0.0/24", ) s.api.CheckCallNames(c, "RemoveSubnet", "Close") s.api.CheckCall(c, 0, "RemoveSubnet", names.NewSubnetTag("10.10.0.0/24")) }
func (s *CreateSuite) TestRunOneZoneSucceeds(c *gc.C) { s.AssertRunSucceeds(c, `created a private subnet "10.20.0.0/24" in space "myspace" with zones zone1\n`, "", // empty stdout. "10.20.0.0/24", "myspace", "zone1", ) s.api.CheckCallNames(c, "AllZones", "CreateSubnet", "Close") s.api.CheckCall(c, 1, "CreateSubnet", names.NewSubnetTag("10.20.0.0/24"), names.NewSpaceTag("myspace"), s.Strings("zone1"), false, ) }
func (s *CreateSuite) TestRunWithPublicAndIPv6CIDRSucceeds(c *gc.C) { s.AssertRunSucceeds(c, `created a public subnet "2001:db8::/32" in space "space" with zones zone1\n`, "", // empty stdout. "2001:db8::/32", "space", "zone1", "--public", ) s.api.CheckCallNames(c, "AllZones", "CreateSubnet", "Close") s.api.CheckCall(c, 1, "CreateSubnet", names.NewSubnetTag("2001:db8::/32"), names.NewSpaceTag("space"), s.Strings("zone1"), true, ) }
func (s *RemoveSuite) TestRunWithNonExistingSubnetFails(c *gc.C) { s.api.SetErrors(errors.NotFoundf("subnet %q", "10.10.0.0/24")) err := s.AssertRunFails(c, `cannot remove subnet "10.10.0.0/24": subnet "10.10.0.0/24" not found`, "10.10.0.0/24", ) c.Assert(err, jc.Satisfies, errors.IsNotFound) s.api.CheckCallNames(c, "RemoveSubnet", "Close") s.api.CheckCall(c, 0, "RemoveSubnet", names.NewSubnetTag("10.10.0.0/24")) }
// ValidateCIDR parses given and returns an error if it's not valid. // If the CIDR is incorrectly specified (e.g. 10.10.10.0/16 instead of // 10.10.0.0/16) and strict is false, the correctly parsed CIDR in the // expected format is returned instead without an error. Otherwise, // when strict is true and given is incorrectly formatted, an error // will be returned. func (s *SubnetCommandBase) ValidateCIDR(given string, strict bool) (names.SubnetTag, error) { _, ipNet, err := net.ParseCIDR(given) if err != nil { logger.Debugf("cannot parse CIDR %q: %v", given, err) return names.SubnetTag{}, errors.Errorf("%q is not a valid CIDR", given) } if strict && given != ipNet.String() { expected := ipNet.String() return names.SubnetTag{}, errors.Errorf("%q is not correctly specified, expected %q", given, expected) } // Already validated, so shouldn't error here. return names.NewSubnetTag(ipNet.String()), nil }
func (s *CreateSuite) TestRunWithNonExistingSpaceFails(c *gc.C) { s.api.SetErrors(nil, errors.NotFoundf("space %q", "space")) err := s.AssertRunFails(c, `cannot create subnet "10.10.0.0/24": space "space" not found`, "10.10.0.0/24", "space", "zone1", ) c.Assert(err, jc.Satisfies, errors.IsNotFound) s.api.CheckCallNames(c, "AllZones", "CreateSubnet", "Close") s.api.CheckCall(c, 1, "CreateSubnet", names.NewSubnetTag("10.10.0.0/24"), names.NewSpaceTag("space"), s.Strings("zone1"), false, ) }
func (s *CreateSuite) TestRunWithMultipleZonesSucceeds(c *gc.C) { s.AssertRunSucceeds(c, // The list of zones is sorted both when displayed and passed // to CreateSubnet. `created a private subnet "10.20.0.0/24" in space "foo" with zones zone1, zone2\n`, "", // empty stdout. "10.20.0.0/24", "foo", "zone2", "zone1", // unsorted zones ) s.api.CheckCallNames(c, "AllZones", "CreateSubnet", "Close") s.api.CheckCall(c, 1, "CreateSubnet", names.NewSubnetTag("10.20.0.0/24"), names.NewSpaceTag("foo"), s.Strings("zone1", "zone2"), false, ) }
func (s *CreateSuite) TestRunWithExistingSubnetFails(c *gc.C) { s.api.SetErrors(nil, errors.AlreadyExistsf("subnet %q", "10.10.0.0/24")) err := s.AssertRunFails(c, `cannot create subnet "10.10.0.0/24": subnet "10.10.0.0/24" already exists`, "10.10.0.0/24", "space", "zone1", ) c.Assert(err, jc.Satisfies, errors.IsAlreadyExists) s.api.CheckCallNames(c, "AllZones", "CreateSubnet", "Close") s.api.CheckCall(c, 1, "CreateSubnet", names.NewSubnetTag("10.10.0.0/24"), names.NewSpaceTag("space"), s.Strings("zone1"), false, ) }
func makeCreateSpaceParams(name string, subnetIds []string, public bool) params.CreateSpaceParams { spaceTag := names.NewSpaceTag(name).String() subnetTags := make([]string, len(subnetIds)) for i, s := range subnetIds { subnetTags[i] = names.NewSubnetTag(s).String() } return params.CreateSpaceParams{ SpaceTag: spaceTag, SubnetTags: subnetTags, Public: public, } }
// parsePortsKey parses a ports document global key coming from the ports // watcher (e.g. "42:0.1.2.0/24") and returns the machine and subnet tags from // its components (in the last example "machine-42" and "subnet-0.1.2.0/24"). func parsePortsKey(change string) (machineTag names.MachineTag, subnetTag names.SubnetTag, err error) { defer errors.DeferredAnnotatef(&err, "invalid ports change %q", change) parts := strings.SplitN(change, ":", 2) if len(parts) != 2 { return names.MachineTag{}, names.SubnetTag{}, errors.Errorf("unexpected format") } machineID, subnetID := parts[0], parts[1] machineTag = names.NewMachineTag(machineID) if subnetID != "" { subnetTag = names.NewSubnetTag(subnetID) } return machineTag, subnetTag, nil }
func (s *AddSuite) TestRunWithIPv6CIDRSucceeds(c *gc.C) { s.AssertRunSucceeds(c, `added subnet with CIDR "2001:db8::/32" in space "hyperspace"\n`, "", // empty stdout. "2001:db8::/32", "hyperspace", ) s.api.CheckCallNames(c, "AddSubnet", "Close") s.api.CheckCall(c, 0, "AddSubnet", names.NewSubnetTag("2001:db8::/32"), network.Id(""), names.NewSpaceTag("hyperspace"), []string(nil), ) }
func (s *AddSuite) TestRunWithIPv4CIDRSucceeds(c *gc.C) { s.AssertRunSucceeds(c, `added subnet with CIDR "10.20.0.0/24" in space "myspace"\n`, "", // empty stdout. "10.20.0.0/24", "myspace", ) s.api.CheckCallNames(c, "AddSubnet", "Close") s.api.CheckCall(c, 0, "AddSubnet", names.NewSubnetTag("10.20.0.0/24"), network.Id(""), names.NewSpaceTag("myspace"), []string(nil), ) }
func (s *SubnetsSuite) TestCreateSubnet(c *gc.C) { cidr := "1.1.1.0/24" space := "bar" zones := []string{"foo", "bar"} isPublic := true args := makeCreateSubnetsArgs(cidr, space, zones, isPublic) s.prepareAPICall(c, &args, nil) err := s.api.CreateSubnet( names.NewSubnetTag(cidr), names.NewSpaceTag(space), zones, isPublic, ) c.Assert(s.called, gc.Equals, 1) c.Assert(err, jc.ErrorIsNil) }
func (s *SubnetsSuite) TestAddSubnetFails(c *gc.C) { cidr := "1.1.1.0/24" providerId := "foo" space := "bar" zones := []string{"foo", "bar"} args := makeAddSubnetsArgs(cidr, providerId, space, zones) s.prepareAPICall(c, &args, errors.New("bang")) err := s.api.AddSubnet( names.NewSubnetTag(cidr), network.Id(providerId), names.NewSpaceTag(space), zones, ) c.Check(s.called, gc.Equals, 1) c.Assert(err, gc.ErrorMatches, "bang") }
func (s *SubnetsSuite) TestCreateSubnetFails(c *gc.C) { cidr := "1.1.1.0/24" isPublic := true space := "bar" zones := []string{"foo", "bar"} args := makeCreateSubnetsArgs(cidr, space, zones, isPublic) s.prepareAPICall(c, &args, errors.New("bang")) err := s.api.CreateSubnet( names.NewSubnetTag(cidr), names.NewSpaceTag(space), zones, isPublic, ) c.Check(s.called, gc.Equals, 1) c.Assert(err, gc.ErrorMatches, "bang") }
func (s *firewallerSuite) TestGetMachinePorts(c *gc.C) { s.openPorts(c) subnetTag := names.NewSubnetTag("10.20.30.0/24").String() args := params.MachinePortsParams{ Params: []params.MachinePorts{ {MachineTag: s.machines[0].Tag().String(), SubnetTag: ""}, {MachineTag: s.machines[0].Tag().String(), SubnetTag: subnetTag}, {MachineTag: s.machines[1].Tag().String(), SubnetTag: ""}, {MachineTag: s.machines[2].Tag().String(), SubnetTag: ""}, {MachineTag: s.machines[0].Tag().String(), SubnetTag: "invalid"}, {MachineTag: "machine-42", SubnetTag: ""}, {MachineTag: s.machines[0].Tag().String(), SubnetTag: "subnet-bad"}, }, } unit0Tag := s.units[0].Tag().String() expectPortsMachine0NoSubnet := []params.MachinePortRange{ {UnitTag: unit0Tag, PortRange: params.PortRange{ FromPort: 4321, ToPort: 4321, Protocol: "tcp", }}, } expectPortsMachine0WithSubnet := []params.MachinePortRange{ {UnitTag: unit0Tag, PortRange: params.PortRange{ FromPort: 1234, ToPort: 1400, Protocol: "tcp", }}, } unit2Tag := s.units[2].Tag().String() expectPortsMachine2 := []params.MachinePortRange{ {UnitTag: unit2Tag, PortRange: params.PortRange{ FromPort: 1111, ToPort: 2222, Protocol: "udp", }}, } result, err := s.firewaller.GetMachinePorts(args) c.Assert(err, jc.ErrorIsNil) c.Assert(result, jc.DeepEquals, params.MachinePortsResults{ Results: []params.MachinePortsResult{ {Ports: expectPortsMachine0NoSubnet}, {Ports: expectPortsMachine0WithSubnet}, {Error: nil, Ports: nil}, {Ports: expectPortsMachine2}, {Error: apiservertesting.ServerError(`"invalid" is not a valid tag`)}, {Error: apiservertesting.NotFoundError("machine 42")}, {Error: apiservertesting.ServerError(`"subnet-bad" is not a valid subnet tag`)}, }, }) }
func (s *AddSuite) TestRunWithExistingSubnetFails(c *gc.C) { s.api.SetErrors(errors.AlreadyExistsf("subnet %q", "10.10.0.0/24")) err := s.AssertRunFails(c, `cannot add subnet: subnet "10.10.0.0/24" already exists`, "10.10.0.0/24", "space", ) c.Assert(err, jc.Satisfies, errors.IsAlreadyExists) s.api.CheckCallNames(c, "AddSubnet", "Close") s.api.CheckCall(c, 0, "AddSubnet", names.NewSubnetTag("10.10.0.0/24"), network.Id(""), names.NewSpaceTag("space"), []string(nil), ) }
func (s *AddSuite) TestRunWithNonExistingSpaceFails(c *gc.C) { s.api.SetErrors(errors.NotFoundf("space %q", "space")) err := s.AssertRunFails(c, `cannot add subnet: space "space" not found`, "10.10.0.0/24", "space", "zone1", "zone2", ) c.Assert(err, jc.Satisfies, errors.IsNotFound) s.api.CheckCallNames(c, "AddSubnet", "Close") s.api.CheckCall(c, 0, "AddSubnet", names.NewSubnetTag("10.10.0.0/24"), network.Id(""), names.NewSpaceTag("space"), s.Strings("zone1", "zone2"), ) }
func (s *AddSuite) TestRunWithAmbiguousCIDRDisplaysError(c *gc.C) { apiError := errors.New(`multiple subnets with CIDR "10.10.0.0/24" <snip>`) s.api.SetErrors(apiError) s.AssertRunSucceeds(c, fmt.Sprintf("ERROR: %v.\n", apiError), "", "10.10.0.0/24", "space", "zone1", "zone2", ) s.api.CheckCallNames(c, "AddSubnet", "Close") s.api.CheckCall(c, 0, "AddSubnet", names.NewSubnetTag("10.10.0.0/24"), network.Id(""), names.NewSpaceTag("space"), s.Strings("zone1", "zone2"), ) }
// GetMachineActiveSubnets returns the tags of the all subnets that each machine // (in args) has open ports on. func (f *FirewallerAPI) GetMachineActiveSubnets(args params.Entities) (params.StringsResults, error) { result := params.StringsResults{ Results: make([]params.StringsResult, len(args.Entities)), } canAccess, err := f.accessMachine() if err != nil { return params.StringsResults{}, err } for i, entity := range args.Entities { machineTag, err := names.ParseMachineTag(entity.Tag) if err != nil { result.Results[i].Error = common.ServerError(err) continue } machine, err := f.getMachine(canAccess, machineTag) if err != nil { result.Results[i].Error = common.ServerError(err) continue } ports, err := machine.AllPorts() if err != nil { result.Results[i].Error = common.ServerError(err) continue } for _, port := range ports { subnetID := port.SubnetID() if subnetID != "" && !names.IsValidSubnet(subnetID) { // The error message below will look like e.g. `ports for // machine "0", subnet "bad" not valid`. err = errors.NotValidf("%s", ports) result.Results[i].Error = common.ServerError(err) continue } else if subnetID != "" && names.IsValidSubnet(subnetID) { subnetTag := names.NewSubnetTag(subnetID).String() result.Results[i].Result = append(result.Results[i].Result, subnetTag) continue } // TODO(dimitern): Empty subnet CIDRs for ports are still OK until // we can enforce it across all providers. result.Results[i].Result = append(result.Results[i].Result, "") } } return result, nil }
func (s *AddSuite) TestRunWithIncorrectlyGivenCIDRSucceedsWithWarning(c *gc.C) { expectStderr := strings.Join([]string{ "(.|\n)*", "WARNING: using CIDR \"10.0.0.0/8\" instead of ", "the incorrectly specified \"10.10.0.0/8\".\n", "added subnet with CIDR \"10.0.0.0/8\" in space \"myspace\"\n", }, "") s.AssertRunSucceeds(c, expectStderr, "", // empty stdout. "10.10.0.0/8", "myspace", ) s.api.CheckCallNames(c, "AddSubnet", "Close") s.api.CheckCall(c, 0, "AddSubnet", names.NewSubnetTag("10.0.0.0/8"), network.Id(""), names.NewSpaceTag("myspace"), []string(nil), ) }
}} var makeTag = map[string]func(string) names.Tag{ names.MachineTagKind: func(tag string) names.Tag { return names.NewMachineTag(tag) }, names.UnitTagKind: func(tag string) names.Tag { return names.NewUnitTag(tag) }, names.ServiceTagKind: func(tag string) names.Tag { return names.NewServiceTag(tag) }, names.RelationTagKind: func(tag string) names.Tag { return names.NewRelationTag(tag) }, names.EnvironTagKind: func(tag string) names.Tag { return names.NewEnvironTag(tag) }, names.UserTagKind: func(tag string) names.Tag { return names.NewUserTag(tag) }, names.NetworkTagKind: func(tag string) names.Tag { return names.NewNetworkTag(tag) }, names.ActionTagKind: func(tag string) names.Tag { return names.NewActionTag(tag) }, names.VolumeTagKind: func(tag string) names.Tag { return names.NewVolumeTag(tag) }, names.FilesystemTagKind: func(tag string) names.Tag { return names.NewFilesystemTag(tag) }, names.StorageTagKind: func(tag string) names.Tag { return names.NewStorageTag(tag) }, names.IPAddressTagKind: func(tag string) names.Tag { return names.NewIPAddressTag(tag) }, names.SubnetTagKind: func(tag string) names.Tag { return names.NewSubnetTag(tag) }, names.SpaceTagKind: func(tag string) names.Tag { return names.NewSpaceTag(tag) }, } func (*tagSuite) TestParseTag(c *gc.C) { for i, test := range parseTagTests { c.Logf("test %d: %q expectKind %q", i, test.tag, test.expectKind) tag, err := names.ParseTag(test.tag) if test.resultErr != "" { c.Assert(err, gc.ErrorMatches, test.resultErr) c.Assert(tag, gc.IsNil) // If the tag has a valid kind which matches the // expected kind, test that using an empty // expectKind does not change the error message. if tagKind, err := names.TagKind(test.tag); err == nil && tagKind == test.expectKind {
f := func() { tag = names.NewSubnetTag("foo") } c.Assert(f, gc.PanicMatches, "foo is not a valid subnet CIDR") } var parseSubnetTagTests = []struct { tag string expected names.Tag err error }{{ tag: "", err: names.InvalidTagError("", ""), }, { tag: "subnet-10.20.0.0/16", expected: names.NewSubnetTag("10.20.0.0/16"), }, { tag: "subnet-2001:db8::/32", expected: names.NewSubnetTag("2001:db8::/32"), }, { tag: "subnet-fe80::3%zone1/10", err: names.InvalidTagError("subnet-fe80::3%zone1/10", names.SubnetTagKind), }, { tag: "subnet-10.20.30.40/16", err: names.InvalidTagError("subnet-10.20.30.40/16", names.SubnetTagKind), }, { tag: "subnet-2001:db8::123/32", err: names.InvalidTagError("subnet-2001:db8::123/32", names.SubnetTagKind), }, { tag: "subnet-foo", err: names.InvalidTagError("subnet-foo", names.SubnetTagKind),