@@ -16,10 +16,9 @@ import (
16
16
corev1 "k8s.io/api/core/v1"
17
17
rbacv1 "k8s.io/api/rbac/v1"
18
18
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions"
19
- v1beta1ext "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1 "
19
+ apiextensionsv1 "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1 "
20
20
"k8s.io/apiextensions-apiserver/pkg/apiserver/validation"
21
21
extinf "k8s.io/apiextensions-apiserver/pkg/client/informers/externalversions"
22
- k8serrors "k8s.io/apimachinery/pkg/api/errors"
23
22
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24
23
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
25
24
"k8s.io/apimachinery/pkg/runtime/schema"
@@ -53,7 +52,6 @@ import (
53
52
"github.com/operator-framework/operator-lifecycle-manager/pkg/lib/scoped"
54
53
sharedtime "github.com/operator-framework/operator-lifecycle-manager/pkg/lib/time"
55
54
"github.com/operator-framework/operator-lifecycle-manager/pkg/metrics"
56
- "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
57
55
)
58
56
59
57
const (
@@ -62,6 +60,7 @@ const (
62
60
clusterRoleKind = "ClusterRole"
63
61
clusterRoleBindingKind = "ClusterRoleBinding"
64
62
configMapKind = "ConfigMap"
63
+ csvKind = "ClusterServiceVersion"
65
64
serviceAccountKind = "ServiceAccount"
66
65
serviceKind = "Service"
67
66
roleKind = "Role"
@@ -323,8 +322,8 @@ func NewOperator(ctx context.Context, kubeconfigPath string, clock utilclock.Clo
323
322
}
324
323
325
324
// Register CustomResourceDefinition QueueInformer
326
- crdInformer := extinf .NewSharedInformerFactory (op .opClient .ApiextensionsV1beta1Interface (), resyncPeriod ()).Apiextensions ().V1beta1 ().CustomResourceDefinitions ()
327
- op .lister .APIExtensionsV1beta1 ().RegisterCustomResourceDefinitionLister (crdInformer .Lister ())
325
+ crdInformer := extinf .NewSharedInformerFactory (op .opClient .ApiextensionsInterface (), resyncPeriod ()).Apiextensions ().V1 ().CustomResourceDefinitions ()
326
+ op .lister .APIExtensionsV1 ().RegisterCustomResourceDefinitionLister (crdInformer .Lister ())
328
327
crdQueueInformer , err := queueinformer .NewQueueInformer (
329
328
ctx ,
330
329
queueinformer .WithLogger (op .logger ),
@@ -1300,22 +1299,18 @@ func (o *Operator) ResolvePlan(plan *v1alpha1.InstallPlan) error {
1300
1299
return nil
1301
1300
}
1302
1301
1303
- func getCRDVersionsMap (crd * v1beta1ext .CustomResourceDefinition ) map [string ]struct {} {
1302
+ func GetCRDV1VersionsMap (crd * apiextensionsv1 .CustomResourceDefinition ) map [string ]struct {} {
1304
1303
versionsMap := map [string ]struct {}{}
1305
1304
1306
1305
for _ , version := range crd .Spec .Versions {
1307
1306
versionsMap [version .Name ] = struct {}{}
1308
1307
}
1309
- if crd .Spec .Version != "" {
1310
- versionsMap [crd .Spec .Version ] = struct {}{}
1311
- }
1312
-
1313
1308
return versionsMap
1314
1309
}
1315
1310
1316
1311
// Ensure all existing served versions are present in new CRD
1317
- func ensureCRDVersions (oldCRD * v1beta1ext .CustomResourceDefinition , newCRD * v1beta1ext .CustomResourceDefinition ) error {
1318
- newCRDVersions := getCRDVersionsMap (newCRD )
1312
+ func EnsureCRDVersions (oldCRD * apiextensionsv1 .CustomResourceDefinition , newCRD * apiextensionsv1 .CustomResourceDefinition ) error {
1313
+ newCRDVersions := GetCRDV1VersionsMap (newCRD )
1319
1314
1320
1315
for _ , oldVersion := range oldCRD .Spec .Versions {
1321
1316
if oldVersion .Served {
@@ -1325,49 +1320,47 @@ func ensureCRDVersions(oldCRD *v1beta1ext.CustomResourceDefinition, newCRD *v1be
1325
1320
}
1326
1321
}
1327
1322
}
1328
- if oldCRD .Spec .Version != "" {
1329
- _ , ok := newCRDVersions [oldCRD .Spec .Version ]
1330
- if ! ok {
1331
- return fmt .Errorf ("New CRD (%s) must contain existing version (%s)" , oldCRD .Name , oldCRD .Spec .Version )
1332
- }
1333
- }
1334
1323
return nil
1335
1324
}
1336
1325
1337
1326
// Validate all existing served versions against new CRD's validation (if changed)
1338
- func (o * Operator ) validateCustomResourceDefinition (oldCRD * v1beta1ext.CustomResourceDefinition , newCRD * v1beta1ext.CustomResourceDefinition ) error {
1339
- o .logger .Debugf ("Comparing %#v to %#v" , oldCRD .Spec .Validation , newCRD .Spec .Validation )
1327
+ func validateV1CRDCompatibility (dynamicClient dynamic.Interface , oldCRD * apiextensionsv1.CustomResourceDefinition , newCRD * apiextensionsv1.CustomResourceDefinition ) error {
1328
+ logrus .Debugf ("Comparing %#v to %#v" , oldCRD .Spec .Versions , newCRD .Spec .Versions )
1329
+
1340
1330
// If validation schema is unchanged, return right away
1341
- if reflect .DeepEqual (oldCRD .Spec .Validation , newCRD .Spec .Validation ) {
1342
- return nil
1331
+ newestSchema := newCRD .Spec .Versions [len (newCRD .Spec .Versions )- 1 ].Schema
1332
+ for i , oldVersion := range oldCRD .Spec .Versions {
1333
+ if ! reflect .DeepEqual (oldVersion .Schema , newestSchema ) {
1334
+ break
1335
+ }
1336
+ if i == len (oldCRD .Spec .Versions )- 1 {
1337
+ // we are on the last iteration
1338
+ // schema has not changed between versions at this point.
1339
+ return nil
1340
+ }
1343
1341
}
1342
+
1344
1343
convertedCRD := & apiextensions.CustomResourceDefinition {}
1345
- if err := v1beta1ext . Convert_v1beta1_CustomResourceDefinition_To_apiextensions_CustomResourceDefinition (newCRD , convertedCRD , nil ); err != nil {
1344
+ if err := apiextensionsv1 . Convert_v1_CustomResourceDefinition_To_apiextensions_CustomResourceDefinition (newCRD , convertedCRD , nil ); err != nil {
1346
1345
return err
1347
1346
}
1348
1347
for _ , version := range oldCRD .Spec .Versions {
1349
1348
if ! version .Served {
1350
1349
gvr := schema.GroupVersionResource {Group : oldCRD .Spec .Group , Version : version .Name , Resource : oldCRD .Spec .Names .Plural }
1351
- err := o . validateExistingCRs (gvr , convertedCRD )
1350
+ err := validateExistingCRs (dynamicClient , gvr , convertedCRD )
1352
1351
if err != nil {
1353
1352
return err
1354
1353
}
1355
1354
}
1356
1355
}
1357
1356
1358
- if oldCRD .Spec .Version != "" {
1359
- gvr := schema.GroupVersionResource {Group : oldCRD .Spec .Group , Version : oldCRD .Spec .Version , Resource : oldCRD .Spec .Names .Plural }
1360
- err := o .validateExistingCRs (gvr , convertedCRD )
1361
- if err != nil {
1362
- return err
1363
- }
1364
- }
1365
- o .logger .Debugf ("Successfully validated CRD %s\n " , newCRD .Name )
1357
+ logrus .Debugf ("Successfully validated CRD %s\n " , newCRD .Name )
1366
1358
return nil
1367
1359
}
1368
1360
1369
- func (o * Operator ) validateExistingCRs (gvr schema.GroupVersionResource , newCRD * apiextensions.CustomResourceDefinition ) error {
1370
- crList , err := o .dynamicClient .Resource (gvr ).List (metav1.ListOptions {})
1361
+ func validateExistingCRs (dynamicClient dynamic.Interface , gvr schema.GroupVersionResource , newCRD * apiextensions.CustomResourceDefinition ) error {
1362
+ // make dynamic client
1363
+ crList , err := dynamicClient .Resource (gvr ).List (metav1.ListOptions {})
1371
1364
if err != nil {
1372
1365
return fmt .Errorf ("error listing resources in GroupVersionResource %#v: %s" , gvr , err )
1373
1366
}
@@ -1389,14 +1382,14 @@ func (o *Operator) validateExistingCRs(gvr schema.GroupVersionResource, newCRD *
1389
1382
// The function may not always succeed as storedVersions requires at least one
1390
1383
// version. If there is only stored version, it won't be removed until a new
1391
1384
// stored version is added.
1392
- func removeDeprecatedStoredVersions (oldCRD * v1beta1ext .CustomResourceDefinition , newCRD * v1beta1ext .CustomResourceDefinition ) []string {
1385
+ func removeDeprecatedV1StoredVersions (oldCRD * apiextensionsv1 .CustomResourceDefinition , newCRD * apiextensionsv1 .CustomResourceDefinition ) []string {
1393
1386
// StoredVersions requires to have at least one version.
1394
1387
if len (oldCRD .Status .StoredVersions ) <= 1 {
1395
1388
return nil
1396
1389
}
1397
1390
1398
1391
newStoredVersions := []string {}
1399
- newCRDVersions := getCRDVersionsMap (newCRD )
1392
+ newCRDVersions := GetCRDV1VersionsMap (newCRD )
1400
1393
for _ , v := range oldCRD .Status .StoredVersions {
1401
1394
_ , ok := newCRDVersions [v ]
1402
1395
if ok {
@@ -1437,113 +1430,35 @@ func (o *Operator) ExecutePlan(plan *v1alpha1.InstallPlan) error {
1437
1430
}
1438
1431
1439
1432
ensurer := newStepEnsurer (kubeclient , crclient , dynamicClient )
1433
+ b := newBuilder (kubeclient , dynamicClient , o .csvProvidedAPIsIndexer )
1440
1434
1441
1435
for i , step := range plan .Status .Plan {
1442
- switch step .Status {
1443
- case v1alpha1 .StepStatusPresent , v1alpha1 .StepStatusCreated :
1436
+ doStep := true
1437
+ s , err := b .create (step )
1438
+ if err != nil {
1439
+ if _ , ok := err .(notSupportedStepperErr ); ok {
1440
+ // stepper not implemented for this type yet
1441
+ // stepper currently only implemented for CRD types
1442
+ doStep = false
1443
+ } else {
1444
+ return err
1445
+ }
1446
+ }
1447
+ if doStep {
1448
+ status , err := s .Status ()
1449
+ if err != nil {
1450
+ return err
1451
+ }
1452
+ plan .Status .Plan [i ].Status = status
1444
1453
continue
1445
- case v1alpha1 .StepStatusWaitingForAPI :
1446
- switch step .Resource .Kind {
1447
- case crdKind :
1448
- crd , err := o .opClient .ApiextensionsV1beta1Interface ().ApiextensionsV1beta1 ().CustomResourceDefinitions ().Get (step .Resource .Name , metav1.GetOptions {})
1449
- if err != nil {
1450
- if k8serrors .IsNotFound (err ) {
1451
- plan .Status .Plan [i ].Status = v1alpha1 .StepStatusNotPresent
1452
- } else {
1453
- return errorwrap .Wrapf (err , "error finding the %s CRD" , crd .Name )
1454
- }
1455
- continue
1456
- }
1457
-
1458
- established , namesAccepted := false , false
1459
- for _ , cdt := range crd .Status .Conditions {
1460
- switch cdt .Type {
1461
- case v1beta1 .Established :
1462
- if cdt .Status == v1beta1 .ConditionTrue {
1463
- established = true
1464
- }
1465
- case v1beta1 .NamesAccepted :
1466
- if cdt .Status == v1beta1 .ConditionTrue {
1467
- namesAccepted = true
1468
- }
1469
- }
1470
- }
1454
+ }
1471
1455
1472
- if established && namesAccepted {
1473
- plan .Status .Plan [i ].Status = v1alpha1 .StepStatusCreated
1474
- }
1475
- continue
1476
- }
1456
+ switch step .Status {
1457
+ case v1alpha1 .StepStatusPresent , v1alpha1 .StepStatusCreated , v1alpha1 .StepStatusWaitingForAPI :
1458
+ continue
1477
1459
case v1alpha1 .StepStatusUnknown , v1alpha1 .StepStatusNotPresent :
1478
1460
o .logger .WithFields (logrus.Fields {"kind" : step .Resource .Kind , "name" : step .Resource .Name }).Debug ("execute resource" )
1479
1461
switch step .Resource .Kind {
1480
- case crdKind :
1481
- // Marshal the manifest into a CRD instance.
1482
- var crd v1beta1ext.CustomResourceDefinition
1483
- err := json .Unmarshal ([]byte (step .Resource .Manifest ), & crd )
1484
- if err != nil {
1485
- return errorwrap .Wrapf (err , "error parsing step manifest: %s" , step .Resource .Name )
1486
- }
1487
-
1488
- // TODO: check that names are accepted
1489
- // Attempt to create the CRD.
1490
- _ , err = o .opClient .ApiextensionsV1beta1Interface ().ApiextensionsV1beta1 ().CustomResourceDefinitions ().Create (& crd )
1491
- if k8serrors .IsAlreadyExists (err ) {
1492
- currentCRD , _ := o .lister .APIExtensionsV1beta1 ().CustomResourceDefinitionLister ().Get (crd .GetName ())
1493
- // Compare 2 CRDs to see if it needs to be updatetd
1494
- if ! (reflect .DeepEqual (crd .Spec .Version , currentCRD .Spec .Version ) &&
1495
- reflect .DeepEqual (crd .Spec .Versions , currentCRD .Spec .Versions ) &&
1496
- reflect .DeepEqual (crd .Spec .Validation , currentCRD .Spec .Validation )) {
1497
- // Verify CRD ownership, only attempt to update if
1498
- // CRD has only one owner
1499
- // Example: provided=database.coreos.com/v1alpha1/EtcdCluster
1500
- matchedCSV , err := index .CRDProviderNames (o .csvProvidedAPIsIndexer , crd )
1501
- if err != nil {
1502
- return errorwrap .Wrapf (err , "error find matched CSV: %s" , step .Resource .Name )
1503
- }
1504
- crd .SetResourceVersion (currentCRD .GetResourceVersion ())
1505
- if len (matchedCSV ) == 1 {
1506
- o .logger .Debugf ("Found one owner for CRD %v" , crd )
1507
- } else if len (matchedCSV ) > 1 {
1508
- o .logger .Debugf ("Found multiple owners for CRD %v" , crd )
1509
-
1510
- err := ensureCRDVersions (currentCRD , & crd )
1511
- if err != nil {
1512
- return errorwrap .Wrapf (err , "error missing existing CRD version(s) in new CRD: %s" , step .Resource .Name )
1513
- }
1514
-
1515
- if err = o .validateCustomResourceDefinition (currentCRD , & crd ); err != nil {
1516
- return errorwrap .Wrapf (err , "error validating existing CRs agains new CRD's schema: %s" , step .Resource .Name )
1517
- }
1518
- }
1519
- // Remove deprecated version in CRD storedVersions
1520
- storeVersions := removeDeprecatedStoredVersions (currentCRD , & crd )
1521
- if storeVersions != nil {
1522
- currentCRD .Status .StoredVersions = storeVersions
1523
- resultCRD , err := o .opClient .ApiextensionsV1beta1Interface ().ApiextensionsV1beta1 ().CustomResourceDefinitions ().UpdateStatus (currentCRD )
1524
- if err != nil {
1525
- return errorwrap .Wrapf (err , "error updating CRD's status: %s" , step .Resource .Name )
1526
- }
1527
- crd .SetResourceVersion (resultCRD .GetResourceVersion ())
1528
- }
1529
- // Update CRD to new version
1530
- _ , err = o .opClient .ApiextensionsV1beta1Interface ().ApiextensionsV1beta1 ().CustomResourceDefinitions ().Update (& crd )
1531
- if err != nil {
1532
- return errorwrap .Wrapf (err , "error updating CRD: %s" , step .Resource .Name )
1533
- }
1534
- }
1535
- // If it already existed, mark the step as Present.
1536
- plan .Status .Plan [i ].Status = v1alpha1 .StepStatusPresent
1537
- continue
1538
- } else if err != nil {
1539
- // Unexpected error creating the CRD.
1540
- return err
1541
- } else {
1542
- // If no error occured, make sure to wait for the API to become available.
1543
- plan .Status .Plan [i ].Status = v1alpha1 .StepStatusWaitingForAPI
1544
- continue
1545
- }
1546
-
1547
1462
case v1alpha1 .ClusterServiceVersionKind :
1548
1463
// Marshal the manifest into a CSV instance.
1549
1464
var csv v1alpha1.ClusterServiceVersion
0 commit comments