Example #1
0
// hasFailedDependencies checks if a resource has failed dependencies.
func (c *Catalog) hasFailedDependencies(r resource.Resource) error {
	c.status.Lock()
	defer c.status.Unlock()

	for _, dep := range r.Dependencies() {
		item := c.status.Items[dep]
		if item.Err != nil {
			return fmt.Errorf("failed dependency for %s", dep)
		}
	}

	return nil
}
Example #2
0
// processResource processes a single resource
func (c *Catalog) processResource(r resource.Resource) error {
	if err := r.Validate(); err != nil {
		return err
	}

	state, err := r.Evaluate()
	if err != nil {
		return err
	}

	if c.config.DryRun {
		return nil
	}

	// Current and wanted states for the resource
	want := utils.NewString(state.Want)
	current := utils.NewString(state.Current)

	// The list of present and absent states for the resource
	present := utils.NewList(r.GetPresentStates()...)
	absent := utils.NewList(r.GetAbsentStates()...)

	var action func() error
	switch {
	case want.IsInList(present) && current.IsInList(absent):
		action = r.Create
	case want.IsInList(absent) && current.IsInList(present):
		action = r.Delete
	case state.Outdated:
		action = r.Update
	}

	if action != nil {
		return action()
	}

	return nil
}
Example #3
0
// runTriggers executes the triggers for each
// monitored resource if it's state has changed
func (c *Catalog) runTriggers(r resource.Resource) error {
	c.status.Lock()
	defer c.status.Unlock()

	for subscribed, trigger := range r.SubscribedTo() {
		item := c.status.Items[subscribed]
		if !item.StateChanged {
			continue
		}

		c.config.Logger.Printf("%s running trigger, because %s has changed\n", r.ID(), subscribed)
		c.config.L.Push(trigger)
		if err := c.config.L.PCall(0, 0, nil); err != nil {
			c.config.Logger.Printf("%s trigger exited with an error: %s\n", r.ID(), err)
			return err
		}
	}

	return nil
}
Example #4
0
// execute processes a single resource
func (c *Catalog) execute(r resource.Resource) *StatusItem {
	if err := c.hasFailedDependencies(r); err != nil {
		return &StatusItem{Err: err}
	}

	if err := r.Validate(); err != nil {
		return &StatusItem{Err: err}
	}

	if err := r.Initialize(); err != nil {
		return &StatusItem{Err: err}
	}
	defer r.Close()

	state, err := r.Evaluate()
	if err != nil {
		return &StatusItem{Err: err}
	}

	if c.config.DryRun {
		return &StatusItem{}
	}

	// Current and wanted states for the resource
	want := utils.NewString(state.Want)
	current := utils.NewString(state.Current)

	// The list of present and absent states for the resource
	present := utils.NewList(r.PresentStates()...)
	absent := utils.NewList(r.AbsentStates()...)

	// Process resource
	id := r.ID()
	var action func() error
	switch {
	case want.IsInList(present) && current.IsInList(absent):
		action = r.Create
		c.config.Logger.Printf("%s is %s, should be %s\n", id, current, want)
	case want.IsInList(absent) && current.IsInList(present):
		action = r.Delete
		c.config.Logger.Printf("%s is %s, should be %s\n", id, current, want)
	default:
		// No-op: resource is in sync
	}

	stateChanged := false
	if action != nil {
		stateChanged = true
		if err := action(); err != nil {
			return &StatusItem{StateChanged: true, Err: err}
		}
	}

	// Process resource properties
	for _, p := range r.Properties() {
		synced, err := p.IsSynced()
		if err != nil {
			// Some properties make no sense if the resource is absent, e.g.
			// setting up file permissions requires that the file managed by the
			// resource is present, therefore we ignore errors for properties
			// which make no sense if the resource is absent.
			if err == resource.ErrResourceAbsent {
				continue
			}
			e := fmt.Errorf("unable to evaluate property %s: %s\n", p.Name, err)
			return &StatusItem{StateChanged: true, Err: e}
		}

		if !synced {
			stateChanged = true
			c.config.Logger.Printf("%s property '%s' is out of date\n", id, p.Name())
			if err := p.Set(); err != nil {
				e := fmt.Errorf("unable to set property %s: %s\n", p.Name, err)
				return &StatusItem{StateChanged: true, Err: e}
			}
		}
	}

	if err := c.runTriggers(r); err != nil {
		return &StatusItem{StateChanged: stateChanged, Err: err}
	}

	return &StatusItem{StateChanged: stateChanged, Err: nil}
}