/
util.go
288 lines (242 loc) · 7.35 KB
/
util.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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
package util
import (
"fmt"
"io"
"os"
"path/filepath"
"runtime"
"strings"
"time"
crcConfig "github.com/crc-org/crc/v2/pkg/crc/config"
"github.com/crc-org/crc/v2/pkg/crc/constants"
"github.com/crc-org/crc/v2/pkg/crc/machine"
"github.com/crc-org/crc/v2/pkg/crc/preset"
"github.com/crc-org/crc/v2/pkg/crc/ssh"
"github.com/crc-org/crc/v2/pkg/download"
)
var (
CRCHome string
)
func CopyFilesToTestDir() error {
cwd, err := os.Getwd()
if err != nil {
fmt.Printf("Error retrieving current dir: %s", err)
return err
}
l := strings.Split(cwd, string(filepath.Separator))
dataDirPieces := l[:len(l)-3]
dataDirPieces = append(dataDirPieces, "testdata")
var volume string
if runtime.GOOS == "windows" {
volume = filepath.VolumeName(cwd)
dataDirPieces = dataDirPieces[1:] // drop volume from list of dirs
}
dataDir := filepath.Join(dataDirPieces...)
dataDir = fmt.Sprintf("%s%c%s", volume, filepath.Separator, dataDir) // prepend volume back
return CopyResourcesFromPath(dataDir)
}
func CopyResourcesFromPath(resourcesPath string) error {
files, err := os.ReadDir(resourcesPath)
if err != nil {
fmt.Printf("Error occurred loading data files: %s", err)
return err
}
destLoc, _ := os.Getwd()
for _, file := range files {
sFileName := filepath.Join(resourcesPath, file.Name())
fmt.Printf("Copying %s to %s\n", sFileName, destLoc)
sFile, err := os.Open(sFileName)
if err != nil {
fmt.Printf("Error occurred opening file: %s", err)
return err
}
defer sFile.Close()
dFileName := file.Name()
dFile, err := os.Create(dFileName)
if err != nil {
fmt.Printf("Error occurred creating file: %s", err)
return err
}
defer dFile.Close()
_, err = io.Copy(dFile, sFile) // ignore num of bytes
if err != nil {
fmt.Printf("Error occurred copying file: %s", err)
return err
}
err = dFile.Sync()
if err != nil {
fmt.Printf("Error occurred syncing file: %s", err)
return err
}
err = dFile.Close()
if err != nil {
fmt.Printf("Error closing file: %s", err)
return err
}
}
return nil
}
// Download bundle for testing
func DownloadBundle(bundleLocation string, bundleDestination string, bundleName string) (string, error) {
if bundleLocation[:4] != "http" {
// copy the file locall
if bundleDestination == "." {
bundleDestination, _ = os.Getwd()
}
fmt.Printf("Copying bundle from %s to %s.\n", bundleLocation, bundleDestination)
bundleDestination = filepath.Join(bundleDestination, bundleName)
source, err := os.Open(bundleLocation)
if err != nil {
return "", err
}
defer source.Close()
destination, err := os.Create(bundleDestination)
if err != nil {
return "", err
}
defer destination.Close()
_, err = io.Copy(destination, source)
if err != nil {
return "", err
}
err = destination.Sync()
return bundleDestination, err
}
filename, err := download.Download(bundleLocation, bundleDestination, 0644, nil)
fmt.Printf("Downloading bundle from %s to %s.\n", bundleLocation, bundleDestination)
if err != nil {
return "", err
}
return filename, nil
}
func RemoveCRCHome() error {
keepFile := filepath.Join(CRCHome, ".keep")
_, err := os.Stat(keepFile)
if err != nil { // cannot get keepFile's status
err = os.RemoveAll(CRCHome)
if err != nil {
fmt.Printf("Problem deleting CRC home folder %s.\n", CRCHome)
return err
}
fmt.Printf("Deleted CRC home folder %s.\n", CRCHome)
return nil
}
// keepFile exists
return fmt.Errorf("folder %s not removed as per request: %s present", CRCHome, keepFile)
}
func RemoveCRCConfig() error {
configFile := filepath.Join(CRCHome, "crc.json")
err := os.RemoveAll(configFile)
if err != nil {
fmt.Printf("Problem deleting CRC config file %s.\n", configFile)
return err
}
return nil
}
// MatchWithRetry will execute match function with expression as arg
// for #iterations with a timeout
func MatchWithRetry(expression string, match func(string) error, iterations, timeoutInSeconds int) error {
return MatchRepetitionsWithRetry(expression, match, 1, iterations, timeoutInSeconds)
}
// MatchRepetitionsWithRetry will execute match function with expression as arg
// for #iterations with a timeout, expression should be matched # matchRepetitions in a row
func MatchRepetitionsWithRetry(expression string, match func(string) error, matchRepetitions int, iterations, timeoutInSeconds int) error {
timeout := time.After(time.Duration(timeoutInSeconds) * time.Second)
tick := time.NewTicker(time.Duration(timeoutInSeconds/iterations) * time.Second)
matchRepetition := 0
for {
select {
case <-timeout:
tick.Stop()
return fmt.Errorf("not found: %s. Timeout", expression)
case <-tick.C:
if err := match(expression); err == nil {
matchRepetition++
if matchRepetition == matchRepetitions {
tick.Stop()
return nil
}
} else {
// repetions should be matched in a row, otherwise reset the counter
matchRepetition = 0
}
}
}
}
// GetBundlePath returns a path to the cached bundle, depending on the preset
func GetBundlePath(preset preset.Preset) string {
bundle := constants.GetDefaultBundle(preset)
return filepath.Join(CRCHome, "cache", bundle)
}
// WriteTempFile returns full path of the temp file it created, and an error
func WriteTempFile(content string, name string) (string, error) {
tmpFile, err := os.CreateTemp("", name)
if err != nil {
return "", err
}
defer tmpFile.Close()
_, err = tmpFile.WriteString(content)
return tmpFile.Name(), err
}
// Send command to CRC VM via SSH
func SendCommandToVM(cmd string) (string, error) {
client := machine.NewClient(constants.DefaultName, false,
crcConfig.New(crcConfig.NewEmptyInMemoryStorage(), crcConfig.NewEmptyInMemorySecretStorage()),
)
connectionDetails, err := client.ConnectionDetails()
if err != nil {
return "", err
}
ssh, err := ssh.NewClient(connectionDetails.SSHUsername, connectionDetails.IP, connectionDetails.SSHPort, connectionDetails.SSHKeys...)
if err != nil {
return "", err
}
out, _, err := ssh.Run(cmd)
if err != nil {
return "", err
}
return string(out), nil
}
func AddOCToPath() error {
path := os.ExpandEnv("${HOME}/.crc/bin/oc:$PATH")
if runtime.GOOS == "windows" {
userHomeDir, err := os.UserHomeDir()
if err != nil {
return err
}
unexpandedPath := filepath.Join(userHomeDir, ".crc/bin/oc;${PATH}")
path = os.ExpandEnv(unexpandedPath)
}
err := os.Setenv("PATH", path)
if err != nil {
return err
}
return nil
}
// LoginToOcCluster logs into the cluster as admin with oc command
// 'options' should have a form of a string slice like: [--option1 --option2 --option3] (string slice)
func LoginToOcCluster(options []string) error {
credentialsCommand := "crc console --credentials" //#nosec G101
err := ExecuteCommand(credentialsCommand)
if err != nil {
return err
}
out := GetLastCommandOutput("stdout")
ocLoginAsAdminCommand := strings.Split(out, "'")[3]
for _, option := range options {
ocLoginAsAdminCommand = ocLoginAsAdminCommand + " " + option
}
return ExecuteCommand(ocLoginAsAdminCommand)
}
// LoginToOcClusterSucceedsOrFails is a wrapper for LoginToOcCluster
func LoginToOcClusterSucceedsOrFails(expected string) error {
if expected == "fails" {
err := LoginToOcCluster([]string{})
if err != nil {
return nil
}
_ = LogMessage("error:", "Login succeeded but was not supposed to")
return fmt.Errorf("Login succeeded but was not supposed to")
}
return LoginToOcCluster([]string{})
}