pkg/controllers/serviceaccount_controller.go (68 lines of code) (raw):

// Copyright (c) 2024, Oracle and/or its affiliates. // // Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ package controllers import ( "context" "github.com/mysql/ndb-operator/pkg/resources" corev1 "k8s.io/api/core/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes" typedcorev1 "k8s.io/client-go/kubernetes/typed/core/v1" listerscorev1 "k8s.io/client-go/listers/core/v1" klog "k8s.io/klog/v2" ) type ServiceAccountControlInterface interface { ensureServiceAccount( ctx context.Context, sc *SyncContext) (*corev1.ServiceAccount, error) deleteServiceAccount( ctx context.Context, namespace, name string) error } type ServiceAccountControl struct { k8sClient kubernetes.Interface ServiceAccountLister listerscorev1.ServiceAccountLister } // NewServiceAccountControl creates a new ServiceAccountControl func NewServiceAccountControl(client kubernetes.Interface, ServiceAccountLister listerscorev1.ServiceAccountLister) ServiceAccountControlInterface { return &ServiceAccountControl{ k8sClient: client, ServiceAccountLister: ServiceAccountLister, } } // getServiceAccountInterface retrieves the ServiceAccount Interface from the API Server func (saCtrl *ServiceAccountControl) getServiceAccountInterface(namespace string) typedcorev1.ServiceAccountInterface { return saCtrl.k8sClient.CoreV1().ServiceAccounts(namespace) } // EnsureServiceAccount creates a ServiceAccount if it doesn't exist yet. func (saCtrl *ServiceAccountControl) ensureServiceAccount( ctx context.Context, sc *SyncContext) (*corev1.ServiceAccount, error) { nc := sc.ndb ServiceAccountName := nc.GetServiceAccountName() sa, err := saCtrl.ServiceAccountLister.ServiceAccounts(nc.Namespace).Get(ServiceAccountName) if err == nil { // ServiceAccount exists already if err = sc.isOwnedByNdbCluster(sa); err != nil { // But it is not owned by the NdbCluster resource klog.Errorf( "Attempting to create ServiceAccount %q failed as it exists already but not owned by NdbCluster resource %q", ServiceAccountName, getNamespacedName(nc)) return nil, err } // ServiceAccount already exists and is owned by nc return sa, nil } if !apierrors.IsNotFound(err) { // Error other than NotFound klog.Errorf("Error getting ServiceAccount %q from ServiceAccountLister : %s", ServiceAccountName, err) return nil, err } // ServiceAccount not found - create it sa = resources.NewServiceAccount(nc) klog.Infof("Creating a new ServiceAccount %q for NdbCluster resource %q", getNamespacedName(sa), getNamespacedName(sc.ndb)) sa, err = saCtrl.getServiceAccountInterface(sc.ndb.Namespace).Create(ctx, sa, metav1.CreateOptions{}) if err != nil && !apierrors.IsAlreadyExists(err) { // Create failed. Ignore AlreadyExists error as it // might have been caused due to an outdated cache read. klog.Errorf("Error creating ServiceAccount %q : %s", getNamespacedName(sa), err) return nil, err } return sa, nil } // deleteServiceAccount deletes the given ServiceAccount func (saCtrl *ServiceAccountControl) deleteServiceAccount( ctx context.Context, namespace, name string) error { err := saCtrl.getServiceAccountInterface(namespace).Delete(ctx, name, metav1.DeleteOptions{}) if err != nil && !apierrors.IsNotFound(err) { // Delete failed with an error. // Ignore NotFound error as this delete might be a redundant // step, caused by an outdated cache read. klog.Errorf("Failed to delete the ServiceAccount %q : %s", getNamespacedName2(namespace, name), err) return err } klog.Infof("Deleted ServiceAccount %q", getNamespacedName2(namespace, name)) return nil }