github.com/redhat-appstudio/release-service@v0.0.0-20240507045911-a8558ef3422a/controllers/release/controller.go (about)

     1  /*
     2  Copyright 2022.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package release
    18  
    19  import (
    20  	"context"
    21  
    22  	"github.com/konflux-ci/operator-toolkit/controller"
    23  	"github.com/konflux-ci/operator-toolkit/predicates"
    24  	tektonv1 "github.com/tektoncd/pipeline/pkg/apis/pipeline/v1"
    25  	"sigs.k8s.io/controller-runtime/pkg/cluster"
    26  
    27  	"github.com/go-logr/logr"
    28  	libhandler "github.com/operator-framework/operator-lib/handler"
    29  	"github.com/redhat-appstudio/release-service/api/v1alpha1"
    30  	"github.com/redhat-appstudio/release-service/cache"
    31  	"github.com/redhat-appstudio/release-service/loader"
    32  	"github.com/redhat-appstudio/release-service/tekton"
    33  	"k8s.io/apimachinery/pkg/api/errors"
    34  	"k8s.io/apimachinery/pkg/runtime/schema"
    35  	ctrl "sigs.k8s.io/controller-runtime"
    36  	"sigs.k8s.io/controller-runtime/pkg/builder"
    37  	"sigs.k8s.io/controller-runtime/pkg/client"
    38  	"sigs.k8s.io/controller-runtime/pkg/predicate"
    39  )
    40  
    41  // Controller reconciles a Release object
    42  type Controller struct {
    43  	client client.Client
    44  	log    logr.Logger
    45  }
    46  
    47  //+kubebuilder:rbac:groups=appstudio.redhat.com,resources=releases,verbs=get;list;watch;create;update;patch;delete
    48  //+kubebuilder:rbac:groups=appstudio.redhat.com,resources=releases/status,verbs=get;update;patch
    49  //+kubebuilder:rbac:groups=appstudio.redhat.com,resources=releases/finalizers,verbs=update
    50  //+kubebuilder:rbac:groups=appstudio.redhat.com,resources=applications/finalizers,verbs=update
    51  //+kubebuilder:rbac:groups=appstudio.redhat.com,resources=enterprisecontractpolicies,verbs=get;list;watch
    52  //+kubebuilder:rbac:groups=appstudio.redhat.com,resources=enterprisecontractpolicies/status,verbs=get
    53  //+kubebuilder:rbac:groups=appstudio.redhat.com,resources=releaseserviceconfigs,verbs=get;list;watch
    54  //+kubebuilder:rbac:groups=core,resources=configmaps,verbs=get;list;watch
    55  //+kubebuilder:rbac:groups=rbac.authorization.k8s.io,resources=rolebindings,verbs=get;list;watch;create;update;patch;delete
    56  //+kubebuilder:rbac:groups=appstudio.redhat.com,resources=internalrequests,verbs=create;delete;get;list;watch
    57  //InternalRequests RBAC is required to prevent `forbidden: user system:serviceaccount:release-service:release-service-controller-manager
    58  //is attempting to grant RBAC permissions not currently held`
    59  
    60  // Reconcile is part of the main kubernetes reconciliation loop which aims to
    61  // move the current state of the cluster closer to the desired state.
    62  func (c *Controller) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
    63  	logger := c.log.WithValues("Release", req.NamespacedName)
    64  
    65  	release := &v1alpha1.Release{}
    66  	err := c.client.Get(ctx, req.NamespacedName, release)
    67  	if err != nil {
    68  		if errors.IsNotFound(err) {
    69  			return ctrl.Result{}, nil
    70  		}
    71  
    72  		return ctrl.Result{}, err
    73  	}
    74  
    75  	adapter := newAdapter(ctx, c.client, release, loader.NewLoader(), &logger)
    76  
    77  	return controller.ReconcileHandler([]controller.Operation{
    78  		adapter.EnsureFinalizersAreCalled,
    79  		adapter.EnsureConfigIsLoaded, // This operation sets the config in the adapter to be used in other operations.
    80  		adapter.EnsureReleaseIsRunning,
    81  		adapter.EnsureReleaseIsValid,
    82  		adapter.EnsureFinalizerIsAdded,
    83  		adapter.EnsureReleaseExpirationTimeIsAdded,
    84  		adapter.EnsureReleaseIsProcessed,
    85  		adapter.EnsureReleaseProcessingIsTracked,
    86  		adapter.EnsureReleaseProcessingResourcesAreCleanedUp,
    87  		adapter.EnsureReleaseIsCompleted,
    88  	})
    89  }
    90  
    91  // Register registers the controller with the passed manager and log. This controller ignores Release status updates and
    92  // also watches for PipelineRuns and SnapshotEnvironmentBindings that are created by the adapter and owned by the
    93  // Releases so the owner gets reconciled on changes.
    94  func (c *Controller) Register(mgr ctrl.Manager, log *logr.Logger, _ cluster.Cluster) error {
    95  	c.client = mgr.GetClient()
    96  	c.log = log.WithName("release")
    97  
    98  	return ctrl.NewControllerManagedBy(mgr).
    99  		For(&v1alpha1.Release{}, builder.WithPredicates(predicate.GenerationChangedPredicate{}, predicates.IgnoreBackups{})).
   100  		Watches(&tektonv1.PipelineRun{}, &libhandler.EnqueueRequestForAnnotation{
   101  			Type: schema.GroupKind{
   102  				Kind:  "Release",
   103  				Group: "appstudio.redhat.com",
   104  			},
   105  		}, builder.WithPredicates(tekton.ReleasePipelineRunSucceededPredicate())).
   106  		Complete(c)
   107  }
   108  
   109  // SetupCache indexes fields for each of the resources used in the release adapter in those cases where filtering by
   110  // field is required.
   111  func (c *Controller) SetupCache(mgr ctrl.Manager) error {
   112  	if err := cache.SetupComponentCache(mgr); err != nil {
   113  		return err
   114  	}
   115  
   116  	// NOTE: Both the release and releaseplan controller need this ReleasePlanAdmission cache. However, it only needs to be added
   117  	// once to the manager, so only one controller should add it. If it is removed here, it should be added to the ReleasePlan controller.
   118  	return cache.SetupReleasePlanAdmissionCache(mgr)
   119  }