@@ -1028,6 +1028,54 @@ func (o *Operator) syncResolvingNamespace(obj interface{}) error {
1028
1028
return err
1029
1029
}
1030
1030
1031
+ // Attempt to unpack bundles before installing
1032
+ // Note: This should probably use the attenuated client to prevent users from resolving resources they otherwise don't have access to.
1033
+ if len (bundleLookups ) > 0 {
1034
+ logger .Debug ("unpacking bundles" )
1035
+
1036
+ var unpacked bool
1037
+ unpacked , steps , bundleLookups , err = o .unpackBundles (namespace , bundleLookups )
1038
+ if err != nil {
1039
+ return fmt .Errorf ("bundle unpacking failed with an error: %v" , err )
1040
+ }
1041
+
1042
+ // Check BundleLookup status conditions to see if the BundleLookupFailed condtion is true
1043
+ // which means bundle lookup has failed and subscriptions need to be updated
1044
+ // with a condition indicating the failure.
1045
+ isFailed , cond := hasBundleLookupFailureCondition (bundleLookups )
1046
+ if isFailed {
1047
+ err := fmt .Errorf ("bundle unpacking failed. Reason: %v, and Message: %v" , cond .Reason , cond .Message )
1048
+ logger .Infof ("%v" , err )
1049
+
1050
+ _ , updateErr := o .updateSubscriptionStatuses (
1051
+ o .setSubsCond (subs , v1alpha1.SubscriptionCondition {
1052
+ // TODO: Decide if we need a separate type and/or reason for unpack failures
1053
+ Type : v1alpha1 .SubscriptionResolutionFailed ,
1054
+ Reason : "BundleUnpackFailurePreventedResolution" ,
1055
+ Message : err .Error (),
1056
+ Status : corev1 .ConditionTrue ,
1057
+ }))
1058
+ if updateErr != nil {
1059
+ logger .WithError (updateErr ).Debug ("failed to update subs conditions" )
1060
+ return updateErr
1061
+ }
1062
+ // Since this is likely requires intervention we do not want to
1063
+ // requeue too often. We return no error here and rely on a
1064
+ // periodic resync which will help to automatically resolve
1065
+ // some issues such as unreachable bundle images caused by
1066
+ // bad catalog updates.
1067
+ return nil
1068
+ }
1069
+
1070
+ // This means that the unpack job is still running (most likely) or
1071
+ // there was some issue which we did not handle above.
1072
+ if ! unpacked {
1073
+ logger .Debug ("unpacking is not complete yet, requeueing" )
1074
+ o .nsResolveQueue .AddAfter (namespace , 5 * time .Second )
1075
+ return nil
1076
+ }
1077
+ }
1078
+
1031
1079
// create installplan if anything updated
1032
1080
if len (updatedSubs ) > 0 {
1033
1081
logger .Debug ("resolution caused subscription changes, creating installplan" )
@@ -1408,32 +1456,38 @@ type UnpackedBundleReference struct {
1408
1456
Properties string `json:"properties"`
1409
1457
}
1410
1458
1411
- func (o * Operator ) unpackBundles (plan * v1alpha1.InstallPlan ) (bool , * v1alpha1.InstallPlan , error ) {
1412
- out := plan .DeepCopy ()
1459
+ func (o * Operator ) unpackBundles (namespace string , bundleLookups []v1alpha1.BundleLookup ) (bool , []* v1alpha1.Step , []v1alpha1.BundleLookup , error ) {
1413
1460
unpacked := true
1414
1461
1462
+ outBundleLookups := make ([]v1alpha1.BundleLookup , len (bundleLookups ))
1463
+ for i := range bundleLookups {
1464
+ bundleLookups [i ].DeepCopyInto (& outBundleLookups [i ])
1465
+ }
1466
+
1415
1467
// The bundle timeout annotation if specified overrides the --bundle-unpack-timeout flag value
1416
1468
// If the timeout cannot be parsed it's set to < 0 and subsequently ignored
1417
1469
unpackTimeout := - 1 * time .Minute
1418
- timeoutStr , ok := plan .GetAnnotations ()[bundle .BundleUnpackTimeoutAnnotationKey ]
1419
- if ok {
1420
- d , err := time .ParseDuration (timeoutStr )
1421
- if err != nil {
1422
- o .logger .Errorf ("failed to parse unpack timeout annotation(%s: %s): %v" , bundle .BundleUnpackTimeoutAnnotationKey , timeoutStr , err )
1423
- } else {
1424
- unpackTimeout = d
1425
- }
1426
- }
1427
-
1470
+ // TODO: Update. This is internal stuff for testing. Maybe move to a sub?
1471
+ // timeoutStr, ok := plan.GetAnnotations()[bundle.BundleUnpackTimeoutAnnotationKey]
1472
+ // if ok {
1473
+ // d, err := time.ParseDuration(timeoutStr)
1474
+ // if err != nil {
1475
+ // o.logger.Errorf("failed to parse unpack timeout annotation(%s: %s): %v", bundle.BundleUnpackTimeoutAnnotationKey, timeoutStr, err)
1476
+ // } else {
1477
+ // unpackTimeout = d
1478
+ // }
1479
+ // }
1480
+
1481
+ installPlanSteps := []* v1alpha1.Step {}
1428
1482
var errs []error
1429
- for i := 0 ; i < len (out . Status . BundleLookups ); i ++ {
1430
- lookup := out . Status . BundleLookups [i ]
1483
+ for i := 0 ; i < len (outBundleLookups ); i ++ {
1484
+ lookup := outBundleLookups [i ]
1431
1485
res , err := o .bundleUnpacker .UnpackBundle (& lookup , unpackTimeout )
1432
1486
if err != nil {
1433
1487
errs = append (errs , err )
1434
1488
continue
1435
1489
}
1436
- out . Status . BundleLookups [i ] = * res .BundleLookup
1490
+ outBundleLookups [i ] = * res .BundleLookup
1437
1491
1438
1492
// if the failed condition is present it means the bundle unpacking has failed
1439
1493
failedCondition := res .GetCondition (bundle .BundleLookupFailed )
@@ -1455,11 +1509,11 @@ func (o *Operator) unpackBundles(plan *v1alpha1.InstallPlan) (bool, *v1alpha1.In
1455
1509
continue
1456
1510
}
1457
1511
1458
- // Ensure that bundle can be applied by the current version of OLM by converting to steps
1459
- steps , err := resolver .NewStepsFromBundle (res .Bundle (), out . GetNamespace () , res .Replaces , res .CatalogSourceRef .Name , res .CatalogSourceRef .Namespace )
1512
+ // Ensure that bundle can be applied by the current version of OLM by converting to bundleSteps
1513
+ bundleSteps , err := resolver .NewStepsFromBundle (res .Bundle (), namespace , res .Replaces , res .CatalogSourceRef .Name , res .CatalogSourceRef .Namespace )
1460
1514
if err != nil {
1461
1515
if fatal := olmerrors .IsFatal (err ); fatal {
1462
- return false , nil , err
1516
+ return false , nil , nil , err
1463
1517
}
1464
1518
1465
1519
errs = append (errs , fmt .Errorf ("failed to turn bundle into steps: %v" , err ))
@@ -1468,7 +1522,7 @@ func (o *Operator) unpackBundles(plan *v1alpha1.InstallPlan) (bool, *v1alpha1.In
1468
1522
}
1469
1523
1470
1524
// step manifests are replaced with references to the configmap containing them
1471
- for i , s := range steps {
1525
+ for i , s := range bundleSteps {
1472
1526
ref := UnpackedBundleReference {
1473
1527
Kind : "ConfigMap" ,
1474
1528
Namespace : res .CatalogSourceRef .Namespace ,
@@ -1485,19 +1539,19 @@ func (o *Operator) unpackBundles(plan *v1alpha1.InstallPlan) (bool, *v1alpha1.In
1485
1539
continue
1486
1540
}
1487
1541
s .Resource .Manifest = string (r )
1488
- steps [i ] = s
1542
+ bundleSteps [i ] = s
1489
1543
}
1490
1544
res .RemoveCondition (resolver .BundleLookupConditionPacked )
1491
- out . Status . BundleLookups [i ] = * res .BundleLookup
1492
- out . Status . Plan = append (out . Status . Plan , steps ... )
1545
+ outBundleLookups [i ] = * res .BundleLookup
1546
+ installPlanSteps = append (installPlanSteps , bundleSteps ... )
1493
1547
}
1494
1548
1495
1549
if err := utilerrors .NewAggregate (errs ); err != nil {
1496
1550
o .logger .Debugf ("failed to unpack bundles: %v" , err )
1497
- return false , nil , err
1551
+ return false , nil , nil , err
1498
1552
}
1499
1553
1500
- return unpacked , out , nil
1554
+ return unpacked , installPlanSteps , outBundleLookups , nil
1501
1555
}
1502
1556
1503
1557
// gcInstallPlans garbage collects installplans that are too old
@@ -1645,65 +1699,6 @@ func (o *Operator) syncInstallPlans(obj interface{}) (syncError error) {
1645
1699
}
1646
1700
}
1647
1701
1648
- // Attempt to unpack bundles before installing
1649
- // Note: This should probably use the attenuated client to prevent users from resolving resources they otherwise don't have access to.
1650
- if len (plan .Status .BundleLookups ) > 0 {
1651
- unpacked , out , err := o .unpackBundles (plan )
1652
- if err != nil {
1653
- // If the error was fatal capture and fail
1654
- if fatal := olmerrors .IsFatal (err ); fatal {
1655
- if err := o .transitionInstallPlanToFailed (plan , logger , v1alpha1 .InstallPlanReasonInstallCheckFailed , err .Error ()); err != nil {
1656
- // retry for failure to update status
1657
- syncError = err
1658
- return
1659
- }
1660
- }
1661
- // Retry sync if non-fatal error
1662
- syncError = fmt .Errorf ("bundle unpacking failed: %v" , err )
1663
- return
1664
- }
1665
-
1666
- if ! reflect .DeepEqual (plan .Status , out .Status ) {
1667
- logger .Warnf ("status not equal, updating..." )
1668
- if _ , err := o .client .OperatorsV1alpha1 ().InstallPlans (out .GetNamespace ()).UpdateStatus (context .TODO (), out , metav1.UpdateOptions {}); err != nil {
1669
- syncError = fmt .Errorf ("failed to update installplan bundle lookups: %v" , err )
1670
- }
1671
-
1672
- return
1673
- }
1674
-
1675
- // Check BundleLookup status conditions to see if the BundleLookupPending condtion is false
1676
- // which means bundle lookup has failed and the InstallPlan should be failed as well
1677
- isFailed , cond := hasBundleLookupFailureCondition (plan )
1678
- if isFailed {
1679
- err := fmt .Errorf ("bundle unpacking failed. Reason: %v, and Message: %v" , cond .Reason , cond .Message )
1680
- // Mark the InstallPlan as failed for a fatal bundle unpack error
1681
- logger .Infof ("%v" , err )
1682
-
1683
- if err := o .transitionInstallPlanToFailed (plan , logger , v1alpha1 .InstallPlanReasonInstallCheckFailed , err .Error ()); err != nil {
1684
- // retry for failure to update status
1685
- syncError = err
1686
- return
1687
- }
1688
-
1689
- // Requeue subscription to propagate SubscriptionInstallPlanFailed condtion to subscription
1690
- o .requeueSubscriptionForInstallPlan (plan , logger )
1691
- return
1692
- }
1693
-
1694
- // TODO: Remove in favor of job and configmap informer requeuing
1695
- if ! unpacked {
1696
- err := o .ipQueueSet .RequeueAfter (plan .GetNamespace (), plan .GetName (), 5 * time .Second )
1697
- if err != nil {
1698
- syncError = err
1699
- return
1700
- }
1701
- logger .Debug ("install plan not yet populated from bundle image, requeueing" )
1702
-
1703
- return
1704
- }
1705
- }
1706
-
1707
1702
outInstallPlan , syncError := transitionInstallPlanState (logger .Logger , o , * plan , o .now (), o .installPlanTimeout )
1708
1703
1709
1704
if syncError != nil {
@@ -1731,8 +1726,8 @@ func (o *Operator) syncInstallPlans(obj interface{}) (syncError error) {
1731
1726
return
1732
1727
}
1733
1728
1734
- func hasBundleLookupFailureCondition (plan * v1alpha1.InstallPlan ) (bool , * v1alpha1.BundleLookupCondition ) {
1735
- for _ , bundleLookup := range plan . Status . BundleLookups {
1729
+ func hasBundleLookupFailureCondition (bundleLookups [] v1alpha1.BundleLookup ) (bool , * v1alpha1.BundleLookupCondition ) {
1730
+ for _ , bundleLookup := range bundleLookups {
1736
1731
for _ , cond := range bundleLookup .Conditions {
1737
1732
if cond .Type == bundle .BundleLookupFailed && cond .Status == corev1 .ConditionTrue {
1738
1733
return true , & cond
@@ -1742,27 +1737,6 @@ func hasBundleLookupFailureCondition(plan *v1alpha1.InstallPlan) (bool, *v1alpha
1742
1737
return false , nil
1743
1738
}
1744
1739
1745
- func (o * Operator ) transitionInstallPlanToFailed (plan * v1alpha1.InstallPlan , logger logrus.FieldLogger , reason v1alpha1.InstallPlanConditionReason , message string ) error {
1746
- now := o .now ()
1747
- out := plan .DeepCopy ()
1748
- out .Status .SetCondition (v1alpha1 .ConditionFailed (v1alpha1 .InstallPlanInstalled ,
1749
- reason , message , & now ))
1750
- out .Status .Phase = v1alpha1 .InstallPlanPhaseFailed
1751
-
1752
- logger .Info ("transitioning InstallPlan to failed" )
1753
- _ , err := o .client .OperatorsV1alpha1 ().InstallPlans (plan .GetNamespace ()).UpdateStatus (context .TODO (), out , metav1.UpdateOptions {})
1754
- if err == nil {
1755
- return nil
1756
- }
1757
-
1758
- updateErr := errors .New ("error updating InstallPlan status: " + err .Error ())
1759
- logger = logger .WithField ("updateError" , updateErr )
1760
- logger .Errorf ("error transitioning InstallPlan to failed" )
1761
-
1762
- // retry sync with error to update InstallPlan status
1763
- return fmt .Errorf ("installplan failed: %s and error updating InstallPlan status as failed: %s" , message , updateErr )
1764
- }
1765
-
1766
1740
func (o * Operator ) requeueSubscriptionForInstallPlan (plan * v1alpha1.InstallPlan , logger * logrus.Entry ) {
1767
1741
// Notify subscription loop of installplan changes
1768
1742
owners := ownerutil .GetOwnersByKind (plan , v1alpha1 .SubscriptionKind )
0 commit comments