generated from kyma-project/template-repository
/
fsm.go
144 lines (124 loc) · 3.17 KB
/
fsm.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
package state
import (
"context"
"fmt"
"reflect"
"runtime"
"strings"
"github.com/kyma-project/serverless-manager/components/operator/api/v1alpha1"
"github.com/kyma-project/serverless-manager/components/operator/internal/chart"
"github.com/kyma-project/serverless-manager/components/operator/internal/warning"
"go.uber.org/zap"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/rest"
"k8s.io/client-go/tools/record"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
)
var (
defaultResult = ctrl.Result{}
secretCacheKey = types.NamespacedName{
Name: "serverless-manifest-cache",
Namespace: "kyma-system", // TODO: detect serverless-manager's namespace
}
)
type stateFn func(context.Context, *reconciler, *systemState) (stateFn, *ctrl.Result, error)
type cfg struct {
finalizer string
chartPath string
namespace string
managerPodUID string
}
type systemState struct {
instance v1alpha1.Serverless
statusSnapshot v1alpha1.ServerlessStatus
chartConfig *chart.Config
warningBuilder *warning.Builder
flagsBuilder chart.FlagsBuilder
}
func (s *systemState) saveStatusSnapshot() {
result := s.instance.Status.DeepCopy()
if result == nil {
result = &v1alpha1.ServerlessStatus{}
}
s.statusSnapshot = *result
}
func (s *systemState) setState(state v1alpha1.State) {
s.instance.Status.State = state
}
func (s *systemState) setServed(served v1alpha1.Served) {
s.instance.Status.Served = served
}
func chartConfig(ctx context.Context, r *reconciler, namespace string) *chart.Config {
return &chart.Config{
Ctx: ctx,
Log: r.log,
Cache: r.cache,
CacheKey: secretCacheKey,
ManagerUID: r.managerPodUID,
Cluster: chart.Cluster{
Client: r.client,
Config: r.config,
},
Release: chart.Release{
ChartPath: r.chartPath,
Namespace: namespace,
Name: "serverless",
},
}
}
type k8s struct {
client client.Client
config *rest.Config
record.EventRecorder
}
type reconciler struct {
fn stateFn
log *zap.SugaredLogger
cache chart.ManifestCache
result ctrl.Result
k8s
cfg
}
func (m *reconciler) stateFnName() string {
fullName := runtime.FuncForPC(reflect.ValueOf(m.fn).Pointer()).Name()
splitFullName := strings.Split(fullName, ".")
if len(splitFullName) < 3 {
return fullName
}
shortName := splitFullName[2]
return shortName
}
func (m *reconciler) Reconcile(ctx context.Context, v v1alpha1.Serverless) (ctrl.Result, error) {
state := systemState{
instance: v,
warningBuilder: warning.NewBuilder(),
flagsBuilder: chart.NewFlagsBuilder(),
chartConfig: chartConfig(ctx, m, v.Namespace),
}
state.saveStatusSnapshot()
var err error
var result *ctrl.Result
loop:
for m.fn != nil && err == nil {
select {
case <-ctx.Done():
err = ctx.Err()
break loop
default:
m.log.Info(fmt.Sprintf("switching state: %s", m.stateFnName()))
m.fn, result, err = m.fn(ctx, m, &state)
if updateErr := updateServerlessStatus(ctx, m, &state); updateErr != nil {
err = updateErr
}
}
}
if result == nil {
result = &defaultResult
}
m.log.
With("error", err).
With("result", result).
Info("reconciliation done")
return *result, err
}