/
preflight.go
188 lines (161 loc) · 4.88 KB
/
preflight.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
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
package preflight
import (
"fmt"
crcConfig "github.com/crc-org/crc/v2/pkg/crc/config"
"github.com/crc-org/crc/v2/pkg/crc/errors"
"github.com/crc-org/crc/v2/pkg/crc/logging"
)
type Flags uint32
const (
// Indicates a PreflightCheck should only be run as part of "crc setup"
SetupOnly Flags = 1 << iota
NoFix
CleanUpOnly
StartUpOnly
)
type CheckFunc func() error
type FixFunc func() error
type CleanUpFunc func() error
type Check struct {
configKeySuffix string
checkDescription string
check CheckFunc
fixDescription string
fix FixFunc
flags Flags
cleanupDescription string
cleanup CleanUpFunc
labels labels
}
func (check *Check) getSkipConfigName() string {
if check.configKeySuffix == "" {
return ""
}
return "skip-" + check.configKeySuffix
}
func (check *Check) shouldSkip(config crcConfig.Storage) bool {
if check.configKeySuffix == "" {
return false
}
return config.Get(check.getSkipConfigName()).AsBool()
}
func (check *Check) doCheck(config crcConfig.Storage) error {
if check.checkDescription == "" {
panic(fmt.Sprintf("Should not happen, empty description for check '%s'", check.configKeySuffix))
}
logging.Infof("%s", check.checkDescription)
if check.shouldSkip(config) {
logging.Warn("Skipping above check...")
return nil
}
err := check.check()
if err != nil {
logging.Debug(err.Error())
}
return err
}
func (check *Check) doFix() error {
if check.fixDescription == "" {
panic(fmt.Sprintf("Should not happen, empty description for fix '%s'", check.configKeySuffix))
}
if check.flags&NoFix == NoFix {
return fmt.Errorf(check.fixDescription)
}
logging.Infof("%s", check.fixDescription)
return check.fix()
}
func (check *Check) doCleanUp() error {
if check.cleanupDescription == "" {
panic(fmt.Sprintf("Should not happen, empty description for cleanup '%s'", check.configKeySuffix))
}
logging.Infof("%s", check.cleanupDescription)
return check.cleanup()
}
func doPreflightChecks(config crcConfig.Storage, checks []Check) error {
for _, check := range checks {
if check.flags&SetupOnly == SetupOnly || check.flags&CleanUpOnly == CleanUpOnly {
continue
}
if err := check.doCheck(config); err != nil {
return err
}
}
return nil
}
func doFixPreflightChecks(config crcConfig.Storage, checks []Check, checkOnly bool) error {
for _, check := range checks {
if check.flags&CleanUpOnly == CleanUpOnly || check.flags&StartUpOnly == StartUpOnly {
continue
}
err := check.doCheck(config)
if err == nil {
continue
} else if checkOnly {
return err
}
if err = check.doFix(); err != nil {
return err
}
}
return nil
}
func doCleanUpPreflightChecks(checks []Check) error {
var mErr errors.MultiError
// Do the cleanup in reverse order to avoid any dependency during cleanup
for i := len(checks) - 1; i >= 0; i-- {
check := checks[i]
if check.cleanup == nil {
continue
}
err := check.doCleanUp()
if err != nil {
// If an error occurs in a cleanup function
// we log/collect it and move to the next
logging.Debug(err)
mErr.Collect(err)
}
}
if len(mErr.Errors) == 0 {
return nil
}
return mErr
}
func doRegisterSettings(cfg crcConfig.Schema, checks []Check) {
for _, check := range checks {
if check.configKeySuffix != "" {
cfg.AddSetting(check.getSkipConfigName(), false, crcConfig.ValidateBool, crcConfig.SuccessfullyApplied,
"Skip preflight check (true/false, default: false)")
}
}
}
func getPreflightChecksHelper(config crcConfig.Storage) []Check {
experimentalFeatures := config.Get(crcConfig.ExperimentalFeatures).AsBool()
mode := crcConfig.GetNetworkMode(config)
bundlePath := config.Get(crcConfig.Bundle).AsString()
preset := crcConfig.GetPreset(config)
enableBundleQuayFallback := config.Get(crcConfig.EnableBundleQuayFallback).AsBool()
logging.Infof("Using bundle path %s", bundlePath)
return getPreflightChecks(experimentalFeatures, mode, bundlePath, preset, enableBundleQuayFallback)
}
// StartPreflightChecks performs the preflight checks before starting the cluster
func StartPreflightChecks(config crcConfig.Storage) error {
if err := doPreflightChecks(config, getPreflightChecksHelper(config)); err != nil {
return &errors.PreflightError{Err: err}
}
return nil
}
// SetupHost performs the prerequisite checks and setups the host to run the cluster
func SetupHost(config crcConfig.Storage, checkOnly bool) error {
return doFixPreflightChecks(config, getPreflightChecksHelper(config), checkOnly)
}
func RegisterSettings(config crcConfig.Schema) {
doRegisterSettings(config, getAllPreflightChecks())
}
func CleanUpHost() error {
// A user can use setup with experiment flag
// and not use cleanup with same flag, to avoid
// any extra step/confusion we are just adding the checks
// which are behind the experiment flag. This way cleanup
// perform action in a sane way.
return doCleanUpPreflightChecks(getAllPreflightChecks())
}