Example #1
0
File: space.go Project: makyo/juju
// CheckName checks whether name is a valid space name.
func CheckName(name string) (string, error) {
	// Validate given name.
	if !names.IsValidSpace(name) {
		return "", errors.Errorf("%q is not a valid space name", name)
	}
	return name, nil
}
Example #2
0
func (v *Value) validateSpaces(spaces *[]string) error {
	if spaces == nil {
		return nil
	}
	for _, name := range *spaces {
		space := strings.TrimPrefix(name, "^")
		if !names.IsValidSpace(space) {
			return errors.Errorf("%q is not a valid space name", space)
		}
	}
	return nil
}
Example #3
0
func (s *spaceSuite) TestSpaceNames(c *gc.C) {
	for i, test := range spaceNameTests {
		c.Logf("test %d: %q", i, test.pattern)
		c.Check(names.IsValidSpace(test.pattern), gc.Equals, test.valid)
		if test.valid {
			expectTag := fmt.Sprintf("%s-%s", names.SpaceTagKind, test.pattern)
			c.Check(names.NewSpaceTag(test.pattern).String(), gc.Equals, expectTag)
		} else {
			expectErr := fmt.Sprintf("%q is not a valid space name", test.pattern)
			testTag := func() { names.NewSpaceTag(test.pattern) }
			c.Check(testTag, gc.PanicMatches, regexp.QuoteMeta(expectErr))
		}
	}
}
Example #4
0
// AddSpace creates and returns a new space.
func (st *State) AddSpace(name string, subnets []string, isPublic bool) (newSpace *Space, err error) {
	defer errors.DeferredAnnotatef(&err, "adding space %q", name)
	if !names.IsValidSpace(name) {
		return nil, errors.NewNotValid(nil, "invalid space name")
	}

	spaceID := st.docID(name)
	spaceDoc := spaceDoc{
		DocID:    spaceID,
		EnvUUID:  st.EnvironUUID(),
		Life:     Alive,
		Name:     name,
		IsPublic: isPublic,
	}
	newSpace = &Space{doc: spaceDoc, st: st}

	ops := []txn.Op{{
		C:      spacesC,
		Id:     spaceID,
		Assert: txn.DocMissing,
		Insert: spaceDoc,
	}}

	for _, subnetId := range subnets {
		// TODO:(mfoord) once we have refcounting for subnets we should
		// also assert that the refcount is zero as moving the space of a
		// subnet in use is not permitted.
		ops = append(ops, txn.Op{
			C:      subnetsC,
			Id:     st.docID(subnetId),
			Assert: txn.DocExists,
			Update: bson.D{{"$set", bson.D{{"space-name", name}}}},
		})
	}

	if err := st.runTransaction(ops); err == txn.ErrAborted {
		if _, err := st.Space(name); err == nil {
			return nil, errors.AlreadyExistsf("space %q", name)
		}
		for _, subnetId := range subnets {
			if _, err := st.Subnet(subnetId); errors.IsNotFound(err) {
				return nil, err
			}
		}
	} else if err != nil {
		return nil, err
	}
	return newSpace, nil
}
Example #5
0
// Init is defined on the cmd.Command interface. It checks the
// arguments for sanity and sets up the command to run.
func (c *removeCommand) Init(args []string) (err error) {
	defer errors.DeferredAnnotatef(&err, "invalid arguments specified")

	// Validate given name.
	if len(args) == 0 {
		return errors.New("space name is required")
	}
	givenName := args[0]
	if !names.IsValidSpace(givenName) {
		return errors.Errorf("%q is not a valid space name", givenName)
	}
	c.name = givenName

	return cmd.CheckEmpty(args[1:])
}
Example #6
0
// Init is defined on the cmd.Command interface. It checks the
// arguments for sanity and sets up the command to run.
func (c *renameCommand) Init(args []string) (err error) {
	defer errors.DeferredAnnotatef(&err, "invalid arguments specified")

	switch len(args) {
	case 0:
		return errors.New("old-name is required")
	case 1:
		return errors.New("new-name is required")
	}
	for _, name := range args {
		if !names.IsValidSpace(name) {
			return errors.Errorf("%q is not a valid space name", name)
		}
	}
	c.Name = args[0]
	c.NewName = args[1]

	if c.Name == c.NewName {
		return errors.New("old-name and new-name are the same")
	}

	return cmd.CheckEmpty(args[2:])
}
Example #7
0
File: deploy.go Project: OSBI/juju
// parseBind parses the --bind option. Valid forms are:
// * relation-name=space-name
// * space-name
// * The above in a space separated list to specify multiple bindings,
//   e.g. "rel1=space1 rel2=space2 space3"
func (c *DeployCommand) parseBind() error {
	bindings := make(map[string]string)
	if c.BindToSpaces == "" {
		return nil
	}

	for _, s := range strings.Split(c.BindToSpaces, " ") {
		s = strings.TrimSpace(s)
		if s == "" {
			continue
		}

		v := strings.Split(s, "=")
		var endpoint, space string
		switch len(v) {
		case 1:
			endpoint = ""
			space = v[0]
		case 2:
			if v[0] == "" {
				return errors.New(parseBindErrorPrefix + "Found = without relation name. Use a lone space name to set the default.")
			}
			endpoint = v[0]
			space = v[1]
		default:
			return errors.New(parseBindErrorPrefix + "Found multiple = in binding. Did you forget to space-separate the binding list?")
		}

		if !names.IsValidSpace(space) {
			return errors.New(parseBindErrorPrefix + "Space name invalid.")
		}
		bindings[endpoint] = space
	}
	c.Bindings = bindings
	return nil
}
Example #8
0
func (dw *discoverspacesWorker) handleSubnets() error {
	environ, ok := environs.SupportsNetworking(dw.config.Environ)
	if !ok {
		logger.Debugf("not a networking environ")
		return nil
	}
	if supported, err := environ.SupportsSpaceDiscovery(); err != nil {
		return errors.Trace(err)
	} else if !supported {
		logger.Debugf("environ does not support space discovery")
		return nil
	}
	providerSpaces, err := environ.Spaces()
	if err != nil {
		return errors.Trace(err)
	}

	facade := dw.config.Facade
	listSpacesResult, err := facade.ListSpaces()
	if err != nil {
		return errors.Trace(err)
	}
	stateSubnets, err := facade.ListSubnets(params.SubnetsFilters{})
	if err != nil {
		return errors.Trace(err)
	}

	stateSubnetIds := make(set.Strings)
	for _, subnet := range stateSubnets.Results {
		stateSubnetIds.Add(subnet.ProviderId)
	}
	stateSpaceMap := make(map[string]params.ProviderSpace)
	spaceNames := make(set.Strings)
	for _, space := range listSpacesResult.Results {
		stateSpaceMap[space.ProviderId] = space
		spaceNames.Add(space.Name)
	}

	// TODO(mfoord): we need to delete spaces and subnets that no longer
	// exist, so long as they're not in use.
	var createSpacesArgs params.CreateSpacesParams
	var addSubnetsArgs params.AddSubnetsParams
	for _, space := range providerSpaces {
		// Check if the space is already in state, in which case we know
		// its name.
		stateSpace, ok := stateSpaceMap[string(space.ProviderId)]
		var spaceTag names.SpaceTag
		if ok {
			spaceName := stateSpace.Name
			if !names.IsValidSpace(spaceName) {
				// Can only happen if an invalid name is stored
				// in state.
				logger.Errorf("space %q has an invalid name, ignoring", spaceName)
				continue

			}
			spaceTag = names.NewSpaceTag(spaceName)

		} else {
			// The space is new, we need to create a valid name for it
			// in state.
			spaceName := string(space.Name)
			// Convert the name into a valid name that isn't already in
			// use.
			spaceName = dw.config.NewName(spaceName, spaceNames)
			spaceNames.Add(spaceName)
			spaceTag = names.NewSpaceTag(spaceName)
			// We need to create the space.
			createSpacesArgs.Spaces = append(createSpacesArgs.Spaces, params.CreateSpaceParams{
				Public:     false,
				SpaceTag:   spaceTag.String(),
				ProviderId: string(space.ProviderId),
			})
		}
		// TODO(mfoord): currently no way of removing subnets, or
		// changing the space they're in, so we can only add ones we
		// don't already know about.
		for _, subnet := range space.Subnets {
			if stateSubnetIds.Contains(string(subnet.ProviderId)) {
				continue
			}
			zones := subnet.AvailabilityZones
			if len(zones) == 0 {
				logger.Tracef(
					"provider does not specify zones for subnet %q; using 'default' zone as fallback",
					subnet.CIDR,
				)
				zones = []string{"default"}
			}
			addSubnetsArgs.Subnets = append(addSubnetsArgs.Subnets, params.AddSubnetParams{
				SubnetProviderId: string(subnet.ProviderId),
				SpaceTag:         spaceTag.String(),
				Zones:            zones,
			})
		}
	}

	if err := dw.createSpacesFromArgs(createSpacesArgs); err != nil {
		return errors.Trace(err)
	}

	if err := dw.addSubnetsFromArgs(addSubnetsArgs); err != nil {
		return errors.Trace(err)
	}

	return nil
}
Example #9
0
// ValidateSpace parses given and returns an error if it's not a valid
// space name, otherwise returns the parsed tag and no error.
func (s *SubnetCommandBase) ValidateSpace(given string) (names.SpaceTag, error) {
	if !names.IsValidSpace(given) {
		return names.SpaceTag{}, errors.Errorf("%q is not a valid space name", given)
	}
	return names.NewSpaceTag(given), nil
}
Example #10
0
func (dw *discoverspacesWorker) handleSubnets(env environs.NetworkingEnviron) error {
	ok, err := env.SupportsSpaceDiscovery()
	if err != nil {
		return errors.Trace(err)
	}
	if !ok {
		// Nothing to do.
		return nil
	}
	providerSpaces, err := env.Spaces()
	if err != nil {
		return errors.Trace(err)
	}
	listSpacesResult, err := dw.api.ListSpaces()
	if err != nil {
		return errors.Trace(err)
	}

	stateSubnets, err := dw.api.ListSubnets(params.SubnetsFilters{})
	if err != nil {
		return errors.Trace(err)
	}
	stateSubnetIds := make(set.Strings)
	for _, subnet := range stateSubnets.Results {
		stateSubnetIds.Add(subnet.ProviderId)
	}
	stateSpaceMap := make(map[string]params.ProviderSpace)
	spaceNames := make(set.Strings)
	for _, space := range listSpacesResult.Results {
		stateSpaceMap[space.ProviderId] = space
		spaceNames.Add(space.Name)
	}

	// TODO(mfoord): we need to delete spaces and subnets that no longer
	// exist, so long as they're not in use.
	for _, space := range providerSpaces {
		// Check if the space is already in state, in which case we know
		// its name.
		stateSpace, ok := stateSpaceMap[string(space.ProviderId)]
		var spaceTag names.SpaceTag
		if ok {
			spaceName := stateSpace.Name
			if !names.IsValidSpace(spaceName) {
				// Can only happen if an invalid name is stored
				// in state.
				logger.Errorf("space %q has an invalid name, ignoring", spaceName)
				continue

			}
			spaceTag = names.NewSpaceTag(spaceName)

		} else {
			// The space is new, we need to create a valid name for it
			// in state.
			spaceName := string(space.ProviderId)
			// Convert the name into a valid name that isn't already in
			// use.
			spaceName = convertSpaceName(spaceName, spaceNames)
			spaceNames.Add(spaceName)
			spaceTag = names.NewSpaceTag(spaceName)
			// We need to create the space.
			args := params.CreateSpacesParams{
				Spaces: []params.CreateSpaceParams{{
					Public:     false,
					SpaceTag:   spaceTag.String(),
					ProviderId: string(space.ProviderId),
				}}}
			result, err := dw.api.CreateSpaces(args)
			if err != nil {
				logger.Errorf("error creating space %v", err)
				return errors.Trace(err)
			}
			if len(result.Results) != 1 {
				return errors.Errorf("unexpected number of results from CreateSpaces, should be 1: %v", result)
			}
			if result.Results[0].Error != nil {
				return errors.Errorf("error from CreateSpaces: %v", result.Results[0].Error)
			}
		}
		// TODO(mfoord): currently no way of removing subnets, or
		// changing the space they're in, so we can only add ones we
		// don't already know about.
		logger.Debugf("Created space %v with %v subnets", spaceTag.String(), len(space.Subnets))
		for _, subnet := range space.Subnets {
			if stateSubnetIds.Contains(string(subnet.ProviderId)) {
				continue
			}
			zones := subnet.AvailabilityZones
			if len(zones) == 0 {
				zones = []string{"default"}
			}
			args := params.AddSubnetsParams{
				Subnets: []params.AddSubnetParams{{
					SubnetProviderId: string(subnet.ProviderId),
					SpaceTag:         spaceTag.String(),
					Zones:            zones,
				}}}
			logger.Tracef("Adding subnet %v", subnet.CIDR)
			result, err := dw.api.AddSubnets(args)
			if err != nil {
				logger.Errorf("invalid creating subnet %v", err)
				return errors.Trace(err)
			}
			if len(result.Results) != 1 {
				return errors.Errorf("unexpected number of results from AddSubnets, should be 1: %v", result)
			}
			if result.Results[0].Error != nil {
				logger.Errorf("error creating subnet %v", result.Results[0].Error)
				return errors.Errorf("error creating subnet %v", result.Results[0].Error)
			}
		}
	}
	return nil
}
Example #11
0
// AddSpace creates and returns a new space.
func (st *State) AddSpace(name string, providerId network.Id, subnets []string, isPublic bool) (newSpace *Space, err error) {
	defer errors.DeferredAnnotatef(&err, "adding space %q", name)
	if !names.IsValidSpace(name) {
		return nil, errors.NewNotValid(nil, "invalid space name")
	}

	spaceID := st.docID(name)
	var modelLocalProviderID string
	if providerId != "" {
		modelLocalProviderID = st.docID(string(providerId))
	}

	spaceDoc := spaceDoc{
		DocID:      spaceID,
		ModelUUID:  st.ModelUUID(),
		Life:       Alive,
		Name:       name,
		IsPublic:   isPublic,
		ProviderId: string(modelLocalProviderID),
	}
	newSpace = &Space{doc: spaceDoc, st: st}

	ops := []txn.Op{{
		C:      spacesC,
		Id:     spaceID,
		Assert: txn.DocMissing,
		Insert: spaceDoc,
	}}

	for _, subnetId := range subnets {
		// TODO:(mfoord) once we have refcounting for subnets we should
		// also assert that the refcount is zero as moving the space of a
		// subnet in use is not permitted.
		ops = append(ops, txn.Op{
			C:      subnetsC,
			Id:     st.docID(subnetId),
			Assert: txn.DocExists,
			Update: bson.D{{"$set", bson.D{{"space-name", name}}}},
		})
	}

	if err := st.runTransaction(ops); err == txn.ErrAborted {
		if _, err := st.Space(name); err == nil {
			return nil, errors.AlreadyExistsf("space %q", name)
		}
		for _, subnetId := range subnets {
			if _, err := st.Subnet(subnetId); errors.IsNotFound(err) {
				return nil, err
			}
		}
	} else if err != nil {
		return nil, err
	}

	// If the ProviderId was not unique adding the space can fail without an
	// error. Refreshing catches this by returning NotFoundError.
	err = newSpace.Refresh()
	if err != nil {
		if errors.IsNotFound(err) {
			return nil, errors.Errorf("ProviderId %q not unique", providerId)
		}
		return nil, errors.Trace(err)
	}

	return newSpace, nil
}