Example #1
0
// Handle is part of the watcher.StringsHandler interface.
// It should give us any actions currently enqueued for this machine.
// We try to execute every action before returning
func (h *handler) Handle(_ <-chan struct{}, actionsSlice []string) error {
	for _, actionId := range actionsSlice {
		ok := names.IsValidAction(actionId)
		if !ok {
			return errors.Errorf("got invalid action id %s", actionId)
		}

		actionTag := names.NewActionTag(actionId)
		action, err := h.config.Facade.Action(actionTag)
		if err != nil {
			return errors.Annotatef(err, "could not retrieve action %s", actionId)
		}

		err = h.config.Facade.ActionBegin(actionTag)
		if err != nil {
			return errors.Annotatef(err, "could not begin action %s", action.Name())
		}

		// We try to handle the action. The result returned from handling the action is
		// sent through using ActionFinish. We only stop the loop if ActionFinish fails.
		var finishErr error
		results, err := h.config.HandleAction(action.Name(), action.Params())
		if err != nil {
			finishErr = h.config.Facade.ActionFinish(actionTag, params.ActionFailed, nil, err.Error())
		} else {
			finishErr = h.config.Facade.ActionFinish(actionTag, params.ActionCompleted, results, "")
		}
		if finishErr != nil {
			return errors.Trace(finishErr)
		}
	}
	return nil
}
Example #2
0
// NewActionRunner exists to satisfy the Factory interface.
func (f *factory) NewActionRunner(actionId string) (Runner, error) {
	ch, err := getCharm(f.paths.GetCharmDir())
	if err != nil {
		return nil, errors.Trace(err)
	}

	ok := names.IsValidAction(actionId)
	if !ok {
		return nil, &badActionError{actionId, "not valid actionId"}
	}
	tag := names.NewActionTag(actionId)
	action, err := f.state.Action(tag)
	if params.IsCodeNotFoundOrCodeUnauthorized(err) {
		return nil, ErrActionNotAvailable
	} else if params.IsCodeActionNotAvailable(err) {
		return nil, ErrActionNotAvailable
	} else if err != nil {
		return nil, errors.Trace(err)
	}

	name := action.Name()
	spec, ok := ch.Actions().ActionSpecs[name]
	if !ok {
		return nil, &badActionError{name, "not defined"}
	}
	params := action.Params()
	if err := spec.ValidateParams(params); err != nil {
		return nil, &badActionError{name, err.Error()}
	}

	actionData := newActionData(name, &tag, params)
	ctx, err := f.contextFactory.ActionContext(actionData)
	runner := NewRunner(ctx, f.paths)
	return runner, nil
}
Example #3
0
func (s *actionSuite) TestActionNameFormats(c *gc.C) {
	marker := names.ActionMarker
	actionNameTests := []struct {
		pattern string
		valid   bool
	}{
		{pattern: "", valid: false},
		{pattern: "service", valid: false},
		{pattern: "service" + marker, valid: false},
		{pattern: "service" + marker + "0", valid: true},
		{pattern: "service" + marker + "00", valid: false},
		{pattern: "service" + marker + "0" + marker + "0", valid: false},

		{pattern: "service-name/0" + marker, valid: false},
		{pattern: "service-name-0" + marker, valid: false},
		{pattern: "service-name/0" + marker + "0", valid: true},
		{pattern: "service-name-0" + marker + "0", valid: false},

		{pattern: "service-name/0" + marker + "00", valid: false},
		{pattern: "service-name-0" + marker + "00", valid: false},
		{pattern: "service-name/0" + marker + "01", valid: false},
		{pattern: "service-name-0" + marker + "01", valid: false},
		{pattern: "service-name/0" + marker + "11", valid: true},
		{pattern: "service-name-0" + marker + "11", valid: false},
	}

	assertAction := func(s string, expect bool) {
		c.Assert(names.IsValidAction(s), gc.Equals, expect)
	}

	for i, test := range actionNameTests {
		c.Logf("test %d: %q", i, test.pattern)
		assertAction(test.pattern, test.valid)
	}
}
Example #4
0
// NewAction is part of the Factory interface.
func (f *factory) NewAction(actionId string) (Operation, error) {
	if !names.IsValidAction(actionId) {
		return nil, errors.Errorf("invalid action id %q", actionId)
	}
	return &runAction{
		actionId:      actionId,
		callbacks:     f.config.Callbacks,
		runnerFactory: f.config.RunnerFactory,
	}, nil
}
Example #5
0
// FailAction is part of the operation.Callbacks interface.
func (opc *operationCallbacks) FailAction(actionId, message string) error {
	if !names.IsValidAction(actionId) {
		return errors.Errorf("invalid action id %q", actionId)
	}
	tag := names.NewActionTag(actionId)
	err := opc.u.st.ActionFinish(tag, params.ActionFailed, nil, message)
	if params.IsCodeNotFoundOrCodeUnauthorized(err) {
		err = nil
	}
	return err
}
Example #6
0
// Validate returns an error if the info is not valid.
func (hi Info) Validate() error {
	switch hi.Kind {
	case hooks.RelationJoined, hooks.RelationChanged, hooks.RelationDeparted:
		if hi.RemoteUnit == "" {
			return fmt.Errorf("%q hook requires a remote unit", hi.Kind)
		}
		fallthrough
	case hooks.Install, hooks.Start, hooks.ConfigChanged, hooks.UpgradeCharm, hooks.Stop, hooks.RelationBroken:
		return nil
	case hooks.ActionRequested:
		if !names.IsValidAction(hi.ActionId) {
			return fmt.Errorf("action id %q cannot be parsed as an action tag", hi.ActionId)
		}
		return nil
	}
	return fmt.Errorf("unknown hook kind %q", hi.Kind)
}
Example #7
0
func (s *actionSuite) TestAction(c *gc.C) {
	var actionTests = []struct {
		description string
		action      params.Action
	}{{
		description: "A simple Action.",
		action: params.Action{
			Name:       "fakeaction",
			Parameters: basicParams,
		},
	}, {
		description: "An Action with nested parameters.",
		action: params.Action{
			Name: "fakeaction",
			Parameters: map[string]interface{}{
				"outfile": "foo.bz2",
				"compression": map[string]interface{}{
					"kind":    "bzip",
					"quality": float64(5.0),
				},
			},
		},
	}}

	for i, actionTest := range actionTests {
		c.Logf("test %d: %s", i, actionTest.description)
		a, err := s.uniterSuite.wordpressUnit.AddAction(
			actionTest.action.Name,
			actionTest.action.Parameters)
		c.Assert(err, jc.ErrorIsNil)

		ok := names.IsValidAction(a.Id())
		c.Assert(ok, gc.Equals, true)
		actionTag := names.NewActionTag(a.Id())
		c.Assert(a.Tag(), gc.Equals, actionTag)

		retrievedAction, err := s.uniter.Action(actionTag)
		c.Assert(err, jc.ErrorIsNil)

		c.Assert(retrievedAction.Name(), gc.DeepEquals, actionTest.action.Name)
		c.Assert(retrievedAction.Params(), gc.DeepEquals, actionTest.action.Parameters)
	}
}
Example #8
0
// FindActionTagsByPrefix finds Actions with ids that share the supplied prefix, and
// returns a list of corresponding ActionTags.
func (st *State) FindActionTagsByPrefix(prefix string) []names.ActionTag {
	actionLogger.Tracef("FindActionTagsByPrefix() %q", prefix)
	var results []names.ActionTag
	var doc struct {
		Id string `bson:"_id"`
	}

	actions, closer := st.getCollection(actionsC)
	defer closer()

	iter := actions.Find(bson.D{{"_id", bson.D{{"$regex", "^" + st.docID(prefix)}}}}).Iter()
	defer iter.Close()
	for iter.Next(&doc) {
		actionLogger.Tracef("FindActionTagsByPrefix() iter doc %+v", doc)
		localID := st.localID(doc.Id)
		if names.IsValidAction(localID) {
			results = append(results, names.NewActionTag(localID))
		}
	}
	actionLogger.Tracef("FindActionTagsByPrefix() %q found %+v", prefix, results)
	return results
}
Example #9
0
// ValidateTag should be called before calls to Tag() or ActionTag(). It verifies
// that the Action can produce a valid Tag.
func (a *Action) ValidateTag() bool {
	return names.IsValidAction(a.Id())
}