@@ -17,27 +17,35 @@ limitations under the License.
1717package controllers
1818
1919import (
20+ "bytes"
2021 "context"
2122 "errors"
2223 "fmt"
24+ "io"
2325 "sort"
2426 "strings"
2527
28+ "github.com/operator-framework/operator-controller/internal/rukpak/handler"
29+ "github.com/operator-framework/operator-controller/internal/rukpak/util"
30+ "helm.sh/helm/v3/pkg/postrender"
31+
2632 mmsemver "github.com/Masterminds/semver/v3"
2733 bsemver "github.com/blang/semver/v4"
2834 "github.com/go-logr/logr"
2935 "k8s.io/apimachinery/pkg/api/equality"
3036 apierrors "k8s.io/apimachinery/pkg/api/errors"
37+ "k8s.io/apimachinery/pkg/api/meta"
3138 apimeta "k8s.io/apimachinery/pkg/api/meta"
3239 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
3340 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
3441 "k8s.io/apimachinery/pkg/runtime"
3542 "k8s.io/apimachinery/pkg/types"
3643 utilerrors "k8s.io/apimachinery/pkg/util/errors"
44+ apimachyaml "k8s.io/apimachinery/pkg/util/yaml"
3745 "k8s.io/utils/ptr"
3846 ctrl "sigs.k8s.io/controller-runtime"
3947 "sigs.k8s.io/controller-runtime/pkg/client"
40- "sigs.k8s.io/controller-runtime/pkg/handler"
48+ crhandler "sigs.k8s.io/controller-runtime/pkg/handler"
4149 "sigs.k8s.io/controller-runtime/pkg/log"
4250 "sigs.k8s.io/controller-runtime/pkg/reconcile"
4351
@@ -51,13 +59,19 @@ import (
5159 catalogfilter "github.com/operator-framework/operator-controller/internal/catalogmetadata/filter"
5260 catalogsort "github.com/operator-framework/operator-controller/internal/catalogmetadata/sort"
5361 rukpakapi "github.com/operator-framework/operator-controller/internal/rukpak/api"
62+ "github.com/operator-framework/operator-controller/internal/rukpak/source"
63+ "github.com/operator-framework/operator-controller/internal/rukpak/storage"
5464)
5565
5666// ClusterExtensionReconciler reconciles a ClusterExtension object
5767type ClusterExtensionReconciler struct {
5868 client.Client
69+ ReleaseNamespace string
5970 BundleProvider BundleProvider
71+ Unpacker source.Unpacker
6072 ActionClientGetter helmclient.ActionClientGetter
73+ Storage storage.Storage
74+ Handler handler.Handler
6175 Scheme * runtime.Scheme
6276}
6377
@@ -137,10 +151,62 @@ func (r *ClusterExtensionReconciler) reconcile(ctx context.Context, ext *ocv1alp
137151 // Considering only image source.
138152
139153 // Generate a BundleSource, and then pass this and the ClusterExtension to Unpack
140- // TODO:
141- // bs := r.GenerateExpectedBundleSource(*ext, bundle.Image)
142- // unpacker := NewDefaultUnpacker(msg, namespace, unpackImage)
143- // unpacker..Unpack(bs, ext)
154+ bs := r .GenerateExpectedBundleSource (* ext , bundle .Image )
155+ unpackResult , err := r .Unpacker .Unpack (ctx , bs , ext )
156+ if err != nil {
157+ return ctrl.Result {}, updateStatusUnpackFailing (& ext .Status , fmt .Errorf ("source bundle content: %v" , err ))
158+ }
159+
160+ switch unpackResult .State {
161+ case source .StatePending :
162+ updateStatusUnpackPending (& ext .Status , unpackResult )
163+ // There must be a limit to number of entries if status is stuck at
164+ // unpack pending.
165+ return ctrl.Result {}, nil
166+ case source .StateUnpacking :
167+ updateStatusUnpacking (& ext .Status , unpackResult )
168+ return ctrl.Result {}, nil
169+ case source .StateUnpacked :
170+ if err := r .Storage .Store (ctx , ext , unpackResult .Bundle ); err != nil {
171+ return ctrl.Result {}, updateStatusUnpackFailing (& ext .Status , fmt .Errorf ("persist bundle content: %v" , err ))
172+ }
173+ contentURL , err := r .Storage .URLFor (ctx , ext )
174+ if err != nil {
175+ return ctrl.Result {}, updateStatusUnpackFailing (& ext .Status , fmt .Errorf ("get content URL: %v" , err ))
176+ }
177+ updateStatusUnpacked (& ext .Status , unpackResult , contentURL )
178+ default :
179+ return ctrl.Result {}, updateStatusUnpackFailing (& ext .Status , fmt .Errorf ("unknown unpack state %q: %v" , unpackResult .State , err ))
180+ }
181+
182+ bundleFS , err := r .Storage .Load (ctx , ext )
183+ if err != nil {
184+ meta .SetStatusCondition (& ext .Status .Conditions , metav1.Condition {
185+ Type : ocv1alpha1 .TypeHasValidBundle ,
186+ Status : metav1 .ConditionFalse ,
187+ Reason : ocv1alpha1 .ReasonBundleLoadFailed ,
188+ Message : err .Error (),
189+ })
190+ return ctrl.Result {}, err
191+ }
192+
193+ _ , _ , err = r .Handler .Handle (ctx , bundleFS , ext )
194+ if err != nil {
195+ meta .SetStatusCondition (& ext .Status .Conditions , metav1.Condition {
196+ Type : rukpakv1alpha2 .TypeInstalled ,
197+ Status : metav1 .ConditionFalse ,
198+ Reason : rukpakv1alpha2 .ReasonInstallFailed ,
199+ Message : err .Error (),
200+ })
201+ return ctrl.Result {}, err
202+ }
203+
204+ ext .SetNamespace (r .ReleaseNamespace )
205+ _ , err = r .ActionClientGetter .ActionClientFor (ext )
206+ if err != nil {
207+ setInstalledStatusConditionFailed (& ext .Status .Conditions , fmt .Sprintf ("%s:%v" , ocv1alpha1 .ReasonErrorGettingClient , err ), ext .Generation )
208+ return ctrl.Result {}, err
209+ }
144210
145211 // set the status of the cluster extension based on the respective bundle deployment status conditions.
146212 return ctrl.Result {}, nil
@@ -286,7 +352,7 @@ func (r *ClusterExtensionReconciler) SetupWithManager(mgr ctrl.Manager) error {
286352 err := ctrl .NewControllerManagedBy (mgr ).
287353 For (& ocv1alpha1.ClusterExtension {}).
288354 Watches (& catalogd.Catalog {},
289- handler .EnqueueRequestsFromMapFunc (clusterExtensionRequestsForCatalog (mgr .GetClient (), mgr .GetLogger ()))).
355+ crhandler .EnqueueRequestsFromMapFunc (clusterExtensionRequestsForCatalog (mgr .GetClient (), mgr .GetLogger ()))).
290356 Owns (& rukpakv1alpha2.BundleDeployment {}).
291357 Complete (r )
292358
@@ -297,7 +363,7 @@ func (r *ClusterExtensionReconciler) SetupWithManager(mgr ctrl.Manager) error {
297363}
298364
299365// Generate reconcile requests for all cluster extensions affected by a catalog change
300- func clusterExtensionRequestsForCatalog (c client.Reader , logger logr.Logger ) handler .MapFunc {
366+ func clusterExtensionRequestsForCatalog (c client.Reader , logger logr.Logger ) crhandler .MapFunc {
301367 return func (ctx context.Context , _ client.Object ) []reconcile.Request {
302368 // no way of associating an extension to a catalog so create reconcile requests for everything
303369 clusterExtensions := ocv1alpha1.ClusterExtensionList {}
@@ -417,3 +483,33 @@ func (r *ClusterExtensionReconciler) getInstalledVersion(ctx context.Context, cl
417483 }
418484 return existingVersionSemver , nil
419485}
486+
487+ type postrenderer struct {
488+ labels map [string ]string
489+ cascade postrender.PostRenderer
490+ }
491+
492+ func (p * postrenderer ) Run (renderedManifests * bytes.Buffer ) (* bytes.Buffer , error ) {
493+ var buf bytes.Buffer
494+ dec := apimachyaml .NewYAMLOrJSONDecoder (renderedManifests , 1024 )
495+ for {
496+ obj := unstructured.Unstructured {}
497+ err := dec .Decode (& obj )
498+ if errors .Is (err , io .EOF ) {
499+ break
500+ }
501+ if err != nil {
502+ return nil , err
503+ }
504+ obj .SetLabels (util .MergeMaps (obj .GetLabels (), p .labels ))
505+ b , err := obj .MarshalJSON ()
506+ if err != nil {
507+ return nil , err
508+ }
509+ buf .Write (b )
510+ }
511+ if p .cascade != nil {
512+ return p .cascade .Run (& buf )
513+ }
514+ return & buf , nil
515+ }
0 commit comments