summaryrefslogtreecommitdiff
path: root/docs/dev/design_documents/resource_before_notifications.md
blob: cfae566289ac5c8f265a28997a6a9da7fa6c51ee (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# Before Notifications

Let users trigger another resource prior to an action happening.

## Motivation

    As a Chef user,
    I want to make one resource action a precondition for another,
    So that when two resources depend on each other, I can make an update succeed.

    As a Chef user,
    I want this action only to happen if the other resource *does* update,
    So that I don't unnecessarily run my preconditions on every single Chef run.

    As a Chef user,
    I want Chef to run an action if a resource updates,
    So that I don't have to implement the resource test logic in my recipe.

## Specification

We add a new `:before` timing which causes a notification to happen
*before* the resource actually updates. If the resource will not actually update,
this event does not fire.

The events you can specify would become:

- `:before` - before the resource updates, but *only* if an update will occur.
- `:immediately` - after the resource updates, but *only* if an update occurred.
- `:delayed` - after the resource updates, at the end of the run.

```ruby
package "foo" do
  action :upgrade
  # The package upgrade will fail if we try to upgrade while it runs!!!
  notifies :stop, "service[blah]", :before
end

service "blah" do
end
```

This will work for both `subscribes` and `notifies`.

### Backwards Compatibility

This will only affect resources, which have `:before` on them, and will
not modify any existing resources or recipes.

### Implementation

There is a tricky implementation detail here, because both the test part -- "is my
package version lower than the latest?" -- and the set part -- "call rpm and update the
package"-- of a resource are both part of the action. Chef only runs one
action to run at a time, and it seems ill-advised to change that without a lot
of extra thinking.

To get around this without breaking the model, we propose that resources with an
`:before` action run a why-run test of the action and trigger off of
that, before running the action for real. The flow of this resource:

```ruby
package "foo" do
  action :upgrade
  notifies :stop, "service[blah]", :before
end
```

The execution of the package upgrade looks like this:

1. If `:before` events are on the resource:
   a. raise an error if the resource does not support `why-run`.
   b. Turn on `why-run` temporarily.
   c. Run the action.
   d. Send the notification if `updated_by_last_action?` is true.
   e. Turn off `why-run`.
2. Run the action (for real!).
3. Send `:immediate` or `:delayed` notifications if `updated_by_last_action?` is true.