-
Notifications
You must be signed in to change notification settings - Fork 0
/
resource.go
148 lines (121 loc) · 3.75 KB
/
resource.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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
package viaduct
import (
"crypto/sha1"
"encoding/hex"
"encoding/json"
"fmt"
"reflect"
"strings"
)
// ResourceKind is the kind of resource, such as "File" or "Package".
type ResourceKind string
// Resource holds details about a particular resource during a Viaduct run.
type Resource struct {
// ResourceID is the resources generated ID.
ResourceID
// ResourceKind is what the resource kind is, such as "File" or "Package".
ResourceKind
// Status denotes the current status of the resource.
Status
// Attributes are the resource type attributes.
Attributes ResourceAttributes
// DependsOn is a list of resource dependencies.
DependsOn []ResourceID `json:"DependsOn,omitempty"`
// GlobalLock will mean the resource will not run at the same time
// as other resources that have this set to true.
GlobalLock bool
// Error contains any errors raised during a run.
Error `json:"Error"`
}
type Error struct {
Err error `json:"-"`
Message string `json:"Message"`
}
// ResourceParams are a set of options that each resource can set
// depending on their logic
type ResourceParams struct {
// GlobalLock can be set to ensure that the resource uses a global
// lock during operations
GlobalLock bool
}
// NewResourceParams creates a new ResourceParams.
func NewResourceParams() *ResourceParams {
return &ResourceParams{}
}
// NewResourceParamsWithLock creates a new ResourceParams, but with
// a global lock applied.
func NewResourceParamsWithLock() *ResourceParams {
return &ResourceParams{GlobalLock: true}
}
// ResourceAttributes implement different resource types, such as File or
// Directory. As long as this interface is implemented, then custom resources
// can be directly integrated.
type ResourceAttributes interface {
// OperationName is a simple identifier for the operation type, such as
// Create, Delete, Update or Run.
OperationName() string
// Params are a set of parameters that determine how a resource should
// interact with Viaduct.
Params() *ResourceParams
// PreflightChecks are used to check that the resource parameters have been
// correctly set, and to ensure that default parameters are assigned.
PreflightChecks(log *Logger) error
// Run performs the resource operation.
Run(log *Logger) error
}
// ResourceID is an id of a resource.
type ResourceID string
func newResource(deps []*Resource) (*Resource, error) {
var dependsOn []ResourceID
for _, d := range deps {
if d.ResourceID == "" {
return &Resource{}, fmt.Errorf("dependency is not a valid resource: %s", attrJSON(d))
}
dependsOn = append(dependsOn, d.ResourceID)
}
return &Resource{
DependsOn: dependsOn,
Status: Pending,
}, nil
}
func (r *Resource) init(a ResourceAttributes) error {
if err := r.setKind(a); err != nil {
return err
}
return nil
}
func (r *Resource) setKind(a ResourceAttributes) error {
t := reflect.TypeOf(a)
if t.Kind() != reflect.Pointer {
return fmt.Errorf("cannot determine resource type")
}
k := t.Elem().Name()
r.ResourceKind = ResourceKind(k)
return nil
}
func (r *Resource) setID() error {
if r.ResourceKind == "" {
return fmt.Errorf("resource kind has not been set")
}
j, err := json.Marshal(r)
if err != nil {
return err
}
h := sha1.New()
h.Write(j)
sha := hex.EncodeToString(h.Sum(nil))
idstr := strings.Join([]string{"id", sha[0:8]}, "-")
r.ResourceID = ResourceID(strings.Join([]string{string(r.ResourceKind), idstr}, "_"))
return nil
}
func (r *Resource) preflight() error {
log := NewLogger(string(r.ResourceKind), "Preflight")
return r.Attributes.PreflightChecks(log)
}
func (r *Resource) run() error {
log := NewLogger(string(r.ResourceKind), r.Attributes.OperationName())
return r.Attributes.Run(log)
}
func (r *Resource) Failed() bool {
return r.Status == Failed || r.Status == DependencyFailed
}