Esempio n. 1
0
// 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
}
Esempio n. 2
0
// 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
}