-
Notifications
You must be signed in to change notification settings - Fork 59
/
testutils.go
399 lines (378 loc) · 12.5 KB
/
testutils.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
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
package testutils
import (
"fmt"
"testing"
"github.com/golang/mock/gomock"
configv1 "github.com/openshift/api/config/v1"
cloudingressv1alpha1 "github.com/openshift/cloud-ingress-operator/pkg/apis/cloudingress/v1alpha1"
awsclient "github.com/openshift/cloud-ingress-operator/pkg/awsclient/mock"
gcpproviderapi "github.com/openshift/cluster-api-provider-gcp/pkg/apis/gcpprovider/v1beta1"
machineapi "github.com/openshift/machine-api-operator/pkg/apis/machine/v1beta1"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes/scheme"
"k8s.io/utils/pointer"
awsprovider "sigs.k8s.io/cluster-api-provider-aws/pkg/apis/awsproviderconfig/v1beta1"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
)
const masterMachineLabel string = "machine.openshift.io/cluster-api-machine-role"
const DefaultRegionName string = "us-east-1"
const DefaultAzName string = "us-east-1a"
const DefaultAPIEndpoint string = "https://api.unit.test:6443"
const DefaultClusterDomain string = "unit.test"
// ClusterTokenId represents the part of identifiers which is varied by the installer, eg
// clustername-clustertokenid, as in load balancer names: foo-12345-us-east-1a
const ClusterTokenId string = "12345"
type Mocks struct {
FakeKubeClient client.Client
MockCtrl *gomock.Controller
MockAws *awsclient.MockClient
Scheme *runtime.Scheme
}
// legacyConfig maps a full ConfigMap install-config as a sprintf template.
// Refer to CreateLegacyClusterConfig for usage
const legacyConfig string = `apiVersion: v1
baseDomain: %s
compute:
- hyperthreading: Enabled
name: worker
platform:
aws:
rootVolume:
iops: 100
size: 32
type: gp2
type: m5.xlarge
zones:
- %s
- %s
- %s
replicas: %d
controlPlane:
hyperthreading: Enabled1234
name: master
platform:
aws:
rootVolume:
iops: 1000
size: 350
type: io1
type: m5.xlarge
zones:
- %s
- %s
- %s
replicas: %d
metadata:
creationTimestamp: null
name: %s
networking:
clusterNetwork:
- cidr: 10.128.0.0/14
hostPrefix: 23
machineCIDR: 10.0.0.0/16
networkType: OpenShiftSDN
serviceNetwork:
- 172.30.0.0/16
platform:
aws:
region: %s
pullSecret: ""
sshKey: |
ssh-rsa nothingreal
`
// NewMockTest sets up for a new mock test, pass in some localObjs to seed the fake Kubernetes environment
func NewTestMock(t *testing.T, localObjs []runtime.Object) *Mocks {
mockctrl := gomock.NewController(t)
s := scheme.Scheme
if err := configv1.AddToScheme(s); err != nil {
t.Fatalf("Couldn't add configv1 scheme: (%v)", err)
}
if err := machineapi.AddToScheme(s); err != nil {
t.Fatalf("Couldn't add machine scheme: (%v)", err)
}
if err := cloudingressv1alpha1.SchemeBuilder.AddToScheme(s); err != nil {
t.Fatalf("Couldn't add cloudingressv1alpha1 scheme: (%v)", err)
}
ret := &Mocks{
FakeKubeClient: fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(localObjs...).Build(),
MockCtrl: mockctrl,
MockAws: awsclient.NewMockClient(mockctrl),
Scheme: s,
}
return ret
}
// CreateAPIServerObject creates a configv1.APIServer object
func CreateAPIServerObject(clustername, clusterdomain string) *configv1.APIServer {
ret := &configv1.APIServer{
ObjectMeta: metav1.ObjectMeta{
Name: "cluster",
},
Spec: configv1.APIServerSpec{
ClientCA: configv1.ConfigMapNameReference{
Name: "",
},
ServingCerts: configv1.APIServerServingCerts{
NamedCertificates: []configv1.APIServerNamedServingCert{
{
Names: []string{fmt.Sprintf("api.%s", clusterdomain)},
ServingCertificate: configv1.SecretNameReference{
Name: fmt.Sprintf("%s-primary-certbundle-secret", clustername),
},
},
},
},
},
}
return ret
}
// CreateMachineObjectList makes a MachineList from the slice of names, and returns also a slice of Machine objects for convenience
func CreateMachineObjectList(name []string, clusterid, role, region, zone string) (*machineapi.MachineList, []machineapi.Machine) {
machines := make([]machineapi.Machine, 0)
for _, n := range name {
machines = append(machines, CreateMachineObj(n, clusterid, role, region, zone))
}
ret := &machineapi.MachineList{
Items: machines,
}
return ret, machines
}
// CreateMachineObj makes a single AWS-style machinev1beta1.Machine object
func CreateMachineObj(name, clusterid, role, region, zone string) machineapi.Machine {
ami := "ami-123456"
provider := &awsprovider.AWSMachineProviderConfig{
TypeMeta: metav1.TypeMeta{
APIVersion: "awsproviderconfig.openshift.io/v1beta1",
Kind: "AWSMachineProviderConfig",
},
InstanceType: "small",
BlockDevices: []awsprovider.BlockDeviceMappingSpec{},
AMI: awsprovider.AWSResourceReference{ID: &ami},
Tags: []awsprovider.TagSpecification{{Name: fmt.Sprintf("kubernetes.io/cluster/%s", clusterid), Value: "owned"}},
IAMInstanceProfile: &awsprovider.AWSResourceReference{ID: pointer.StringPtr(fmt.Sprintf("%s-%s-profile", clusterid, role))},
UserDataSecret: &corev1.LocalObjectReference{Name: "aws-cloud-credentials"},
Placement: awsprovider.Placement{Region: region, AvailabilityZone: zone},
LoadBalancers: []awsprovider.LoadBalancerReference{
{
// <clustername>-<id>-ext
Name: fmt.Sprintf("%s-%s-ext", clusterid, ClusterTokenId),
Type: awsprovider.NetworkLoadBalancerType,
},
{
// <clustername>-<id>-int
Name: fmt.Sprintf("%s-%s-int", clusterid, ClusterTokenId),
Type: awsprovider.NetworkLoadBalancerType,
},
},
SecurityGroups: []awsprovider.AWSResourceReference{{
Filters: []awsprovider.Filter{{
Name: "tag:Name",
Values: []string{fmt.Sprintf("%s-%s-sg", clusterid, role)},
}},
}},
}
provider.Subnet.Filters = []awsprovider.Filter{{
Name: "tag:Name",
Values: []string{
fmt.Sprintf("%s-private-%s", clusterid, zone),
fmt.Sprintf("%s-public-%s", clusterid, zone),
},
}}
labels := make(map[string]string)
labels[masterMachineLabel] = role
ret := machineapi.Machine{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: "openshift-machine-api",
Labels: labels,
},
Spec: machineapi.MachineSpec{
ProviderSpec: machineapi.ProviderSpec{
Value: &runtime.RawExtension{Object: provider},
},
// not exactly the same as AWS
ProviderID: pointer.StringPtr(fmt.Sprintf("aws:///%s/i-%s", zone, name)),
},
}
return ret
}
// CreateGCPMachineObj makes a single AWS-style machinev1beta1.Machine object
func CreateGCPMachineObj(name, clusterid, role, region, zone string) machineapi.Machine {
projectID := "o-1234567"
provider := &gcpproviderapi.GCPMachineProviderSpec{
TypeMeta: metav1.TypeMeta{
APIVersion: "gcpprovider.openshift.io/v1beta1",
Kind: "GCPMachineProviderSpec",
},
CanIPForward: false,
DeletionProtection: false,
Metadata: []*gcpproviderapi.GCPMetadata{},
NetworkInterfaces: []*gcpproviderapi.GCPNetworkInterface{},
MachineType: "custom-1-2345",
Disks: []*gcpproviderapi.GCPDisk{},
ServiceAccounts: []gcpproviderapi.GCPServiceAccount{},
Tags: []string{clusterid + "-master"},
UserDataSecret: &corev1.LocalObjectReference{Name: "gcp-cloud-credentials"},
Region: region,
Zone: zone,
ProjectID: projectID,
TargetPools: []string{clusterid + "-api"},
}
labels := make(map[string]string)
labels[masterMachineLabel] = role
ret := machineapi.Machine{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: "openshift-machine-api",
Labels: labels,
},
Spec: machineapi.MachineSpec{
ProviderSpec: machineapi.ProviderSpec{
Value: &runtime.RawExtension{Object: provider},
},
ProviderID: pointer.StringPtr(fmt.Sprintf("gce:///%s/%s/%s", projectID, zone, name)),
},
}
return ret
}
// CreateGCPMachineObjectList makes a MachineList from the slice of names, and returns also a slice of Machine objects for convenience
func CreateGCPMachineObjectList(name []string, clusterid, role, region, zone string) (*machineapi.MachineList, []machineapi.Machine) {
machines := make([]machineapi.Machine, 0)
for _, n := range name {
machines = append(machines, CreateGCPMachineObj(n, clusterid, role, region, zone))
}
ret := &machineapi.MachineList{
Items: machines,
}
return ret, machines
}
// CreateLegacyClusterConfig creates kube-config/configmaps/cluster-config-v1
// To test https://bugzilla.redhat.com/show_bug.cgi?id=1814332
func CreateLegacyClusterConfig(clusterdomain, infraName, region string, workerCount, masterCount int) *corev1.ConfigMap {
yamlConfig := fmt.Sprintf(legacyConfig, clusterdomain, DefaultAzName, DefaultAzName, DefaultAzName, workerCount,
DefaultAzName, DefaultAzName, DefaultAzName, masterCount, infraName, region)
fmt.Printf("Sprintf'd YAML Config = %s\n", yamlConfig)
return &corev1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Namespace: "kube-system",
Name: "cluster-config-v1",
},
Data: map[string]string{
"install-config": yamlConfig,
},
}
}
// CreatOldInfraObject creates an Infrastructure object that is missing information
// eg for https://bugzilla.redhat.com/show_bug.cgi?id=1814332
func CreatOldInfraObject(infraName, apiInternalURL, apiURL, region string) *configv1.Infrastructure {
return &configv1.Infrastructure{
ObjectMeta: metav1.ObjectMeta{
Name: "cluster",
Namespace: "",
},
Spec: configv1.InfrastructureSpec{
CloudConfig: configv1.ConfigMapFileReference{
Name: "",
},
},
Status: configv1.InfrastructureStatus{
InfrastructureName: infraName,
APIServerInternalURL: apiInternalURL,
APIServerURL: apiURL,
Platform: configv1.AWSPlatformType,
// Note: Absent PlatformStatus is intentional
},
}
}
// CreateInfraObject creates an configv1.Infrastructure object
func CreateInfraObject(infraName, apiInternalURL, apiURL, region string) *configv1.Infrastructure {
return &configv1.Infrastructure{
ObjectMeta: metav1.ObjectMeta{
Name: "cluster",
Namespace: "",
},
Spec: configv1.InfrastructureSpec{
CloudConfig: configv1.ConfigMapFileReference{
Name: "",
},
},
Status: configv1.InfrastructureStatus{
InfrastructureName: infraName,
APIServerInternalURL: apiInternalURL,
APIServerURL: apiURL,
Platform: configv1.AWSPlatformType,
PlatformStatus: &configv1.PlatformStatus{
Type: configv1.AWSPlatformType,
AWS: &configv1.AWSPlatformStatus{
Region: region,
},
},
},
}
}
// CreateGCPInfraObject creates an configv1.Infrastructure object
func CreateGCPInfraObject(infraName, apiInternalURL, apiURL, region string) *configv1.Infrastructure {
return &configv1.Infrastructure{
ObjectMeta: metav1.ObjectMeta{
Name: "cluster",
Namespace: "",
},
Spec: configv1.InfrastructureSpec{
CloudConfig: configv1.ConfigMapFileReference{
Name: "",
},
},
Status: configv1.InfrastructureStatus{
InfrastructureName: infraName,
APIServerInternalURL: apiInternalURL,
APIServerURL: apiURL,
Platform: configv1.GCPPlatformType,
PlatformStatus: &configv1.PlatformStatus{
Type: configv1.GCPPlatformType,
GCP: &configv1.GCPPlatformStatus{
Region: region,
},
},
},
}
}
// CreateAPISchemeObject makes an APISCheme object
func CreateAPISchemeObject(dnsname string, enabled bool, cidrs []string) *cloudingressv1alpha1.APIScheme {
return &cloudingressv1alpha1.APIScheme{
ObjectMeta: metav1.ObjectMeta{
Name: "rh-api",
Namespace: "openshift-cloud-ingress-operator",
},
Spec: cloudingressv1alpha1.APISchemeSpec{
ManagementAPIServerIngress: cloudingressv1alpha1.ManagementAPIServerIngress{
Enabled: enabled,
DNSName: dnsname,
AllowedCIDRBlocks: cidrs,
},
},
}
}
// ValidateMachineLB returns length, names and types (slices) and any error if one
// The purpose is to have an easy way to condense 12+ lines of code
func ValidateMachineLB(m *machineapi.Machine) (int, []string, []awsprovider.AWSLoadBalancerType, error) {
names := make([]string, 0)
lbTypes := make([]awsprovider.AWSLoadBalancerType, 0)
l := 0
codec, err := awsprovider.NewCodec()
if err != nil {
return l, names, lbTypes, err
}
awsconfig := &awsprovider.AWSMachineProviderConfig{}
err = codec.DecodeProviderSpec(&m.Spec.ProviderSpec, awsconfig)
if err != nil {
return l, names, lbTypes, err
}
for _, lb := range awsconfig.LoadBalancers {
names = append(names, lb.Name)
lbTypes = append(lbTypes, lb.Type)
l++
}
return l, names, lbTypes, nil
}