diff --git a/manifests/4.2/cluster-logging.v4.2.0.clusterserviceversion.yaml b/manifests/4.2/cluster-logging.v4.2.0.clusterserviceversion.yaml index 1392f92a6f..282b0ccffe 100644 --- a/manifests/4.2/cluster-logging.v4.2.0.clusterserviceversion.yaml +++ b/manifests/4.2/cluster-logging.v4.2.0.clusterserviceversion.yaml @@ -139,6 +139,7 @@ spec: - configmaps - secrets - serviceaccounts + - serviceaccounts/finalizers verbs: - "*" - apiGroups: diff --git a/pkg/k8shandler/collection.go b/pkg/k8shandler/collection.go index 02cd1c32c8..7cdb31d4f5 100644 --- a/pkg/k8shandler/collection.go +++ b/pkg/k8shandler/collection.go @@ -10,10 +10,13 @@ import ( "github.com/sirupsen/logrus" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/apimachinery/pkg/types" "k8s.io/client-go/util/retry" logging "github.com/openshift/cluster-logging-operator/pkg/apis/logging/v1" apps "k8s.io/api/apps/v1" + core "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) const ( @@ -29,11 +32,15 @@ var ( timeout = time.Second * 1800 ) +var serviceAccountLogCollectorUID types.UID + //CreateOrUpdateCollection component of the cluster func (clusterRequest *ClusterLoggingRequest) CreateOrUpdateCollection() (err error) { cluster := clusterRequest.cluster + var collectorServiceAccount *core.ServiceAccount + // there is no easier way to check this in golang without writing a helper function // TODO: write a helper function to validate Type is a valid option for common setup or tear down if cluster.Spec.Collection.Logs.Type == logging.LogCollectionTypeFluentd || cluster.Spec.Collection.Logs.Type == logging.LogCollectionTypeRsyslog { @@ -41,7 +48,7 @@ func (clusterRequest *ClusterLoggingRequest) CreateOrUpdateCollection() (err err return } - if err = clusterRequest.createOrUpdateCollectorServiceAccount(); err != nil { + if collectorServiceAccount, err = clusterRequest.createOrUpdateCollectorServiceAccount(); err != nil { return } } @@ -162,6 +169,15 @@ func (clusterRequest *ClusterLoggingRequest) CreateOrUpdateCollection() (err err return } } + if collectorServiceAccount != nil && (cluster.Spec.Collection.Logs.Type == logging.LogCollectionTypeFluentd || cluster.Spec.Collection.Logs.Type == logging.LogCollectionTypeRsyslog) { + + // remove our finalizer from the list and update it. + collectorServiceAccount.ObjectMeta.Finalizers = utils.RemoveString(collectorServiceAccount.ObjectMeta.Finalizers, metav1.FinalizerDeleteDependents) + err = clusterRequest.Create(collectorServiceAccount) + if err != nil && !errors.IsAlreadyExists(err) { + return + } + } return nil } @@ -180,7 +196,7 @@ func (clusterRequest *ClusterLoggingRequest) createOrUpdateCollectionPriorityCla return nil } -func (clusterRequest *ClusterLoggingRequest) createOrUpdateCollectorServiceAccount() error { +func (clusterRequest *ClusterLoggingRequest) createOrUpdateCollectorServiceAccount() (*core.ServiceAccount, error) { cluster := clusterRequest.cluster @@ -188,9 +204,23 @@ func (clusterRequest *ClusterLoggingRequest) createOrUpdateCollectorServiceAccou utils.AddOwnerRefToObject(collectorServiceAccount, utils.AsOwner(clusterRequest.cluster)) - err := clusterRequest.Create(collectorServiceAccount) - if err != nil && !errors.IsAlreadyExists(err) { - return fmt.Errorf("Failure creating Log Collector service account: %v", err) + delfinalizer := false + if collectorServiceAccount.ObjectMeta.DeletionTimestamp.IsZero() { + // This object is not being deleted. + if !utils.ContainsString(collectorServiceAccount.ObjectMeta.Finalizers, metav1.FinalizerDeleteDependents) { + collectorServiceAccount.ObjectMeta.Finalizers = append(collectorServiceAccount.ObjectMeta.Finalizers, metav1.FinalizerDeleteDependents) + } + err := clusterRequest.Create(collectorServiceAccount) + if err != nil && !errors.IsAlreadyExists(err) { + return nil, fmt.Errorf("Failure creating Log Collector service account: %v", err) + } + if len(collectorServiceAccount.ObjectMeta.UID) != 0 { + serviceAccountLogCollectorUID = collectorServiceAccount.ObjectMeta.UID + } + } else if utils.ContainsString(collectorServiceAccount.ObjectMeta.Finalizers, metav1.FinalizerDeleteDependents) { + // This object is being deleted. + // our finalizer is present, so lets handle any dependency + delfinalizer = true } // Also create the role and role binding so that the service account has host read access @@ -209,9 +239,9 @@ func (clusterRequest *ClusterLoggingRequest) createOrUpdateCollectorServiceAccou utils.AddOwnerRefToObject(collectorRole, utils.AsOwner(cluster)) - err = clusterRequest.Create(collectorRole) + err := clusterRequest.Create(collectorRole) if err != nil && !errors.IsAlreadyExists(err) { - return fmt.Errorf("Failure creating Log collector privileged role: %v", err) + return nil, fmt.Errorf("Failure creating Log collector privileged role: %v", err) } subject := NewSubject( @@ -233,7 +263,7 @@ func (clusterRequest *ClusterLoggingRequest) createOrUpdateCollectorServiceAccou err = clusterRequest.Create(collectorRoleBinding) if err != nil && !errors.IsAlreadyExists(err) { - return fmt.Errorf("Failure creating Log collector privileged role binding: %v", err) + return nil, fmt.Errorf("Failure creating Log collector privileged role binding: %v", err) } // create clusterrole for logcollector to retrieve metadata @@ -247,7 +277,7 @@ func (clusterRequest *ClusterLoggingRequest) createOrUpdateCollectorServiceAccou ) clusterRole, err := clusterRequest.CreateClusterRole("metadata-reader", clusterrules, cluster) if err != nil { - return err + return nil, err } subject = NewSubject( "ServiceAccount", @@ -268,10 +298,14 @@ func (clusterRequest *ClusterLoggingRequest) createOrUpdateCollectorServiceAccou err = clusterRequest.Create(collectorReaderClusterRoleBinding) if err != nil && !errors.IsAlreadyExists(err) { - return fmt.Errorf("Failure creating Log collector %q cluster role binding: %v", collectorReaderClusterRoleBinding.Name, err) + return nil, fmt.Errorf("Failure creating Log collector %q cluster role binding: %v", collectorReaderClusterRoleBinding.Name, err) } - return nil + if delfinalizer { + return collectorServiceAccount, nil + } else { + return nil, nil + } } func isDaemonsetDifferent(current *apps.DaemonSet, desired *apps.DaemonSet) (*apps.DaemonSet, bool) { @@ -387,3 +421,7 @@ func isBufferFlushRequired(current *apps.DaemonSet, desired *apps.DaemonSet) boo return (currVersion == "3.11" && desVersion == "4.0.0") } + +func getServiceAccountLogCollectorUID() types.UID { + return serviceAccountLogCollectorUID +} diff --git a/pkg/k8shandler/fluentd.go b/pkg/k8shandler/fluentd.go index b443137792..9fbf3e4f39 100644 --- a/pkg/k8shandler/fluentd.go +++ b/pkg/k8shandler/fluentd.go @@ -307,7 +307,15 @@ func (clusterRequest *ClusterLoggingRequest) createOrUpdateFluentdDaemonset() (e fluentdPodSpec := newFluentdPodSpec(cluster, "elasticsearch", "elasticsearch") fluentdDaemonset := NewDaemonSet("fluentd", cluster.Namespace, "fluentd", "fluentd", fluentdPodSpec) - utils.AddOwnerRefToObject(fluentdDaemonset, utils.AsOwner(cluster)) + + uid := getServiceAccountLogCollectorUID() + if len(uid) == 0 { + // There's no uid for logcollector serviceaccount; setting ClusterLogging for the ownerReference. + utils.AddOwnerRefToObject(fluentdDaemonset, utils.AsOwner(cluster)) + } else { + // There's a uid for logcollector serviceaccount; setting the ServiceAccount for the ownerReference with blockOwnerDeletion. + utils.AddOwnerRefToObject(fluentdDaemonset, NewLogCollectorServiceAccountRef(uid)) + } err = clusterRequest.Create(fluentdDaemonset) if err != nil && !errors.IsAlreadyExists(err) { diff --git a/pkg/k8shandler/rsyslog.go b/pkg/k8shandler/rsyslog.go index 3916910411..ab025babdf 100644 --- a/pkg/k8shandler/rsyslog.go +++ b/pkg/k8shandler/rsyslog.go @@ -61,7 +61,7 @@ func (clusterRequest *ClusterLoggingRequest) removeRsyslog() (err error) { } // Wait longer than the default terminationGracePeriodSeconds - time.Sleep(12* time.Second) + time.Sleep(12 * time.Second) if err = clusterRequest.RemoveSecret("rsyslog"); err != nil { return @@ -296,7 +296,14 @@ func (clusterRequest *ClusterLoggingRequest) createOrUpdateRsyslogDaemonset() (e rsyslogDaemonset := NewDaemonSet("rsyslog", cluster.Namespace, "rsyslog", "rsyslog", rsyslogPodSpec) - utils.AddOwnerRefToObject(rsyslogDaemonset, utils.AsOwner(cluster)) + uid := getServiceAccountLogCollectorUID() + if len(uid) == 0 { + // There's no uid for logcollector serviceaccount; setting ClusterLogging for the ownerReference. + utils.AddOwnerRefToObject(rsyslogDaemonset, utils.AsOwner(cluster)) + } else { + // There's a uid for logcollector serviceaccount; setting the ServiceAccount for the ownerReference with blockOwnerDeletion. + utils.AddOwnerRefToObject(rsyslogDaemonset, NewLogCollectorServiceAccountRef(uid)) + } err = clusterRequest.Create(rsyslogDaemonset) if err != nil && !errors.IsAlreadyExists(err) { diff --git a/pkg/k8shandler/serviceaccount.go b/pkg/k8shandler/serviceaccount.go index 2e171d14c0..a988ada6aa 100644 --- a/pkg/k8shandler/serviceaccount.go +++ b/pkg/k8shandler/serviceaccount.go @@ -5,6 +5,7 @@ import ( "github.com/openshift/cluster-logging-operator/pkg/utils" "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" core "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -44,6 +45,11 @@ func (clusterRequest *ClusterLoggingRequest) RemoveServiceAccount(serviceAccount serviceAccount := NewServiceAccount(serviceAccountName, clusterRequest.cluster.Namespace) + if serviceAccountName == "logcollector" { + // remove our finalizer from the list and update it. + serviceAccount.ObjectMeta.Finalizers = utils.RemoveString(serviceAccount.ObjectMeta.Finalizers, metav1.FinalizerDeleteDependents) + } + err := clusterRequest.Delete(serviceAccount) if err != nil && !errors.IsNotFound(err) { return fmt.Errorf("Failure deleting %v service account: %v", serviceAccountName, err) @@ -51,3 +57,14 @@ func (clusterRequest *ClusterLoggingRequest) RemoveServiceAccount(serviceAccount return nil } + +func NewLogCollectorServiceAccountRef(uid types.UID) metav1.OwnerReference { + return metav1.OwnerReference { + APIVersion: "v1", // apiversion for serviceaccounts/finalizers in cluster-logging..clusterserviceversion.yaml + Kind: "ServiceAccount", + Name: "logcollector", + UID: uid, + BlockOwnerDeletion: utils.GetBool(true), + Controller: utils.GetBool(true), + } +} diff --git a/pkg/utils/utils.go b/pkg/utils/utils.go index f142c61ca3..d3e5f063d8 100644 --- a/pkg/utils/utils.go +++ b/pkg/utils/utils.go @@ -221,3 +221,22 @@ func CheckFileExists(filePath string) error { } return nil } + +func ContainsString(slice []string, s string) bool { + for _, item := range slice { + if item == s { + return true + } + } + return false +} + +func RemoveString(slice []string, s string) (result []string) { + for _, item := range slice { + if item == s { + continue + } + result = append(result, item) + } + return +}