Skip to content
This repository was archived by the owner on Feb 7, 2020. It is now read-only.

Commit b86efe5

Browse files
authored
Merge pull request #8 from ripienaar/7
(#7) Add a provisioned type
2 parents acdc39b + 9c11a42 commit b86efe5

11 files changed

+262
-185
lines changed

README.md

+13-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ These lifecycle events are published to the `choria.lifecycle.event.<type>.<comp
1212
|-----|-----------|
1313
|Startup|Event to emit when components start, requires `Identity()`, `Component()` and `Version()` options|
1414
|Shutdown|Event to emit when components shut down, requires `Identity()` and `Component()` options|
15+
|Provisioned|Event to emit after provisioning of a component, requires `Identity()` and `Component()` options|
1516

1617
#### Sample Events
1718
### Schemas
@@ -41,6 +42,17 @@ Event Schemas are stored in the [Choria Schemas repository](https://github.com/c
4142
}
4243
```
4344

45+
#### Provisioned
46+
47+
```json
48+
{
49+
"protocol":"choria:lifecycle:provisioned:1",
50+
"identity":"c1.example.net",
51+
"component":"server",
52+
"timestamp":1535369536
53+
}
54+
```
55+
4456
## Viewing events
4557

4658
In a shell configured as a Choria Client run `choria tool event` to view events in real time.
@@ -59,7 +71,7 @@ err = lifecycle.PublishEvent(event, conn)
5971

6072
If you are emitting `lifecycle.Shutdown` events right before exiting be sure to call `conn.Close()` so the buffers are flushed prior to shutdown.
6173

62-
## Receiving a events
74+
## Receiving events
6375

6476
These events are used to orchestrate associated tools like the [Provisioning Server](https://github.com/choria-io/provisioning-agent) that listens for these events and immediately add a new node to the provisioning queue.
6577

basic.go

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
package lifecycle
2+
3+
import "fmt"
4+
5+
type basicEvent struct {
6+
Protocol string `json:"protocol"`
7+
Ident string `json:"identity"`
8+
Comp string `json:"component"`
9+
Timestamp int64 `json:"timestamp"`
10+
11+
etype string
12+
dtype Type
13+
}
14+
15+
// Component is the component that produced the event
16+
func (e *basicEvent) Component() string {
17+
return e.Comp
18+
}
19+
20+
// SetComponent sets the component for the event
21+
func (e *basicEvent) SetComponent(c string) {
22+
e.Comp = c
23+
}
24+
25+
// SetIdentity sets the identity for the event
26+
func (e *basicEvent) SetIdentity(i string) {
27+
e.Ident = i
28+
}
29+
30+
// Identity sets the identity for the event
31+
func (e *basicEvent) Identity() string {
32+
return e.Ident
33+
}
34+
35+
// Target is where to publish the event to
36+
func (e *basicEvent) Target() (string, error) {
37+
if e.Comp == "" {
38+
return "", fmt.Errorf("event is not complete, component has not been set")
39+
}
40+
41+
return fmt.Sprintf("choria.lifecycle.event.%s.%s", e.etype, e.Comp), nil
42+
}
43+
44+
// String is text suitable to display on the console etc
45+
func (e *basicEvent) String() string {
46+
return fmt.Sprintf("[%s] %s: %s", e.etype, e.Ident, e.Component())
47+
}
48+
49+
// Type is the type of event
50+
func (e *basicEvent) Type() Type {
51+
return e.dtype
52+
}

basic_test.go

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package lifecycle
2+
3+
import (
4+
. "github.com/onsi/ginkgo"
5+
. "github.com/onsi/gomega"
6+
)
7+
8+
var _ = Describe("basicEvent", func() {
9+
Describe("Component", func() {
10+
It("Should return the right component", func() {
11+
e := &basicEvent{Comp: "test"}
12+
Expect(e.Component()).To(Equal("test"))
13+
})
14+
})
15+
16+
Describe("SetComponent", func() {
17+
It("Should set the component", func() {
18+
e := &basicEvent{}
19+
e.SetComponent("component")
20+
Expect(e.Comp).To(Equal("component"))
21+
})
22+
})
23+
24+
Describe("SetIdentity", func() {
25+
It("Should set the identity", func() {
26+
e := &basicEvent{}
27+
e.SetIdentity("node.example")
28+
Expect(e.Ident).To(Equal("node.example"))
29+
})
30+
})
31+
32+
Describe("Target", func() {
33+
It("Should detect incomplete events", func() {
34+
e := &basicEvent{etype: "basic"}
35+
_, err := e.Target()
36+
Expect(err).To(MatchError("event is not complete, component has not been set"))
37+
})
38+
39+
It("Should return the right target", func() {
40+
e := &basicEvent{etype: "basic", Comp: "ginkgo"}
41+
t, err := e.Target()
42+
Expect(err).ToNot(HaveOccurred())
43+
Expect(t).To(Equal("choria.lifecycle.event.basic.ginkgo"))
44+
})
45+
})
46+
47+
Describe("String", func() {
48+
It("Should return the right string", func() {
49+
e := &basicEvent{etype: "basic", Comp: "ginkgo", Ident: "node.example"}
50+
Expect(e.String()).To(Equal("[basic] node.example: ginkgo"))
51+
})
52+
})
53+
54+
Describe("Type", func() {
55+
It("Should return the right Type", func() {
56+
e := &basicEvent{etype: "basic", dtype: Shutdown, Comp: "ginkg", Ident: "node.example"}
57+
Expect(e.Type()).To(Equal(Shutdown))
58+
})
59+
})
60+
})

lifecycle.go

+5-2
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,14 @@ type Type int
2121
const (
2222
_ = iota
2323

24-
// Startup is an event components should publish when they start
24+
// Startup is an event components can publish when they start
2525
Startup Type = iota
2626

27-
// Shutdown is an event components should publish when they shutdown
27+
// Shutdown is an event components can publish when they shutdown
2828
Shutdown
29+
30+
// Provisioned is an event components can publish post provisioning
31+
Provisioned
2932
)
3033

3134
var eventTypes = make(map[string]Type)

lifecycle_test.go

+4-9
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"os"
55
"testing"
66

7-
"github.com/choria-io/go-choria/config"
87
gomock "github.com/golang/mock/gomock"
98

109
. "github.com/onsi/ginkgo"
@@ -21,16 +20,11 @@ var _ = Describe("Events", func() {
2120
var (
2221
mockctl *gomock.Controller
2322
conn *MockPublishConnector
24-
cfg *config.Config
25-
err error
2623
)
2724

2825
BeforeEach(func() {
2926
mockctl = gomock.NewController(GinkgoT())
3027
conn = NewMockPublishConnector(mockctl)
31-
cfg, err = config.NewDefaultConfig()
32-
Expect(err).ToNot(HaveOccurred())
33-
cfg.Identity = "test.ginkgo"
3428
mockTime = 1535106973
3529
})
3630

@@ -49,7 +43,7 @@ var _ = Describe("Events", func() {
4943

5044
Describe("EventTypeNames", func() {
5145
It("Should list all known types", func() {
52-
Expect(EventTypeNames()).To(Equal([]string{"shutdown", "startup"}))
46+
Expect(EventTypeNames()).To(Equal([]string{"provisioned", "shutdown", "startup"}))
5347
})
5448
})
5549

@@ -72,10 +66,11 @@ var _ = Describe("Events", func() {
7266

7367
Describe("PublishEvent", func() {
7468
It("Should publish the event to the right destination", func() {
75-
event, err := New(Startup, Component("ginkgo"))
69+
event, err := New(Startup, Component("ginkgo"), Version("1.2.3"), Identity("ginkgo.example.net"))
7670
Expect(err).ToNot(HaveOccurred())
7771
mockTime = 1535106973
78-
conn.EXPECT().PublishRaw("choria.lifecycle.event.startup.ginkgo", []byte(`{"protocol":"choria:lifecycle:startup:1","identity":"","version":"","timestamp":1535106973,"component":"ginkgo"}`))
72+
Expect(err).ToNot(HaveOccurred())
73+
conn.EXPECT().PublishRaw("choria.lifecycle.event.startup.ginkgo", []byte(`{"protocol":"choria:lifecycle:startup:1","identity":"ginkgo.example.net","component":"ginkgo","timestamp":1535106973,"version":"1.2.3"}`))
7974
PublishEvent(event, conn)
8075
})
8176
})

provisioned.go

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package lifecycle
2+
3+
import (
4+
"encoding/json"
5+
"fmt"
6+
)
7+
8+
// ProvisionedEvent is a choria::lifecycle::provisioned:1 event
9+
type ProvisionedEvent struct {
10+
basicEvent
11+
}
12+
13+
func init() {
14+
eventTypes["provisioned"] = Provisioned
15+
16+
eventJSONParsers[Provisioned] = func(j []byte) (Event, error) {
17+
return newProvisionedEventFromJSON(j)
18+
}
19+
20+
eventFactories[Provisioned] = func(opts ...Option) Event {
21+
return newProvisionedEvent(opts...)
22+
}
23+
}
24+
25+
func newProvisionedEvent(opts ...Option) *ProvisionedEvent {
26+
event := &ProvisionedEvent{
27+
basicEvent: basicEvent{
28+
Protocol: "choria:lifecycle:provisioned:1",
29+
Timestamp: timeStamp(),
30+
etype: "provisioned",
31+
dtype: Provisioned,
32+
},
33+
}
34+
35+
for _, o := range opts {
36+
o(event)
37+
}
38+
39+
return event
40+
}
41+
42+
func newProvisionedEventFromJSON(j []byte) (*ProvisionedEvent, error) {
43+
event := &ProvisionedEvent{
44+
basicEvent: basicEvent{
45+
etype: "provisioned",
46+
dtype: Provisioned,
47+
},
48+
}
49+
50+
err := json.Unmarshal(j, event)
51+
if err != nil {
52+
return nil, err
53+
}
54+
55+
if event.Protocol != "choria:lifecycle:provisioned:1" {
56+
return nil, fmt.Errorf("invalid protocol '%s'", event.Protocol)
57+
}
58+
59+
return event, nil
60+
}

provisioned_test.go

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package lifecycle
2+
3+
import (
4+
. "github.com/onsi/ginkgo"
5+
. "github.com/onsi/gomega"
6+
)
7+
8+
var _ = Describe("ProvisionedEvent", func() {
9+
Describe("newProvisionedEvent", func() {
10+
It("Should create the event and set options", func() {
11+
event := newProvisionedEvent(Component("ginkgo"))
12+
Expect(event.Component()).To(Equal("ginkgo"))
13+
Expect(event.dtype).To(Equal(Provisioned))
14+
Expect(event.etype).To(Equal("provisioned"))
15+
})
16+
})
17+
18+
Describe("newProvisionedEventFromJSON", func() {
19+
It("Should detect invalid protocols", func() {
20+
_, err := newProvisionedEventFromJSON([]byte(`{"protocol":"x"}`))
21+
Expect(err).To(MatchError("invalid protocol 'x'"))
22+
})
23+
24+
It("Should parse valid events", func() {
25+
event, err := newProvisionedEventFromJSON([]byte(`{"protocol":"choria:lifecycle:provisioned:1", "component":"ginkgo"}`))
26+
Expect(err).ToNot(HaveOccurred())
27+
Expect(event.Component()).To(Equal("ginkgo"))
28+
Expect(event.dtype).To(Equal(Provisioned))
29+
Expect(event.etype).To(Equal("provisioned"))
30+
})
31+
})
32+
})

shutdown.go

+13-46
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,7 @@ import (
77

88
// ShutdownEvent is a choria:lifecycle:shutdown:1 event
99
type ShutdownEvent struct {
10-
Protocol string `json:"protocol"`
11-
Ident string `json:"identity"`
12-
Comp string `json:"component"`
13-
Timestamp int64 `json:"timestamp"`
10+
basicEvent
1411
}
1512

1613
func init() {
@@ -27,8 +24,12 @@ func init() {
2724

2825
func newShutdownEvent(opts ...Option) *ShutdownEvent {
2926
event := &ShutdownEvent{
30-
Protocol: "choria:lifecycle:shutdown:1",
31-
Timestamp: timeStamp(),
27+
basicEvent: basicEvent{
28+
Protocol: "choria:lifecycle:shutdown:1",
29+
Timestamp: timeStamp(),
30+
etype: "shutdown",
31+
dtype: Shutdown,
32+
},
3233
}
3334

3435
for _, o := range opts {
@@ -39,7 +40,12 @@ func newShutdownEvent(opts ...Option) *ShutdownEvent {
3940
}
4041

4142
func newShutdownEventFromJSON(j []byte) (*ShutdownEvent, error) {
42-
event := &ShutdownEvent{}
43+
event := &ShutdownEvent{
44+
basicEvent: basicEvent{
45+
etype: "shutdown",
46+
dtype: Shutdown,
47+
},
48+
}
4349
err := json.Unmarshal(j, event)
4450
if err != nil {
4551
return nil, err
@@ -51,42 +57,3 @@ func newShutdownEventFromJSON(j []byte) (*ShutdownEvent, error) {
5157

5258
return event, nil
5359
}
54-
55-
// Component is the component that produced the event
56-
func (e *ShutdownEvent) Component() string {
57-
return e.Comp
58-
}
59-
60-
// SetComponent sets the component for the event
61-
func (e *ShutdownEvent) SetComponent(c string) {
62-
e.Comp = c
63-
}
64-
65-
// SetIdentity sets the identity for the event
66-
func (e *ShutdownEvent) SetIdentity(i string) {
67-
e.Ident = i
68-
}
69-
70-
// Identity sets the identity for the event
71-
func (e *ShutdownEvent) Identity() string {
72-
return e.Ident
73-
}
74-
75-
// Target is where to publish the event to
76-
func (e *ShutdownEvent) Target() (string, error) {
77-
if e.Comp == "" {
78-
return "", fmt.Errorf("event is not complete, component has not been set")
79-
}
80-
81-
return fmt.Sprintf("choria.lifecycle.event.shutdown.%s", e.Comp), nil
82-
}
83-
84-
// String is text suitable to display on the console etc
85-
func (e *ShutdownEvent) String() string {
86-
return fmt.Sprintf("[shutdown] %s: %s", e.Ident, e.Component())
87-
}
88-
89-
// Type is the type of event
90-
func (e *ShutdownEvent) Type() Type {
91-
return Shutdown
92-
}

0 commit comments

Comments
 (0)