// Run implements Command.Run. func (c *ListCommand) Run(ctx *cmd.Context) error { return c.RunWithAPI(ctx, func(api SubnetAPI, ctx *cmd.Context) error { // Validate space and/or zone, if given to display a nicer error // message. // Get the list of subnets, filtering them as requested. subnets, err := api.ListSubnets(c.spaceTag, c.ZoneName) if err != nil { return errors.Annotate(err, "cannot list subnets") } // Display a nicer message in case no subnets were found. if len(subnets) == 0 { if c.SpaceName != "" || c.ZoneName != "" { ctx.Infof("no subnets found matching requested criteria") } else { ctx.Infof("no subnets to display") } return nil } // Construct the output list for displaying with the chosen // format. result := formattedList{ Subnets: make(map[string]formattedSubnet), } for _, sub := range subnets { subResult := formattedSubnet{ ProviderId: sub.ProviderId, Zones: sub.Zones, } // Use the CIDR to determine the subnet type. if ip, _, err := net.ParseCIDR(sub.CIDR); err != nil { return errors.Errorf("subnet %q has invalid CIDR", sub.CIDR) } else if ip.To4() != nil { subResult.Type = typeIPv4 } else if ip.To16() != nil { subResult.Type = typeIPv6 } // Space must be valid, but verify anyway. spaceTag, err := names.ParseSpaceTag(sub.SpaceTag) if err != nil { return errors.Annotatef(err, "subnet %q has invalid space", sub.CIDR) } subResult.Space = spaceTag.Id() // Display correct status according to the life cycle value. switch sub.Life { case params.Alive: subResult.Status = statusInUse case params.Dying, params.Dead: subResult.Status = statusTerminating } result.Subnets[sub.CIDR] = subResult } return c.out.Write(ctx, result) }) }
func (s *spaceSuite) TestParseSpaceTag(c *gc.C) { for i, t := range parseSpaceTagTests { c.Logf("test %d: %s", i, t.tag) got, err := names.ParseSpaceTag(t.tag) if err != nil || t.err != nil { c.Check(err, gc.DeepEquals, t.err) continue } c.Check(got, gc.FitsTypeOf, t.expected) c.Check(got, gc.Equals, t.expected) } }
// ListSubnets lists all the available subnets or only those matching // all given optional filters. func ListSubnets(api NetworkBacking, args params.SubnetsFilters) (results params.ListSubnetsResults, err error) { subnets, err := api.AllSubnets() if err != nil { return results, errors.Trace(err) } var spaceFilter string if args.SpaceTag != "" { tag, err := names.ParseSpaceTag(args.SpaceTag) if err != nil { return results, errors.Trace(err) } spaceFilter = tag.Id() } zoneFilter := args.Zone for _, subnet := range subnets { if spaceFilter != "" && subnet.SpaceName() != spaceFilter { logger.Tracef( "filtering subnet %q from space %q not matching filter %q", subnet.CIDR(), subnet.SpaceName(), spaceFilter, ) continue } zoneSet := set.NewStrings(subnet.AvailabilityZones()...) if zoneFilter != "" && !zoneSet.IsEmpty() && !zoneSet.Contains(zoneFilter) { logger.Tracef( "filtering subnet %q with zones %v not matching filter %q", subnet.CIDR(), subnet.AvailabilityZones(), zoneFilter, ) continue } result := params.Subnet{ CIDR: subnet.CIDR(), ProviderId: string(subnet.ProviderId()), VLANTag: subnet.VLANTag(), Life: subnet.Life(), SpaceTag: names.NewSpaceTag(subnet.SpaceName()).String(), Zones: subnet.AvailabilityZones(), Status: subnet.Status(), } results.Results = append(results.Results, result) } return results, nil }
// validateSpace parses the given spaceTag and verifies it exists by looking it // up in the cache (or populates the cache if empty). func (cache *addSubnetsCache) validateSpace(spaceTag string) (*names.SpaceTag, error) { if spaceTag == "" { return nil, errors.Errorf("SpaceTag is required") } tag, err := names.ParseSpaceTag(spaceTag) if err != nil { return nil, errors.Annotate(err, "given SpaceTag is invalid") } // Otherwise we need the cache to validate. if cache.allSpaces == nil { // Not yet cached. logger.Tracef("caching known spaces") allSpaces, err := cache.api.AllSpaces() if err != nil { return nil, errors.Annotate(err, "cannot validate given SpaceTag") } cache.allSpaces = set.NewStrings() for _, space := range allSpaces { if cache.allSpaces.Contains(space.Name()) { logger.Warningf("ignoring duplicated space %q", space.Name()) continue } cache.allSpaces.Add(space.Name()) } } if cache.allSpaces.IsEmpty() { return nil, errors.Errorf("no spaces defined") } logger.Tracef("using cached spaces: %v", cache.allSpaces.SortedValues()) if !cache.allSpaces.Contains(tag.Id()) { return nil, errors.NotFoundf("space %q", tag.Id()) // " not found" } return &tag, nil }
func (api *spacesAPI) createOneSpace(args params.CreateSpaceParams) error { // Validate the args, assemble information for api.backing.AddSpaces var subnets []string spaceTag, err := names.ParseSpaceTag(args.SpaceTag) if err != nil { return errors.Trace(err) } for _, tag := range args.SubnetTags { subnetTag, err := names.ParseSubnetTag(tag) if err != nil { return errors.Trace(err) } subnets = append(subnets, subnetTag.Id()) } // Add the validated space err = api.backing.AddSpace(spaceTag.Id(), subnets, args.Public) if err != nil { return errors.Trace(err) } return nil }