/
utils.go
204 lines (174 loc) · 5.94 KB
/
utils.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
// Copyright (c) 2018 SAP SE or an SAP affiliate company. All rights reserved. This file is licensed under the Apache Software License, v. 2 except as noted otherwise in the LICENSE file
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package framework
import (
"fmt"
"io/ioutil"
"os"
"reflect"
"regexp"
gardencorev1beta1 "github.com/gardener/gardener/pkg/apis/core/v1beta1"
"github.com/gardener/gardener/pkg/client/kubernetes"
"github.com/hashicorp/go-multierror"
"github.com/onsi/ginkgo"
"github.com/pkg/errors"
apimachineryRuntime "k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/serializer"
"sigs.k8s.io/yaml"
)
// Must errors with `GinkgoT().Fatal` if the error is non-nil.
func Must(err error) {
if err != nil {
ginkgo.GinkgoT().Fatal(err)
}
}
func checkPtr(v reflect.Value) error {
if v.Type().Kind() != reflect.Ptr {
return fmt.Errorf("value has to be a pointer-type but got %T", v.Interface())
}
return nil
}
func checkAssignable(src, dst reflect.Value) error {
if !src.Type().AssignableTo(dst.Type().Elem()) {
return fmt.Errorf("src of type %T cannot be assigned to dst of type %T", src.Interface(), dst.Interface())
}
return nil
}
func dereference(v interface{}) interface{} {
dstValue := reflect.ValueOf(v)
Must(checkPtr(dstValue))
return dstValue.Elem().Interface()
}
// RevertableSet sets the element of dst to src and returns a function that can revert back to the original values.
func RevertableSet(dst, src interface{}) (revert func()) {
tmp := dereference(dst)
Set(dst, src)
return func() { Set(dst, tmp) }
}
// Set sets the pointer dst to the value of src.
//
// dst has to be a pointer, src has to be assignable to the element type of dst.
func Set(dst, src interface{}) {
dstValue := reflect.ValueOf(dst)
Must(checkPtr(dstValue))
srcValue := reflect.ValueOf(src)
Must(checkAssignable(srcValue, dstValue))
dstValue.Elem().Set(srcValue)
}
//ComputeTechnicalID computes the technical ID of a shoot
func ComputeTechnicalID(projectName string, shoot *gardencorev1beta1.Shoot) string {
// Use the stored technical ID in the Shoot's status field if it's there.
// For backwards compatibility we keep the pattern as it was before we had to change it
// (double hyphens).
if len(shoot.Status.TechnicalID) > 0 {
return shoot.Status.TechnicalID
}
// New clusters shall be created with the new technical id (double hyphens).
return fmt.Sprintf("shoot--%s--%s", projectName, shoot.Name)
}
// Exists checks if a path exists
func Exists(path string) (bool, error) {
if _, err := os.Stat(path); err != nil {
if os.IsNotExist(err) {
return false, nil
}
return false, err
}
return true, nil
}
// StringSet checks if a string is set
func StringSet(s string) bool {
return len(s) != 0
}
// FileExists Checks if a file path exists and fail otherwise
func FileExists(kc string) bool {
ok, err := Exists(kc)
if err != nil {
ginkgo.Fail(err.Error())
}
return ok
}
// ReadObject loads the contents of file and decodes it as an object.
func ReadObject(file string, into apimachineryRuntime.Object) error {
data, err := ioutil.ReadFile(file)
if err != nil {
return err
}
_, _, err = serializer.NewCodecFactory(kubernetes.GardenScheme).UniversalDecoder().Decode(data, nil, into)
return err
}
// ParseFileAsProviderConfig parses a file as a ProviderConfig
func ParseFileAsProviderConfig(filepath string) (*apimachineryRuntime.RawExtension, error) {
data, err := ioutil.ReadFile(filepath)
if err != nil {
return nil, err
}
// apiServer needs JSON for the Raw data
jsonData, err := yaml.YAMLToJSON(data)
if err != nil {
return nil, fmt.Errorf("unable to decode ProviderConfig: %v", err)
}
return &apimachineryRuntime.RawExtension{Raw: jsonData}, nil
}
// ParseFileAsWorkers parses a file as a Worker configuration
func ParseFileAsWorkers(filepath string) ([]gardencorev1beta1.Worker, error) {
data, err := ioutil.ReadFile(filepath)
if err != nil {
return nil, err
}
workers := []gardencorev1beta1.Worker{}
if err := yaml.Unmarshal(data, &workers); err != nil {
return nil, fmt.Errorf("unable to decode workers: %v", err)
}
return workers, nil
}
// TextValidation is a map of regular expression to description
// that is used to validate texts based on allowed or denied regexps.
type TextValidation map[string]string
// ValidateAsAllowlist validates that all allowed regular expressions
// are in the given text.
func (v *TextValidation) ValidateAsAllowlist(text []byte) error {
return v.validate(text, func(matches [][]byte) error {
if len(matches) == 0 {
return errors.New("allowed RegExp not found")
}
return nil
})
}
// ValidateAsDenylist validates that no denied regular expressions
// are in the given text.
func (v *TextValidation) ValidateAsDenylist(text []byte) error {
return v.validate(text, func(matches [][]byte) error {
if len(matches) != 0 {
return errors.New("denied RegExp found")
}
return nil
})
}
// validate compiles all given regular expressions strings and finds all matches in the given text.
func (v *TextValidation) validate(text []byte, validationFunc func([][]byte) error) error {
var allErrs error
for reString, description := range *v {
re, err := regexp.Compile(reString)
if err != nil {
allErrs = multierror.Append(allErrs, err)
continue
}
matches := re.FindAll(text, -1)
if err := validationFunc(matches); err != nil {
allErrs = multierror.Append(allErrs, errors.Wrapf(err, "RegExp %s validation failed: %s", reString, description))
}
}
return allErrs
}