@@ -6,28 +6,34 @@ import (
6
6
"errors"
7
7
"fmt"
8
8
"io/ioutil"
9
+ "strings"
9
10
"testing"
10
11
"time"
11
12
12
- "github.com/ghodss/yaml"
13
13
"github.com/sirupsen/logrus"
14
14
"github.com/stretchr/testify/require"
15
15
"golang.org/x/time/rate"
16
+ "gopkg.in/yaml.v2"
16
17
appsv1 "k8s.io/api/apps/v1"
17
18
corev1 "k8s.io/api/core/v1"
18
19
rbacv1 "k8s.io/api/rbac/v1"
19
20
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
20
21
apiextensionsfake "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset/fake"
22
+ "k8s.io/apimachinery/pkg/api/meta"
21
23
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24
+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
22
25
"k8s.io/apimachinery/pkg/runtime"
26
+ "k8s.io/apimachinery/pkg/runtime/schema"
23
27
"k8s.io/apimachinery/pkg/types"
24
28
utilclock "k8s.io/apimachinery/pkg/util/clock"
29
+ utilyaml "k8s.io/apimachinery/pkg/util/yaml"
25
30
fakedynamic "k8s.io/client-go/dynamic/fake"
26
31
"k8s.io/client-go/informers"
27
32
k8sfake "k8s.io/client-go/kubernetes/fake"
28
33
"k8s.io/client-go/rest"
29
34
"k8s.io/client-go/tools/cache"
30
35
"k8s.io/client-go/util/workqueue"
36
+ apiregistrationv1 "k8s.io/kube-aggregator/pkg/apis/apiregistration/v1"
31
37
apiregistrationfake "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/fake"
32
38
33
39
"github.com/operator-framework/operator-lifecycle-manager/pkg/api/apis/operators/v1alpha1"
@@ -342,6 +348,7 @@ func TestExecutePlan(t *testing.T) {
342
348
tests := []struct {
343
349
testName string
344
350
in * v1alpha1.InstallPlan
351
+ extObjs []runtime.Object
345
352
want []runtime.Object
346
353
err error
347
354
}{
@@ -363,7 +370,7 @@ func TestExecutePlan(t *testing.T) {
363
370
Version : "v1" ,
364
371
Kind : "Service" ,
365
372
Name : "service" ,
366
- Manifest : toManifest (service ("service" , namespace )),
373
+ Manifest : toManifest (t , service ("service" , namespace )),
367
374
},
368
375
Status : v1alpha1 .StepStatusUnknown ,
369
376
},
@@ -375,7 +382,7 @@ func TestExecutePlan(t *testing.T) {
375
382
Version : "v1alpha1" ,
376
383
Kind : "ClusterServiceVersion" ,
377
384
Name : "csv" ,
378
- Manifest : toManifest (csv ("csv" , namespace , nil , nil )),
385
+ Manifest : toManifest (t , csv ("csv" , namespace , nil , nil )),
379
386
},
380
387
Status : v1alpha1 .StepStatusUnknown ,
381
388
},
@@ -396,7 +403,7 @@ func TestExecutePlan(t *testing.T) {
396
403
Version : "v1" ,
397
404
Kind : "ServiceAccount" ,
398
405
Name : "sa" ,
399
- Manifest : toManifest (serviceAccount ("sa" , namespace , "" ,
406
+ Manifest : toManifest (t , serviceAccount ("sa" , namespace , "" ,
400
407
objectReference ("init secret" ))),
401
408
},
402
409
Status : v1alpha1 .StepStatusUnknown ,
@@ -418,7 +425,7 @@ func TestExecutePlan(t *testing.T) {
418
425
Version : "v1" ,
419
426
Kind : "ServiceAccount" ,
420
427
Name : "sa" ,
421
- Manifest : toManifest (serviceAccount ("sa" , namespace , "name" ,
428
+ Manifest : toManifest (t , serviceAccount ("sa" , namespace , "name" ,
422
429
objectReference ("init secret" ))),
423
430
},
424
431
Status : v1alpha1 .StepStatusUnknown ,
@@ -431,7 +438,7 @@ func TestExecutePlan(t *testing.T) {
431
438
Version : "v1" ,
432
439
Kind : "ServiceAccount" ,
433
440
Name : "sa" ,
434
- Manifest : toManifest (serviceAccount ("sa" , namespace , "name" , nil )),
441
+ Manifest : toManifest (t , serviceAccount ("sa" , namespace , "name" , nil )),
435
442
},
436
443
Status : v1alpha1 .StepStatusUnknown ,
437
444
},
@@ -452,7 +459,7 @@ func TestExecutePlan(t *testing.T) {
452
459
Version : "v1" ,
453
460
Kind : "ServiceAccount" ,
454
461
Name : "sa" ,
455
- Manifest : toManifest (serviceAccount ("sa" , namespace , "old_name" ,
462
+ Manifest : toManifest (t , serviceAccount ("sa" , namespace , "old_name" ,
456
463
objectReference ("init secret" ))),
457
464
},
458
465
Status : v1alpha1 .StepStatusUnknown ,
@@ -465,7 +472,7 @@ func TestExecutePlan(t *testing.T) {
465
472
Version : "v1" ,
466
473
Kind : "ServiceAccount" ,
467
474
Name : "sa" ,
468
- Manifest : toManifest (serviceAccount ("sa" , namespace , "new_name" , nil )),
475
+ Manifest : toManifest (t , serviceAccount ("sa" , namespace , "new_name" , nil )),
469
476
},
470
477
Status : v1alpha1 .StepStatusUnknown ,
471
478
},
@@ -474,19 +481,62 @@ func TestExecutePlan(t *testing.T) {
474
481
want : []runtime.Object {serviceAccount ("sa" , namespace , "new_name" , objectReference ("init secret" ))},
475
482
err : nil ,
476
483
},
484
+ {
485
+ testName : "DynamicResourcesAreOwnerReferencedToCSV" ,
486
+ in : withSteps (installPlan ("p" , namespace , v1alpha1 .InstallPlanPhaseInstalling , "csv" ),
487
+ []* v1alpha1.Step {
488
+ {
489
+ Resolving : "csv" ,
490
+ Resource : v1alpha1.StepResource {
491
+ CatalogSource : "catalog" ,
492
+ CatalogSourceNamespace : namespace ,
493
+ Group : "operators.coreos.com" ,
494
+ Version : "v1alpha1" ,
495
+ Kind : "ClusterServiceVersion" ,
496
+ Name : "csv" ,
497
+ Manifest : toManifest (t , csv ("csv" , namespace , nil , nil )),
498
+ },
499
+ Status : v1alpha1 .StepStatusUnknown ,
500
+ },
501
+ {
502
+ Resolving : "csv" ,
503
+ Resource : v1alpha1.StepResource {
504
+ CatalogSource : "catalog" ,
505
+ CatalogSourceNamespace : namespace ,
506
+ Group : "monitoring.coreos.com" ,
507
+ Version : "v1" ,
508
+ Kind : "PrometheusRule" ,
509
+ Name : "rule" ,
510
+ Manifest : toManifest (t , decodeFile (t , "./testdata/prometheusrule.cr.yaml" , & unstructured.Unstructured {})),
511
+ },
512
+ Status : v1alpha1 .StepStatusUnknown ,
513
+ },
514
+ },
515
+ ),
516
+ extObjs : []runtime.Object {decodeFile (t , "./testdata/prometheusrule.crd.yaml" , & v1beta1.CustomResourceDefinition {})},
517
+ want : []runtime.Object {
518
+ csv ("csv" , namespace , nil , nil ),
519
+ modify (t , decodeFile (t , "./testdata/prometheusrule.cr.yaml" , & unstructured.Unstructured {}),
520
+ withNamespace (namespace ),
521
+ withOwner (csv ("csv" , namespace , nil , nil )),
522
+ ),
523
+ },
524
+ err : nil ,
525
+ },
477
526
}
478
527
479
528
for _ , tt := range tests {
480
529
t .Run (tt .testName , func (t * testing.T ) {
481
530
ctx , cancel := context .WithCancel (context .TODO ())
482
531
defer cancel ()
483
532
484
- op , err := NewFakeOperator (ctx , namespace , []string {namespace }, withClientObjs (tt .in ))
533
+ op , err := NewFakeOperator (ctx , namespace , []string {namespace }, withClientObjs (tt .in ), withExtObjs ( tt . extObjs ... ) )
485
534
require .NoError (t , err )
486
535
487
536
err = op .ExecutePlan (tt .in )
488
537
require .Equal (t , tt .err , err )
489
538
539
+ getOpts := metav1.GetOptions {}
490
540
for _ , obj := range tt .want {
491
541
var err error
492
542
var fetched runtime.Object
@@ -507,8 +557,29 @@ func TestExecutePlan(t *testing.T) {
507
557
fetched , err = op .opClient .GetSecret (namespace , o .GetName ())
508
558
case * corev1.Service :
509
559
fetched , err = op .opClient .GetService (namespace , o .GetName ())
560
+ case * v1beta1.CustomResourceDefinition :
561
+ fetched , err = op .opClient .ApiextensionsV1beta1Interface ().ApiextensionsV1beta1 ().CustomResourceDefinitions ().Get (o .GetName (), getOpts )
510
562
case * v1alpha1.ClusterServiceVersion :
511
- fetched , err = op .client .OperatorsV1alpha1 ().ClusterServiceVersions (namespace ).Get (o .GetName (), metav1.GetOptions {})
563
+ fetched , err = op .client .OperatorsV1alpha1 ().ClusterServiceVersions (namespace ).Get (o .GetName (), getOpts )
564
+ case * unstructured.Unstructured :
565
+ // Get the resource from the GVK
566
+ gvk := o .GroupVersionKind ()
567
+ var r metav1.APIResource
568
+ r , err = op .apiresourceFromGVK (gvk )
569
+ require .NoError (t , err )
570
+
571
+ gvr := schema.GroupVersionResource {
572
+ Group : gvk .Group ,
573
+ Version : gvk .Version ,
574
+ Resource : r .Name ,
575
+ }
576
+
577
+ if r .Namespaced {
578
+ fetched , err = op .dynamicClient .Resource (gvr ).Namespace (namespace ).Get (o .GetName (), getOpts )
579
+ break
580
+ }
581
+
582
+ fetched , err = op .dynamicClient .Resource (gvr ).Get (o .GetName (), getOpts )
512
583
default :
513
584
require .Failf (t , "couldn't find expected object" , "%#v" , obj )
514
585
}
@@ -558,8 +629,7 @@ func TestSupportedDynamicResources(t *testing.T) {
558
629
559
630
func TestExecutePlanDynamicResources (t * testing.T ) {
560
631
namespace := "ns"
561
- unsupportedYaml , err := yamlFromFilePath ("testdata/unsupportedkind.cr.yaml" )
562
- require .NoError (t , err )
632
+ unsupportedYaml := yamlFromFilePath (t , "testdata/unsupportedkind.cr.yaml" )
563
633
564
634
tests := []struct {
565
635
testName string
@@ -593,7 +663,7 @@ func TestExecutePlanDynamicResources(t *testing.T) {
593
663
ctx , cancel := context .WithCancel (context .TODO ())
594
664
defer cancel ()
595
665
596
- op , err := NewFakeOperator (ctx , namespace , []string {namespace })
666
+ op , err := NewFakeOperator (ctx , namespace , []string {namespace }, withClientObjs ( tt . in ) )
597
667
require .NoError (t , err )
598
668
599
669
err = op .ExecutePlan (tt .in )
@@ -991,7 +1061,7 @@ func withK8sObjs(k8sObjs ...runtime.Object) fakeOperatorOption {
991
1061
}
992
1062
}
993
1063
994
- func extObjs (extObjs ... runtime.Object ) fakeOperatorOption {
1064
+ func withExtObjs (extObjs ... runtime.Object ) fakeOperatorOption {
995
1065
return func (config * fakeOperatorConfig ) {
996
1066
config .extObjs = extObjs
997
1067
}
@@ -1017,8 +1087,13 @@ func NewFakeOperator(ctx context.Context, namespace string, namespaces []string,
1017
1087
1018
1088
// Create client fakes
1019
1089
clientFake := fake .NewReactionForwardingClientsetDecorator (config .clientObjs , config .clientOptions ... )
1020
- opClientFake := operatorclient .NewClient (k8sfake .NewSimpleClientset (config .k8sObjs ... ), apiextensionsfake .NewSimpleClientset (config .extObjs ... ), apiregistrationfake .NewSimpleClientset (config .regObjs ... ))
1090
+ // TODO: Using the ReactionForwardingClientsetDecorator for k8s objects causes issues with adding Resources for discovery.
1091
+ // For now, directly use a SimpleClientset instead.
1092
+ k8sClientFake := k8sfake .NewSimpleClientset (config .k8sObjs ... )
1093
+ k8sClientFake .Resources = apiResourcesForObjects (append (config .extObjs , config .regObjs ... ))
1094
+ opClientFake := operatorclient .NewClient (k8sClientFake , apiextensionsfake .NewSimpleClientset (config .extObjs ... ), apiregistrationfake .NewSimpleClientset (config .regObjs ... ))
1021
1095
dynamicClientFake := fakedynamic .NewSimpleDynamicClient (runtime .NewScheme ())
1096
+ // dynamicClientFake.Resources = k8sClientFake.Resources
1022
1097
1023
1098
// Create operator namespace
1024
1099
_ , err := opClientFake .KubernetesInterface ().CoreV1 ().Namespaces ().Create (& corev1.Namespace {ObjectMeta : metav1.ObjectMeta {Name : namespace }})
@@ -1205,17 +1280,17 @@ func objectReference(name string) *corev1.ObjectReference {
1205
1280
return & corev1.ObjectReference {Name : name }
1206
1281
}
1207
1282
1208
- func yamlFromFilePath (fileName string ) ( string , error ) {
1283
+ func yamlFromFilePath (t * testing. T , fileName string ) string {
1209
1284
yaml , err := ioutil .ReadFile (fileName )
1210
- if err != nil {
1211
- return "" , err
1212
- }
1285
+ require .NoError (t , err )
1213
1286
1214
- return string (yaml ), nil
1287
+ return string (yaml )
1215
1288
}
1216
1289
1217
- func toManifest (obj runtime.Object ) string {
1218
- raw , _ := json .Marshal (obj )
1290
+ func toManifest (t * testing.T , obj runtime.Object ) string {
1291
+ raw , err := json .Marshal (obj )
1292
+ require .NoError (t , err )
1293
+
1219
1294
return string (raw )
1220
1295
}
1221
1296
@@ -1224,3 +1299,110 @@ func pod(s v1alpha1.CatalogSource) *corev1.Pod {
1224
1299
ownerutil .AddOwner (pod , & s , false , false )
1225
1300
return pod
1226
1301
}
1302
+
1303
+ func decodeFile (t * testing.T , file string , to runtime.Object ) runtime.Object {
1304
+ manifest := yamlFromFilePath (t , file )
1305
+ dec := utilyaml .NewYAMLOrJSONDecoder (strings .NewReader (manifest ), 10 )
1306
+ require .NoError (t , dec .Decode (to ))
1307
+
1308
+ return to
1309
+ }
1310
+
1311
+ type modifierFunc func (t * testing.T , obj runtime.Object ) runtime.Object
1312
+
1313
+ func modify (t * testing.T , obj runtime.Object , modifiers ... modifierFunc ) runtime.Object {
1314
+ o := obj .DeepCopyObject ()
1315
+ for _ , modifier := range modifiers {
1316
+ o = modifier (t , o )
1317
+ }
1318
+
1319
+ return o
1320
+ }
1321
+
1322
+ type metaModifierFunc func (m metav1.Object )
1323
+
1324
+ func modifyMeta (mf metaModifierFunc ) modifierFunc {
1325
+ return func (t * testing.T , obj runtime.Object ) runtime.Object {
1326
+ accessor , err := meta .Accessor (obj )
1327
+ require .NoError (t , err )
1328
+
1329
+ mf (accessor )
1330
+
1331
+ return obj
1332
+ }
1333
+ }
1334
+
1335
+ func withNamespace (namespace string ) modifierFunc {
1336
+ return modifyMeta (func (m metav1.Object ) {
1337
+ m .SetNamespace (namespace )
1338
+ })
1339
+ }
1340
+
1341
+ func withOwner (owner ownerutil.Owner ) modifierFunc {
1342
+ return modifyMeta (func (m metav1.Object ) {
1343
+ ownerutil .AddNonBlockingOwner (m , owner )
1344
+ })
1345
+ }
1346
+
1347
+ func withObjectMeta (t * testing.T , obj runtime.Object , m * metav1.ObjectMeta ) runtime.Object {
1348
+ o := obj .DeepCopyObject ()
1349
+ accessor , err := meta .Accessor (o )
1350
+ require .NoError (t , err )
1351
+
1352
+ accessor .SetAnnotations (m .GetAnnotations ())
1353
+ accessor .SetClusterName (m .GetClusterName ())
1354
+ accessor .SetCreationTimestamp (m .GetCreationTimestamp ())
1355
+ accessor .SetDeletionGracePeriodSeconds (m .GetDeletionGracePeriodSeconds ())
1356
+ accessor .SetDeletionTimestamp (m .GetDeletionTimestamp ())
1357
+ accessor .SetFinalizers (m .GetFinalizers ())
1358
+ accessor .SetGenerateName (m .GetGenerateName ())
1359
+ accessor .SetGeneration (m .GetGeneration ())
1360
+ accessor .SetLabels (m .GetLabels ())
1361
+ accessor .SetManagedFields (m .GetManagedFields ())
1362
+ accessor .SetName (m .GetName ())
1363
+ accessor .SetNamespace (m .GetNamespace ())
1364
+ accessor .SetOwnerReferences (m .GetOwnerReferences ())
1365
+ accessor .SetResourceVersion (m .GetResourceVersion ())
1366
+ accessor .SetSelfLink (m .GetSelfLink ())
1367
+ accessor .SetUID (m .GetUID ())
1368
+
1369
+ return o
1370
+ }
1371
+
1372
+ func apiResourcesForObjects (objs []runtime.Object ) []* metav1.APIResourceList {
1373
+ apis := []* metav1.APIResourceList {}
1374
+ for _ , o := range objs {
1375
+ switch o .(type ) {
1376
+ case * v1beta1.CustomResourceDefinition :
1377
+ crd := o .(* v1beta1.CustomResourceDefinition )
1378
+ apis = append (apis , & metav1.APIResourceList {
1379
+ GroupVersion : metav1.GroupVersion {Group : crd .Spec .Group , Version : crd .Spec .Versions [0 ].Name }.String (),
1380
+ APIResources : []metav1.APIResource {
1381
+ {
1382
+ Name : crd .GetName (),
1383
+ SingularName : crd .Spec .Names .Singular ,
1384
+ Namespaced : crd .Spec .Scope == v1beta1 .NamespaceScoped ,
1385
+ Group : crd .Spec .Group ,
1386
+ Version : crd .Spec .Versions [0 ].Name ,
1387
+ Kind : crd .Spec .Names .Kind ,
1388
+ },
1389
+ },
1390
+ })
1391
+ case * apiregistrationv1.APIService :
1392
+ a := o .(* apiregistrationv1.APIService )
1393
+ names := strings .Split (a .Name , "." )
1394
+ apis = append (apis , & metav1.APIResourceList {
1395
+ GroupVersion : metav1.GroupVersion {Group : names [1 ], Version : a .Spec .Version }.String (),
1396
+ APIResources : []metav1.APIResource {
1397
+ {
1398
+ Name : names [1 ],
1399
+ Group : names [1 ],
1400
+ Version : a .Spec .Version ,
1401
+ Kind : names [1 ] + "Kind" ,
1402
+ },
1403
+ },
1404
+ })
1405
+ }
1406
+ }
1407
+ return apis
1408
+ }
0 commit comments