-
Notifications
You must be signed in to change notification settings - Fork 243
/
events.go
125 lines (106 loc) · 4.37 KB
/
events.go
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package validation
import (
"fmt"
"github.com/hashicorp/go-multierror"
"strings"
"github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2"
)
const (
preStart = "preStart"
postStart = "postStart"
preStop = "preStop"
postStop = "postStop"
)
// ValidateEvents validates all the devfile events
func ValidateEvents(events v1alpha2.Events, commands []v1alpha2.Command) (err error) {
commandMap := getCommandsMap(commands)
switch {
case len(events.PreStart) > 0:
if preStartErr := isEventValid(events.PreStart, preStart, commandMap); preStartErr != nil {
err = multierror.Append(err, preStartErr)
}
fallthrough
case len(events.PostStart) > 0:
if postStartErr := isEventValid(events.PostStart, postStart, commandMap); postStartErr != nil {
err = multierror.Append(err, postStartErr)
}
fallthrough
case len(events.PreStop) > 0:
if preStopErr := isEventValid(events.PreStop, preStop, commandMap); preStopErr != nil {
err = multierror.Append(err, preStopErr)
}
fallthrough
case len(events.PostStop) > 0:
if postStopErr := isEventValid(events.PostStop, postStop, commandMap); postStopErr != nil {
err = multierror.Append(err, postStopErr)
}
}
return err
}
// isEventValid checks if events belonging to a specific event type are valid ie;
// 1. event should map to a valid devfile command
// 2. preStart and postStop events should either map to an apply command or a composite command with apply commands
// 3. postStart and preStop events should either map to an exec command or a composite command with exec commands
func isEventValid(eventNames []string, eventType string, commandMap map[string]v1alpha2.Command) error {
var invalidCommand, invalidApplyEvents, invalidExecEvents []string
for _, eventName := range eventNames {
command, ok := commandMap[strings.ToLower(eventName)]
if !ok { // check if event is in the list of devfile commands
invalidCommand = append(invalidCommand, eventName)
continue
}
switch eventType {
case preStart, postStop:
// check if the event is either an apply command or a composite of apply commands
if command.Apply == nil && command.Composite == nil {
invalidApplyEvents = append(invalidApplyEvents, eventName)
} else if command.Composite != nil {
invalidApplyEvents = append(invalidApplyEvents, validateCompositeEvents(*command.Composite, eventName, eventType, commandMap)...)
}
case postStart, preStop:
// check if the event is either an exec command or a composite of exec commands
if command.Exec == nil && command.Composite == nil {
invalidExecEvents = append(invalidExecEvents, eventName)
} else if command.Composite != nil {
invalidExecEvents = append(invalidExecEvents, validateCompositeEvents(*command.Composite, eventName, eventType, commandMap)...)
}
}
}
var err error
var eventErrorsList []string
if len(invalidCommand) > 0 {
eventErrorsList = append(eventErrorsList, fmt.Sprintf("%s does not map to a valid devfile command", strings.Join(invalidCommand, ", ")))
}
if len(invalidApplyEvents) > 0 {
eventErrorsList = append(eventErrorsList, fmt.Sprintf("%s should either map to an apply command or a composite command with apply commands", strings.Join(invalidApplyEvents, ", ")))
}
if len(invalidExecEvents) > 0 {
eventErrorsList = append(eventErrorsList, fmt.Sprintf("%s should either map to an exec command or a composite command with exec commands", strings.Join(invalidExecEvents, ", ")))
}
if len(eventErrorsList) != 0 {
eventErrors := fmt.Sprintf("\n%s", strings.Join(eventErrorsList, "\n"))
err = &InvalidEventError{eventType: eventType, errorMsg: eventErrors}
}
return err
}
// validateCompositeEvents checks if a composite subcommands are
// 1. apply commands for preStart and postStop
// 2. exec commands for postStart and preStop
func validateCompositeEvents(composite v1alpha2.CompositeCommand, eventName, eventType string, commandMap map[string]v1alpha2.Command) []string {
var invalidEvents []string
switch eventType {
case preStart, postStop:
for _, subCommand := range composite.Commands {
if command, ok := commandMap[subCommand]; ok && command.Apply == nil {
invalidEvents = append(invalidEvents, eventName)
}
}
case postStart, preStop:
for _, subCommand := range composite.Commands {
if command, ok := commandMap[subCommand]; ok && command.Exec == nil {
invalidEvents = append(invalidEvents, eventName)
}
}
}
return invalidEvents
}