controllers/packagebundle_controller.go (104 lines of code) (raw):
// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package controllers
import (
"context"
"fmt"
"github.com/go-logr/logr"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/builder"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/event"
"sigs.k8s.io/controller-runtime/pkg/handler"
"sigs.k8s.io/controller-runtime/pkg/predicate"
"sigs.k8s.io/controller-runtime/pkg/reconcile"
api "github.com/aws/eks-anywhere-packages/api/v1alpha1"
"github.com/aws/eks-anywhere-packages/pkg/artifacts"
"github.com/aws/eks-anywhere-packages/pkg/authenticator"
"github.com/aws/eks-anywhere-packages/pkg/bundle"
"github.com/aws/eks-anywhere-packages/pkg/config"
)
const packageBundleName = "PackageBundle"
// PackageBundleReconciler reconciles a PackageBundle object
type PackageBundleReconciler struct {
client.Client
Log logr.Logger
Scheme *runtime.Scheme
bundleClient bundle.Client
registryClient bundle.RegistryClient
bundleManager bundle.Manager
}
func NewPackageBundleReconciler(client client.Client, scheme *runtime.Scheme,
bundleClient bundle.Client, bundleManager bundle.Manager, registryClient bundle.RegistryClient, log logr.Logger,
) *PackageBundleReconciler {
return &(PackageBundleReconciler{
Client: client,
Scheme: scheme,
Log: log,
bundleClient: bundleClient,
registryClient: registryClient,
bundleManager: bundleManager,
})
}
func RegisterPackageBundleReconciler(mgr ctrl.Manager) error {
log := ctrl.Log.WithName(packageBundleName)
bundleClient := bundle.NewManagerClient(mgr.GetClient())
tcc := authenticator.NewTargetClusterClient(mgr.GetLogger(), mgr.GetConfig(), mgr.GetClient())
puller := artifacts.NewRegistryPuller(log)
registryClient := bundle.NewRegistryClient(puller)
bundleManager := bundle.NewBundleManager(log, registryClient, bundleClient, tcc, config.GetGlobalConfig())
r := NewPackageBundleReconciler(mgr.GetClient(), mgr.GetScheme(), bundleClient, bundleManager, registryClient, log)
return ctrl.NewControllerManagedBy(mgr).
For(&api.PackageBundle{}).
// Watch for changes in the PackageBundleController, and reconcile
// bundles to update state when active bundle changes.
Watches(&api.PackageBundleController{},
handler.EnqueueRequestsFromMapFunc(r.mapBundleReconcileRequests)).
// Watch for creation or deletion of other bundles, so bundles can update
// their states accordingly.
Watches(&api.PackageBundle{},
handler.EnqueueRequestsFromMapFunc(r.mapBundleReconcileRequests),
builder.WithPredicates(predicate.Funcs{
CreateFunc: func(e event.CreateEvent) bool { return true },
DeleteFunc: func(e event.DeleteEvent) bool { return true },
})).
Complete(r)
}
//+kubebuilder:rbac:groups=packages.eks.amazonaws.com,resources=packagebundles,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=packages.eks.amazonaws.com,resources=packagebundles/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=packages.eks.amazonaws.com,resources=packagebundles/finalizers,verbs=update
// Reconcile is part of the main kubernetes reconciliation loop which aims to
// move the current state of the cluster closer to the desired state.
// the PackageBundle object against the actual cluster state, and then perform
// operations to make the cluster state reflect the state specified by the user.
//
// For more details, check Reconcile and its Result here:
// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.8.3/pkg/reconcile
func (r *PackageBundleReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
r.Log.V(6).Info("Reconcile:", "bundle", req.NamespacedName)
pkgBundle := &api.PackageBundle{}
if err := r.Get(ctx, req.NamespacedName, pkgBundle); err != nil {
if client.IgnoreNotFound(err) != nil {
return ctrl.Result{}, err
}
// ignore deletes
return ctrl.Result{}, nil
}
r.Log.Info("Add/ProcessBundle:", "bundle", req.NamespacedName)
change, err := r.bundleManager.ProcessBundle(ctx, pkgBundle)
if err != nil {
return ctrl.Result{}, fmt.Errorf("package bundle update: %s", err)
}
if change {
err = r.Status().Update(ctx, pkgBundle)
if err != nil {
return ctrl.Result{}, err
}
}
return ctrl.Result{}, nil
}
// mapBundleReconcileRequests generates a reconcile Request for each package bundle in the system.
func (r *PackageBundleReconciler) mapBundleReconcileRequests(_ context.Context, _ client.Object) (
requests []reconcile.Request,
) {
ctx := context.Background()
bundles := &api.PackageBundleList{}
err := r.List(ctx, bundles, &client.ListOptions{Namespace: api.PackageNamespace})
if err != nil {
r.Log.Error(err, "listing package bundles")
return []reconcile.Request{}
}
requests = []reconcile.Request{}
for _, bundle := range bundles.Items {
requests = append(requests, reconcile.Request{
NamespacedName: types.NamespacedName{
Name: bundle.GetName(),
Namespace: bundle.GetNamespace(),
},
})
}
return requests
}