This repository has been archived by the owner on Jul 6, 2022. It is now read-only.
/
provisioner.go
118 lines (105 loc) · 2.88 KB
/
provisioner.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
package service
import (
"context"
"fmt"
)
// ProvisioningStepFunction is the signature for functions that implement a
// provisioning step
type ProvisioningStepFunction func(
ctx context.Context,
instance Instance,
) (InstanceDetails, error)
// ProvisioningStep is an interface to be implemented by types that represent
// a single step in a chain of steps that defines a provisioning process
type ProvisioningStep interface {
GetName() string
Execute(
ctx context.Context,
instance Instance,
) (InstanceDetails, error)
}
type provisioningStep struct {
name string
fn ProvisioningStepFunction
}
// Provisioner is an interface to be implemented by types that model a declared
// chain of tasks used to asynchronously provision a service
type Provisioner interface {
GetFirstStepName() (string, bool)
GetStep(name string) (ProvisioningStep, bool)
GetNextStepName(name string) (string, bool)
}
type provisioner struct {
firstStepName string
steps map[string]ProvisioningStep
nextSteps map[string]string
}
// NewProvisioningStep returns a new ProvisioningStep
func NewProvisioningStep(
name string,
fn ProvisioningStepFunction,
) ProvisioningStep {
return &provisioningStep{
name: name,
fn: fn,
}
}
// GetName returns a provisioning step's name
func (p *provisioningStep) GetName() string {
return p.name
}
// Execute executes a step
func (p *provisioningStep) Execute(
ctx context.Context,
instance Instance,
) (InstanceDetails, error) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
return p.fn(
ctx,
instance,
)
}
// NewProvisioner returns a new provisioner
func NewProvisioner(steps ...ProvisioningStep) (Provisioner, error) {
p := &provisioner{
steps: make(map[string]ProvisioningStep),
nextSteps: make(map[string]string),
}
if len(steps) > 0 {
p.firstStepName = steps[0].GetName()
var lastStep ProvisioningStep
for _, step := range steps {
_, ok := p.steps[step.GetName()]
if ok {
// This means a duplicate step name has been detected. This is a serious
// problem.
return nil, fmt.Errorf(
`duplicate step name "%s" detected`,
step.GetName(),
)
}
p.steps[step.GetName()] = step
if lastStep != nil {
p.nextSteps[lastStep.GetName()] = step.GetName()
}
lastStep = step
}
}
return p, nil
}
// GetFirstStepName retrieves the name of the first step in the chain
func (p *provisioner) GetFirstStepName() (string, bool) {
return p.firstStepName, (p.firstStepName != "")
}
// GetStep retrieves a step by name
func (p *provisioner) GetStep(name string) (ProvisioningStep, bool) {
step, ok := p.steps[name]
return step, ok
}
// GetNextStepName, given the name of one step, returns the name of the next
// step and a boolean indicating whether a next step actually exists
func (p *provisioner) GetNextStepName(name string) (string, bool) {
nextStepName, ok := p.nextSteps[name]
return nextStepName, ok
}