// 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 }
// validateSubnet ensures either subnetTag or providerId is valid (not both), // then uses the cache to validate and lookup the provider SubnetInfo for the // subnet, if found. func (cache *addSubnetsCache) validateSubnet(subnetTag, providerId string) (*network.SubnetInfo, error) { haveTag := subnetTag != "" haveProviderId := providerId != "" if !haveTag && !haveProviderId { return nil, errors.Errorf("either SubnetTag or SubnetProviderId is required") } else if haveTag && haveProviderId { return nil, errors.Errorf("SubnetTag and SubnetProviderId cannot be both set") } var tag names.SubnetTag if haveTag { var err error tag, err = names.ParseSubnetTag(subnetTag) if err != nil { return nil, errors.Annotate(err, "given SubnetTag is invalid") } } // Otherwise we need the cache to validate. if err := cache.cacheSubnets(); err != nil { return nil, errors.Trace(err) } if haveTag { providerIds, ok := cache.providerIdsByCIDR[tag.Id()] if !ok || providerIds.IsEmpty() { return nil, errors.NotFoundf("subnet with CIDR %q", tag.Id()) } if providerIds.Size() > 1 { ids := `"` + strings.Join(providerIds.SortedValues(), `", "`) + `"` return nil, errors.Errorf( "multiple subnets with CIDR %q: retry using ProviderId from: %s", tag.Id(), ids, ) } // A single CIDR matched. providerId = providerIds.Values()[0] } info, ok := cache.subnetsByProviderId[providerId] if !ok || info == nil { return nil, errors.NotFoundf( "subnet with CIDR %q and ProviderId %q", tag.Id(), providerId, ) } // Do last-call validation. if !names.IsValidSubnet(info.CIDR) { _, ipnet, err := net.ParseCIDR(info.CIDR) if err != nil && info.CIDR != "" { // The underlying error is not important here, just that // the CIDR is invalid. return nil, errors.Errorf( "subnet with CIDR %q and ProviderId %q: invalid CIDR", info.CIDR, providerId, ) } if info.CIDR == "" { return nil, errors.Errorf( "subnet with ProviderId %q: empty CIDR", providerId, ) } return nil, errors.Errorf( "subnet with ProviderId %q: incorrect CIDR format %q, expected %q", providerId, info.CIDR, ipnet.String(), ) } return info, nil }