From f92f402a918141e36ec071d5deb9f375e2c8786e Mon Sep 17 00:00:00 2001 From: Peter Wilcsinszky Date: Thu, 18 Jan 2024 16:11:05 +0100 Subject: [PATCH 01/15] scratch implementation Signed-off-by: Peter Wilcsinszky --- api/telemetry/v1alpha1/collector_types.go | 2 +- api/telemetry/v1alpha1/subscription_types.go | 7 ++-- api/telemetry/v1alpha1/tenant_types.go | 3 +- .../telemetry/collector_controller.go | 40 +++++++++++++++++-- 4 files changed, 44 insertions(+), 8 deletions(-) diff --git a/api/telemetry/v1alpha1/collector_types.go b/api/telemetry/v1alpha1/collector_types.go index 933fccee..62561980 100644 --- a/api/telemetry/v1alpha1/collector_types.go +++ b/api/telemetry/v1alpha1/collector_types.go @@ -43,7 +43,7 @@ type Collector struct { Status CollectorStatus `json:"status,omitempty"` } -//+kubebuilder:object:root=true +// +kubebuilder:object:root=true // CollectorList contains a list of Collector type CollectorList struct { diff --git a/api/telemetry/v1alpha1/subscription_types.go b/api/telemetry/v1alpha1/subscription_types.go index d60acf5f..6d966c82 100644 --- a/api/telemetry/v1alpha1/subscription_types.go +++ b/api/telemetry/v1alpha1/subscription_types.go @@ -34,10 +34,11 @@ type SubscriptionSpec struct { type SubscriptionStatus struct { // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster // Important: Run "make" to regenerate code after modifying this file + Tenant string } -//+kubebuilder:object:root=true -//+kubebuilder:subresource:status +// +kubebuilder:object:root=true +// +kubebuilder:subresource:status // Subscription is the Schema for the subscriptions API type Subscription struct { @@ -48,7 +49,7 @@ type Subscription struct { Status SubscriptionStatus `json:"status,omitempty"` } -//+kubebuilder:object:root=true +// +kubebuilder:object:root=true // SubscriptionList contains a list of Subscription type SubscriptionList struct { diff --git a/api/telemetry/v1alpha1/tenant_types.go b/api/telemetry/v1alpha1/tenant_types.go index 51f339fb..de38c400 100644 --- a/api/telemetry/v1alpha1/tenant_types.go +++ b/api/telemetry/v1alpha1/tenant_types.go @@ -28,6 +28,7 @@ type TenantSpec struct { type TenantStatus struct { Subscriptions []string `json:"subscriptions"` LogSourceNamespaces []string `json:"logSourceNamespaces"` + Collector string `json:"collector"` } //+kubebuilder:object:root=true @@ -45,7 +46,7 @@ type Tenant struct { Status TenantStatus `json:"status,omitempty"` } -//+kubebuilder:object:root=true +// +kubebuilder:object:root=true // TenantList contains a list of Tenant type TenantList struct { diff --git a/internal/controller/telemetry/collector_controller.go b/internal/controller/telemetry/collector_controller.go index 0e5bdd37..58e26301 100644 --- a/internal/controller/telemetry/collector_controller.go +++ b/internal/controller/telemetry/collector_controller.go @@ -25,9 +25,12 @@ import ( rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/handler" "sigs.k8s.io/controller-runtime/pkg/log" + "sigs.k8s.io/controller-runtime/pkg/reconcile" "github.com/kube-logging/subscription-operator/api/telemetry/v1alpha1" @@ -41,9 +44,9 @@ type CollectorReconciler struct { Scheme *runtime.Scheme } -//+kubebuilder:rbac:groups=telemetry.kube-logging.dev,resources=collectors,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=telemetry.kube-logging.dev,resources=collectors/status,verbs=get;update;patch -//+kubebuilder:rbac:groups=telemetry.kube-logging.dev,resources=collectors/finalizers,verbs=update +// +kubebuilder:rbac:groups=telemetry.kube-logging.dev,resources=collectors,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=telemetry.kube-logging.dev,resources=collectors/status,verbs=get;update;patch +// +kubebuilder:rbac:groups=telemetry.kube-logging.dev,resources=collectors/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. @@ -82,6 +85,10 @@ func (r *CollectorReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( subscriptions := []v1alpha1.Subscription{} for _, tenant := range tenants { + // check if tenant is owned by us, or make it ours only if orphan + // this update will connect the tenant and collector exclusively + tenant.Status.Collector = collector + err := r.Status().Update(ctx, &tenant) subscriptionsForTenant, err := r.getSubscriptionsForTenant(ctx, &tenant) @@ -91,6 +98,7 @@ func (r *CollectorReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( subscriptions = append(subscriptions, subscriptionsForTenant...) + // Todo implement subscription locking similarly to how we do with tenants subscriptionNames := getSubscriptionNamesFromSubscription(subscriptionsForTenant) tenantSubscriptionMap[tenant.NamespacedName()] = subscriptionNames @@ -206,6 +214,32 @@ func (r *CollectorReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( func (r *CollectorReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). For(&v1alpha1.Collector{}). + Watches(&v1alpha1.Tenant{}, handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, object client.Object) []reconcile.Request { + requests := []reconcile.Request{} + tenant, _ := object.(*v1alpha1.Tenant) + + collectors := v1alpha1.CollectorList{} + r.List(context.TODO(), collectors) + + for _, c := range collectors.Items { + tenantsForCollector := &v1alpha1.TenantList{} + r.List(context.TODO(), tenantsForCollector, c.Spec.TenantSelector) + for _, t := range tenantsForCollector.Items { + if t.Name == tenant.Name { + // optionally we might discard the notification if the tenant is + // owned by another controller + // t.Status.Collector != c.Name + requests = append(requests, reconcile.Request{ + NamespacedName: types.NamespacedName{ + Name: c.Name, + }, + }) + } + } + } + + return requests + })). Complete(r) } From 30234d5e3c19a1821fb24589f0dcc4a2f3fb5ed9 Mon Sep 17 00:00:00 2001 From: Kristof Gyuracz Date: Thu, 25 Jan 2024 14:40:57 +0100 Subject: [PATCH 02/15] api changes Signed-off-by: Kristof Gyuracz --- api/telemetry/v1alpha1/collector_types.go | 2 +- api/telemetry/v1alpha1/subscription_types.go | 10 +--------- api/telemetry/v1alpha1/tenant_types.go | 5 +++-- .../bases/telemetry.kube-logging.dev_collectors.yaml | 2 -- .../telemetry.kube-logging.dev_subscriptions.yaml | 3 +++ .../crd/bases/telemetry.kube-logging.dev_tenants.yaml | 8 ++++++-- 6 files changed, 14 insertions(+), 16 deletions(-) diff --git a/api/telemetry/v1alpha1/collector_types.go b/api/telemetry/v1alpha1/collector_types.go index 62561980..c64bce34 100644 --- a/api/telemetry/v1alpha1/collector_types.go +++ b/api/telemetry/v1alpha1/collector_types.go @@ -26,7 +26,7 @@ type CollectorSpec struct { // CollectorStatus defines the observed state of Collector type CollectorStatus struct { - Tenants []string `json:"tenants"` + Tenants []string `json:"tenants,omitempty"` } //+kubebuilder:object:root=true diff --git a/api/telemetry/v1alpha1/subscription_types.go b/api/telemetry/v1alpha1/subscription_types.go index 6d966c82..c57304ef 100644 --- a/api/telemetry/v1alpha1/subscription_types.go +++ b/api/telemetry/v1alpha1/subscription_types.go @@ -18,23 +18,15 @@ import ( metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" ) -// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN! -// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized. - // SubscriptionSpec defines the desired state of Subscription type SubscriptionSpec struct { - // INSERT ADDITIONAL SPEC FIELDS - desired state of cluster - // Important: Run "make" to regenerate code after modifying this file - Outputs []NamespacedName `json:"outputs,omitempty"` OTTL string `json:"ottl,omitempty"` } // SubscriptionStatus defines the observed state of Subscription type SubscriptionStatus struct { - // INSERT ADDITIONAL STATUS FIELD - define observed state of cluster - // Important: Run "make" to regenerate code after modifying this file - Tenant string + Tenant string `json:"tenant,omitempty"` } // +kubebuilder:object:root=true diff --git a/api/telemetry/v1alpha1/tenant_types.go b/api/telemetry/v1alpha1/tenant_types.go index de38c400..b7015405 100644 --- a/api/telemetry/v1alpha1/tenant_types.go +++ b/api/telemetry/v1alpha1/tenant_types.go @@ -26,8 +26,8 @@ type TenantSpec struct { // TenantStatus defines the observed state of Tenant type TenantStatus struct { - Subscriptions []string `json:"subscriptions"` - LogSourceNamespaces []string `json:"logSourceNamespaces"` + Subscriptions []string `json:"subscriptions,omitempty"` + LogSourceNamespaces []string `json:"logSourceNamespaces,omitempty"` Collector string `json:"collector"` } @@ -36,6 +36,7 @@ type TenantStatus struct { //+kubebuilder:subresource:status //+kubebuilder:printcolumn:name="Subscriptions",type=string,JSONPath=`.status.subscriptions` //+kubebuilder:printcolumn:name="Logsource namespaces",type=string,JSONPath=`.status.logSourceNamespaces` +//+kubebuilder:printcolumn:name="Collector",type=string,JSONPath=`.status.collector` // Tenant is the Schema for the tenants API type Tenant struct { diff --git a/config/crd/bases/telemetry.kube-logging.dev_collectors.yaml b/config/crd/bases/telemetry.kube-logging.dev_collectors.yaml index f91f63c5..548f323a 100644 --- a/config/crd/bases/telemetry.kube-logging.dev_collectors.yaml +++ b/config/crd/bases/telemetry.kube-logging.dev_collectors.yaml @@ -98,8 +98,6 @@ spec: items: type: string type: array - required: - - tenants type: object type: object served: true diff --git a/config/crd/bases/telemetry.kube-logging.dev_subscriptions.yaml b/config/crd/bases/telemetry.kube-logging.dev_subscriptions.yaml index e057ed76..3b66e8eb 100644 --- a/config/crd/bases/telemetry.kube-logging.dev_subscriptions.yaml +++ b/config/crd/bases/telemetry.kube-logging.dev_subscriptions.yaml @@ -51,6 +51,9 @@ spec: type: object status: description: SubscriptionStatus defines the observed state of Subscription + properties: + tenant: + type: string type: object type: object served: true diff --git a/config/crd/bases/telemetry.kube-logging.dev_tenants.yaml b/config/crd/bases/telemetry.kube-logging.dev_tenants.yaml index ad203dfb..95aed1c8 100644 --- a/config/crd/bases/telemetry.kube-logging.dev_tenants.yaml +++ b/config/crd/bases/telemetry.kube-logging.dev_tenants.yaml @@ -21,6 +21,9 @@ spec: - jsonPath: .status.logSourceNamespaces name: Logsource namespaces type: string + - jsonPath: .status.collector + name: Collector + type: string name: v1alpha1 schema: openAPIV3Schema: @@ -145,6 +148,8 @@ spec: status: description: TenantStatus defines the observed state of Tenant properties: + collector: + type: string logSourceNamespaces: items: type: string @@ -154,8 +159,7 @@ spec: type: string type: array required: - - logSourceNamespaces - - subscriptions + - collector type: object type: object served: true From 43b7b43b0245a2da2ddfeba18a250016f13a830c Mon Sep 17 00:00:00 2001 From: Kristof Gyuracz Date: Thu, 25 Jan 2024 15:23:12 +0100 Subject: [PATCH 03/15] set tenant-> collector ref and notify controller on change Signed-off-by: Kristof Gyuracz --- .../telemetry/collector_controller.go | 48 ++++++++++++------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/internal/controller/telemetry/collector_controller.go b/internal/controller/telemetry/collector_controller.go index 58e26301..2788f9ac 100644 --- a/internal/controller/telemetry/collector_controller.go +++ b/internal/controller/telemetry/collector_controller.go @@ -74,21 +74,23 @@ func (r *CollectorReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( return ctrl.Result{}, err } - tenantNames := getTenantNamesFromTenants(tenants) - slices.Sort(tenantNames) - - collector.Status.Tenants = tenantNames - - r.Status().Update(ctx, collector) - logger.Info("Setting collector status") + tenantNames := []string{} subscriptions := []v1alpha1.Subscription{} for _, tenant := range tenants { // check if tenant is owned by us, or make it ours only if orphan // this update will connect the tenant and collector exclusively - tenant.Status.Collector = collector - err := r.Status().Update(ctx, &tenant) + + if tenant.Status.Collector != "" && tenant.Status.Collector != collector.Name { + logger.Error(errors.Errorf("tenant (%s) is owned by another collector (%s), skipping reconciliation for this collector (%s)", tenant.Name, tenant.Status.Collector, collector.Name), + "make sure to remove tenant from the previous collector before adopting to new collector") + continue + } + + tenantNames = append(tenantNames, tenant.Name) + + tenant.Status.Collector = collector.Name subscriptionsForTenant, err := r.getSubscriptionsForTenant(ctx, &tenant) @@ -117,14 +119,26 @@ func (r *CollectorReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( return ctrl.Result{}, err } + tenant.Status.Collector = collector.Name + slices.Sort(logsourceNamespacesForTenant) tenant.Status.LogSourceNamespaces = logsourceNamespacesForTenant - r.Status().Update(ctx, &tenant) + err = r.Status().Update(ctx, &tenant) + if err != nil { + return ctrl.Result{}, err + } logger.Info("Setting tenant status") } + slices.Sort(tenantNames) + + collector.Status.Tenants = tenantNames + + r.Status().Update(ctx, collector) + logger.Info("Setting collector status") + outputs, err := r.getAllOutputs(ctx) if err != nil { return ctrl.Result{}, err @@ -219,16 +233,16 @@ func (r *CollectorReconciler) SetupWithManager(mgr ctrl.Manager) error { tenant, _ := object.(*v1alpha1.Tenant) collectors := v1alpha1.CollectorList{} - r.List(context.TODO(), collectors) + r.List(ctx, &collectors) for _, c := range collectors.Items { - tenantsForCollector := &v1alpha1.TenantList{} - r.List(context.TODO(), tenantsForCollector, c.Spec.TenantSelector) - for _, t := range tenantsForCollector.Items { + tenantsForCollector, err := r.getTenantsMatchingSelectors(ctx, c.Spec.TenantSelector) + if err != nil { + return nil + } + + for _, t := range tenantsForCollector { if t.Name == tenant.Name { - // optionally we might discard the notification if the tenant is - // owned by another controller - // t.Status.Collector != c.Name requests = append(requests, reconcile.Request{ NamespacedName: types.NamespacedName{ Name: c.Name, From ed32153aa19bba0ae95177eba4817ee84a15d414 Mon Sep 17 00:00:00 2001 From: Kristof Gyuracz Date: Mon, 29 Jan 2024 20:08:44 +0100 Subject: [PATCH 04/15] triggering for relevant changes, disowning, and checking ownership before adopting tenants and subscriptions Signed-off-by: Kristof Gyuracz --- api/telemetry/v1alpha1/subscription_types.go | 1 + ...emetry.kube-logging.dev_subscriptions.yaml | 6 +- .../telemetry/collector_controller.go | 239 ++++++++++++++++-- 3 files changed, 226 insertions(+), 20 deletions(-) diff --git a/api/telemetry/v1alpha1/subscription_types.go b/api/telemetry/v1alpha1/subscription_types.go index c57304ef..d7202ad0 100644 --- a/api/telemetry/v1alpha1/subscription_types.go +++ b/api/telemetry/v1alpha1/subscription_types.go @@ -31,6 +31,7 @@ type SubscriptionStatus struct { // +kubebuilder:object:root=true // +kubebuilder:subresource:status +//+kubebuilder:printcolumn:name="Tenant",type=string,JSONPath=`.status.tenant` // Subscription is the Schema for the subscriptions API type Subscription struct { diff --git a/config/crd/bases/telemetry.kube-logging.dev_subscriptions.yaml b/config/crd/bases/telemetry.kube-logging.dev_subscriptions.yaml index 3b66e8eb..33414cbb 100644 --- a/config/crd/bases/telemetry.kube-logging.dev_subscriptions.yaml +++ b/config/crd/bases/telemetry.kube-logging.dev_subscriptions.yaml @@ -14,7 +14,11 @@ spec: singular: subscription scope: Namespaced versions: - - name: v1alpha1 + - additionalPrinterColumns: + - jsonPath: .status.tenant + name: Tenant + type: string + name: v1alpha1 schema: openAPIV3Schema: description: Subscription is the Schema for the subscriptions API diff --git a/internal/controller/telemetry/collector_controller.go b/internal/controller/telemetry/collector_controller.go index 2788f9ac..9f54daac 100644 --- a/internal/controller/telemetry/collector_controller.go +++ b/internal/controller/telemetry/collector_controller.go @@ -24,6 +24,7 @@ import ( apiv1 "k8s.io/api/core/v1" rbacv1 "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" @@ -44,6 +45,9 @@ type CollectorReconciler struct { Scheme *runtime.Scheme } +const collectorReferenceField = ".status.collector" +const tenantReferenceField = ".status.tenant" + // +kubebuilder:rbac:groups=telemetry.kube-logging.dev,resources=collectors,verbs=get;list;watch;create;update;patch;delete // +kubebuilder:rbac:groups=telemetry.kube-logging.dev,resources=collectors/status,verbs=get;update;patch // +kubebuilder:rbac:groups=telemetry.kube-logging.dev,resources=collectors/finalizers,verbs=update @@ -74,6 +78,16 @@ func (r *CollectorReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( return ctrl.Result{}, err } + tenantsToDisown, err := r.getTenantsReferencingCollectorButNotSelected(ctx, collector, tenants) + if err != nil { + return ctrl.Result{}, err + } + + err = r.disownTenants(ctx, tenantsToDisown) + if err != nil { + return ctrl.Result{}, err + } + tenantNames := []string{} subscriptions := []v1alpha1.Subscription{} @@ -98,9 +112,18 @@ func (r *CollectorReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( return ctrl.Result{}, err } + subscriptionsToDisown, err := r.getSubscriptionsReferencingTenantButNotSelected(ctx, &tenant, subscriptionsForTenant) + if err != nil { + return ctrl.Result{}, err + } + + err = r.disownSubscriptions(ctx, subscriptionsToDisown) + if err != nil { + return ctrl.Result{}, err + } + subscriptions = append(subscriptions, subscriptionsForTenant...) - // Todo implement subscription locking similarly to how we do with tenants subscriptionNames := getSubscriptionNamesFromSubscription(subscriptionsForTenant) tenantSubscriptionMap[tenant.NamespacedName()] = subscriptionNames @@ -226,6 +249,27 @@ func (r *CollectorReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( // SetupWithManager sets up the controller with the Manager. func (r *CollectorReconciler) SetupWithManager(mgr ctrl.Manager) error { + + if err := mgr.GetFieldIndexer().IndexField(context.Background(), &v1alpha1.Tenant{}, collectorReferenceField, func(rawObj client.Object) []string { + tenant := rawObj.(*v1alpha1.Tenant) + if tenant.Status.Collector == "" { + return nil + } + return []string{tenant.Status.Collector} + }); err != nil { + return err + } + + if err := mgr.GetFieldIndexer().IndexField(context.Background(), &v1alpha1.Subscription{}, tenantReferenceField, func(rawObj client.Object) []string { + subscription := rawObj.(*v1alpha1.Subscription) + if subscription.Status.Tenant == "" { + return nil + } + return []string{subscription.Status.Tenant} + }); err != nil { + return err + } + return ctrl.NewControllerManagedBy(mgr). For(&v1alpha1.Collector{}). Watches(&v1alpha1.Tenant{}, handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, object client.Object) []reconcile.Request { @@ -235,8 +279,8 @@ func (r *CollectorReconciler) SetupWithManager(mgr ctrl.Manager) error { collectors := v1alpha1.CollectorList{} r.List(ctx, &collectors) - for _, c := range collectors.Items { - tenantsForCollector, err := r.getTenantsMatchingSelectors(ctx, c.Spec.TenantSelector) + for _, collector := range collectors.Items { + tenantsForCollector, err := r.getTenantsMatchingSelectors(ctx, collector.Spec.TenantSelector) if err != nil { return nil } @@ -245,7 +289,63 @@ func (r *CollectorReconciler) SetupWithManager(mgr ctrl.Manager) error { if t.Name == tenant.Name { requests = append(requests, reconcile.Request{ NamespacedName: types.NamespacedName{ - Name: c.Name, + Name: collector.Name, + }, + }) + } + } + + tenantsToDisown, err := r.getTenantsReferencingCollectorButNotSelected(ctx, &collector, tenantsForCollector) + if err != nil { + return nil + } + + for _, t := range tenantsToDisown { + if t.Name == tenant.Name { + requests = append(requests, reconcile.Request{ + NamespacedName: types.NamespacedName{ + Name: collector.Name, + }, + }) + } + } + } + + return requests + })). + Watches(&v1alpha1.Subscription{}, handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, object client.Object) []reconcile.Request { + requests := []reconcile.Request{} + subscription, _ := object.(*v1alpha1.Subscription) + + tenants := v1alpha1.TenantList{} + r.List(ctx, &tenants) + + for _, tenant := range tenants.Items { + subscriptionsForTenant, err := r.getSubscriptionsForTenant(ctx, &tenant) + if err != nil { + return nil + } + + for _, s := range subscriptionsForTenant { + if s.Name == subscription.Name { + requests = append(requests, reconcile.Request{ + NamespacedName: types.NamespacedName{ + Name: tenant.Status.Collector, + }, + }) + } + } + + subscriptionstoDisown, err := r.getSubscriptionsReferencingTenantButNotSelected(ctx, &tenant, subscriptionsForTenant) + if err != nil { + return nil + } + + for _, s := range subscriptionstoDisown { + if s.Name == subscription.Name { + requests = append(requests, reconcile.Request{ + NamespacedName: types.NamespacedName{ + Name: tenant.Status.Collector, }, }) } @@ -352,15 +452,6 @@ func (r *CollectorReconciler) reconcileClusterRole(ctx context.Context, collecto return err } -func getTenantNamesFromTenants(tenants []v1alpha1.Tenant) []string { - var tenantNames []string - for _, tenant := range tenants { - tenantNames = append(tenantNames, tenant.Name) - } - - return tenantNames -} - func getSubscriptionNamesFromSubscription(subscriptions []v1alpha1.Subscription) []v1alpha1.NamespacedName { var subscriptionNames []v1alpha1.NamespacedName for _, subscription := range subscriptions { @@ -389,6 +480,99 @@ func (r *CollectorReconciler) getTenantsMatchingSelectors(ctx context.Context, l return tenantsForSelector.Items, nil } +func (r *CollectorReconciler) getTenantsReferencingCollectorButNotSelected(ctx context.Context, collector *v1alpha1.Collector, selectedTenants []v1alpha1.Tenant) ([]v1alpha1.Tenant, error) { + var tenantsReferencing v1alpha1.TenantList + + listOpts := &client.ListOptions{ + FieldSelector: fields.OneTermEqualSelector(collectorReferenceField, collector.Name), + } + + if err := r.Client.List(ctx, &tenantsReferencing, listOpts); client.IgnoreNotFound(err) != nil { + return nil, err + } + + tenantsToDisown := []v1alpha1.Tenant{} + + for _, tenantReferencing := range tenantsReferencing.Items { + selected := false + + for _, selectedTenant := range selectedTenants { + if tenantReferencing.Name == selectedTenant.Name { + selected = true + break + } + } + + if !selected { + tenantsToDisown = append(tenantsToDisown, tenantReferencing) + } + + } + + return tenantsToDisown, nil + +} + +func (r *CollectorReconciler) disownTenants(ctx context.Context, tenantsToDisown []v1alpha1.Tenant) error { + logger := log.FromContext(ctx) + for _, tenant := range tenantsToDisown { + tenant.Status.Collector = "" + err := r.Client.Status().Update(ctx, &tenant) + if err != nil { + return err + } + logger.Info("Disowning tenant", "tenant", tenant.Name) + } + + return nil +} + +func (r *CollectorReconciler) getSubscriptionsReferencingTenantButNotSelected(ctx context.Context, tenant *v1alpha1.Tenant, selectedSubscriptions []v1alpha1.Subscription) ([]v1alpha1.Subscription, error) { + var subscriptionsReferencing v1alpha1.SubscriptionList + listOpts := &client.ListOptions{ + FieldSelector: fields.OneTermEqualSelector(tenantReferenceField, tenant.Name), + } + + if err := r.Client.List(ctx, &subscriptionsReferencing, listOpts); client.IgnoreNotFound(err) != nil { + return nil, err + } + + var subscriptionsToDisown []v1alpha1.Subscription + + for _, subscriptionReferencing := range subscriptionsReferencing.Items { + selected := false + + for _, selectedSubscription := range selectedSubscriptions { + if subscriptionReferencing.Name == selectedSubscription.Name { + selected = true + break + } + } + + if !selected { + subscriptionsToDisown = append(subscriptionsToDisown, subscriptionReferencing) + } + + } + + return subscriptionsToDisown, nil + +} + +func (r *CollectorReconciler) disownSubscriptions(ctx context.Context, subscriptionsToDisown []v1alpha1.Subscription) error { + logger := log.FromContext(ctx) + for _, subscription := range subscriptionsToDisown { + subscription.Status.Tenant = "" + err := r.Client.Status().Update(ctx, &subscription) + if err != nil { + return err + } + logger.Info("Disowning subscription", "subscription", fmt.Sprintf("%s/%s", subscription.Namespace, subscription.Name)) + } + + return nil +} + func (r *CollectorReconciler) getAllOutputs(ctx context.Context) ([]v1alpha1.OtelOutput, error) { var outputList v1alpha1.OtelOutputList @@ -400,15 +584,16 @@ func (r *CollectorReconciler) getAllOutputs(ctx context.Context) ([]v1alpha1.Ote return outputList.Items, nil } -func (r *CollectorReconciler) getSubscriptionsForTenant(ctx context.Context, tentant *v1alpha1.Tenant) ([]v1alpha1.Subscription, error) { +func (r *CollectorReconciler) getSubscriptionsForTenant(ctx context.Context, tenant *v1alpha1.Tenant) ([]v1alpha1.Subscription, error) { + logger := log.FromContext(ctx) - namespaces, err := r.getNamespacesForSelectorSlice(ctx, tentant.Spec.SubscriptionNamespaceSelectors) + namespaces, err := r.getNamespacesForSelectorSlice(ctx, tenant.Spec.SubscriptionNamespaceSelectors) if err != nil { return nil, err } - var subscriptions []v1alpha1.Subscription + var selectedSubscriptions []v1alpha1.Subscription for _, ns := range namespaces { @@ -421,11 +606,28 @@ func (r *CollectorReconciler) getSubscriptionsForTenant(ctx context.Context, ten return nil, err } - subscriptions = append(subscriptions, subscriptionsForNS.Items...) + selectedSubscriptions = append(selectedSubscriptions, subscriptionsForNS.Items...) + + } + + var validSubscriptions []v1alpha1.Subscription + + for _, subscription := range selectedSubscriptions { + if subscription.Status.Tenant != "" && subscription.Status.Tenant != tenant.Name { + logger.Error(errors.Errorf("subscription (%s) is owned by another tenant (%s), skipping reconciliation for this tenant (%s)", subscription.Name, subscription.Status.Tenant, tenant.Name), + "make sure to remove subscription from the previous tenant before adopting to new tenant") + continue + } + + subscription.Status.Tenant = tenant.Name + validSubscriptions = append(validSubscriptions, subscription) + + r.Status().Update(ctx, &subscription) + logger.Info("Setting subscription status") } - return subscriptions, nil + return validSubscriptions, nil } func (r *CollectorReconciler) getNamespacesForSelectorSlice(ctx context.Context, labelSelectors []metav1.LabelSelector) ([]apiv1.Namespace, error) { @@ -476,7 +678,6 @@ func normalizeNamespaceSlice(inputList []apiv1.Namespace) []apiv1.Namespace { } func (r *CollectorReconciler) getLogsourceNamespaceNamesForTenant(ctx context.Context, tentant *v1alpha1.Tenant) ([]string, error) { - namespaces, err := r.getNamespacesForSelectorSlice(ctx, tentant.Spec.LogSourceNamespaceSelectors) if err != nil { return nil, err From 79aefacd806043ce23eb0ebfe2cf452ccbc206bd Mon Sep 17 00:00:00 2001 From: Kristof Gyuracz Date: Tue, 30 Jan 2024 15:08:51 +0100 Subject: [PATCH 05/15] log non-critical errors, but don't fail Signed-off-by: Kristof Gyuracz --- .../telemetry/collector_controller.go | 83 +++++++++---------- 1 file changed, 38 insertions(+), 45 deletions(-) diff --git a/internal/controller/telemetry/collector_controller.go b/internal/controller/telemetry/collector_controller.go index af4eb734..849e1fff 100644 --- a/internal/controller/telemetry/collector_controller.go +++ b/internal/controller/telemetry/collector_controller.go @@ -83,15 +83,9 @@ func (r *CollectorReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( return ctrl.Result{}, err } - tenantsToDisown, err := r.getTenantsReferencingCollectorButNotSelected(ctx, collector, tenants) - if err != nil { - return ctrl.Result{}, err - } + tenantsToDisown := r.getTenantsReferencingCollectorButNotSelected(ctx, collector, tenants) - err = r.disownTenants(ctx, tenantsToDisown) - if err != nil { - return ctrl.Result{}, err - } + r.disownTenants(ctx, tenantsToDisown) tenantNames := []string{} @@ -101,7 +95,6 @@ func (r *CollectorReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( logger.Info("Setting collector status") - subscriptions := []v1alpha1.Subscription{} for _, tenant := range tenants { @@ -124,15 +117,9 @@ func (r *CollectorReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( return ctrl.Result{}, err } - subscriptionsToDisown, err := r.getSubscriptionsReferencingTenantButNotSelected(ctx, &tenant, subscriptionsForTenant) - if err != nil { - return ctrl.Result{}, err - } + subscriptionsToDisown := r.getSubscriptionsReferencingTenantButNotSelected(ctx, &tenant, subscriptionsForTenant) - err = r.disownSubscriptions(ctx, subscriptionsToDisown) - if err != nil { - return ctrl.Result{}, err - } + r.disownSubscriptions(ctx, subscriptionsToDisown) subscriptions = append(subscriptions, subscriptionsForTenant...) @@ -159,7 +146,6 @@ func (r *CollectorReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( slices.Sort(logsourceNamespacesForTenant) tenant.Status.LogSourceNamespaces = logsourceNamespacesForTenant - if err := r.Status().Update(ctx, &tenant); err != nil { return ctrl.Result{}, err } @@ -172,8 +158,11 @@ func (r *CollectorReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( collector.Status.Tenants = tenantNames - r.Status().Update(ctx, collector) logger.Info("Setting collector status") + err = r.Status().Update(ctx, collector) + if err != nil { + return ctrl.Result{}, err + } outputs, err := r.getAllOutputs(ctx) if err != nil { @@ -292,7 +281,10 @@ func (r *CollectorReconciler) SetupWithManager(mgr ctrl.Manager) error { tenant, _ := object.(*v1alpha1.Tenant) collectors := v1alpha1.CollectorList{} - r.List(ctx, &collectors) + err := r.List(ctx, &collectors) + if err != nil { + return nil + } for _, collector := range collectors.Items { tenantsForCollector, err := r.getTenantsMatchingSelectors(ctx, collector.Spec.TenantSelector) @@ -310,10 +302,7 @@ func (r *CollectorReconciler) SetupWithManager(mgr ctrl.Manager) error { } } - tenantsToDisown, err := r.getTenantsReferencingCollectorButNotSelected(ctx, &collector, tenantsForCollector) - if err != nil { - return nil - } + tenantsToDisown := r.getTenantsReferencingCollectorButNotSelected(ctx, &collector, tenantsForCollector) for _, t := range tenantsToDisown { if t.Name == tenant.Name { @@ -333,7 +322,10 @@ func (r *CollectorReconciler) SetupWithManager(mgr ctrl.Manager) error { subscription, _ := object.(*v1alpha1.Subscription) tenants := v1alpha1.TenantList{} - r.List(ctx, &tenants) + err := r.List(ctx, &tenants) + if err != nil { + return nil + } for _, tenant := range tenants.Items { subscriptionsForTenant, err := r.getSubscriptionsForTenant(ctx, &tenant) @@ -351,10 +343,7 @@ func (r *CollectorReconciler) SetupWithManager(mgr ctrl.Manager) error { } } - subscriptionstoDisown, err := r.getSubscriptionsReferencingTenantButNotSelected(ctx, &tenant, subscriptionsForTenant) - if err != nil { - return nil - } + subscriptionstoDisown := r.getSubscriptionsReferencingTenantButNotSelected(ctx, &tenant, subscriptionsForTenant) for _, s := range subscriptionstoDisown { if s.Name == subscription.Name { @@ -411,6 +400,7 @@ func (r *CollectorReconciler) reconcileServiceAccount(ctx context.Context, colle return v1alpha1.NamespacedName{Namespace: serviceAccount.Namespace, Name: serviceAccount.Name}, nil } + func (r *CollectorReconciler) reconcileClusterRoleBinding(ctx context.Context, collector *v1alpha1.Collector) error { logger := log.FromContext(ctx) @@ -473,7 +463,6 @@ func (r *CollectorReconciler) reconcileClusterRole(ctx context.Context, collecto return err } - func getSubscriptionNamesFromSubscription(subscriptions []v1alpha1.Subscription) []v1alpha1.NamespacedName { subscriptionNames := make([]v1alpha1.NamespacedName, len(subscriptions)) for i, subscription := range subscriptions { @@ -502,7 +491,8 @@ func (r *CollectorReconciler) getTenantsMatchingSelectors(ctx context.Context, l return tenantsForSelector.Items, nil } -func (r *CollectorReconciler) getTenantsReferencingCollectorButNotSelected(ctx context.Context, collector *v1alpha1.Collector, selectedTenants []v1alpha1.Tenant) ([]v1alpha1.Tenant, error) { +func (r *CollectorReconciler) getTenantsReferencingCollectorButNotSelected(ctx context.Context, collector *v1alpha1.Collector, selectedTenants []v1alpha1.Tenant) []v1alpha1.Tenant { + logger := log.FromContext(ctx) var tenantsReferencing v1alpha1.TenantList listOpts := &client.ListOptions{ @@ -510,7 +500,8 @@ func (r *CollectorReconciler) getTenantsReferencingCollectorButNotSelected(ctx c } if err := r.Client.List(ctx, &tenantsReferencing, listOpts); client.IgnoreNotFound(err) != nil { - return nil, err + logger.Error(err, "failed to list tenants that need to be detached from collector") + return nil } tenantsToDisown := []v1alpha1.Tenant{} @@ -531,32 +522,32 @@ func (r *CollectorReconciler) getTenantsReferencingCollectorButNotSelected(ctx c } - return tenantsToDisown, nil + return tenantsToDisown } -func (r *CollectorReconciler) disownTenants(ctx context.Context, tenantsToDisown []v1alpha1.Tenant) error { +func (r *CollectorReconciler) disownTenants(ctx context.Context, tenantsToDisown []v1alpha1.Tenant) { logger := log.FromContext(ctx) for _, tenant := range tenantsToDisown { tenant.Status.Collector = "" err := r.Client.Status().Update(ctx, &tenant) if err != nil { - return err + logger.Error(err, fmt.Sprintf("failed to detach tenant %s from collector", tenant.Name)) } logger.Info("Disowning tenant", "tenant", tenant.Name) } - - return nil } -func (r *CollectorReconciler) getSubscriptionsReferencingTenantButNotSelected(ctx context.Context, tenant *v1alpha1.Tenant, selectedSubscriptions []v1alpha1.Subscription) ([]v1alpha1.Subscription, error) { +func (r *CollectorReconciler) getSubscriptionsReferencingTenantButNotSelected(ctx context.Context, tenant *v1alpha1.Tenant, selectedSubscriptions []v1alpha1.Subscription) []v1alpha1.Subscription { + logger := log.FromContext(ctx) var subscriptionsReferencing v1alpha1.SubscriptionList listOpts := &client.ListOptions{ FieldSelector: fields.OneTermEqualSelector(tenantReferenceField, tenant.Name), } if err := r.Client.List(ctx, &subscriptionsReferencing, listOpts); client.IgnoreNotFound(err) != nil { - return nil, err + logger.Error(err, "failed to list subscriptions that need to be detached from tenant") + return nil } var subscriptionsToDisown []v1alpha1.Subscription @@ -577,22 +568,21 @@ func (r *CollectorReconciler) getSubscriptionsReferencingTenantButNotSelected(ct } - return subscriptionsToDisown, nil + return subscriptionsToDisown } -func (r *CollectorReconciler) disownSubscriptions(ctx context.Context, subscriptionsToDisown []v1alpha1.Subscription) error { +func (r *CollectorReconciler) disownSubscriptions(ctx context.Context, subscriptionsToDisown []v1alpha1.Subscription) { logger := log.FromContext(ctx) for _, subscription := range subscriptionsToDisown { subscription.Status.Tenant = "" err := r.Client.Status().Update(ctx, &subscription) if err != nil { - return err + logger.Error(err, fmt.Sprintf("failed to detach subscription %s/%s from collector", subscription.Namespace, subscription.Name)) } logger.Info("Disowning subscription", "subscription", fmt.Sprintf("%s/%s", subscription.Namespace, subscription.Name)) } - return nil } func (r *CollectorReconciler) getAllOutputs(ctx context.Context) ([]v1alpha1.OtelOutput, error) { @@ -632,7 +622,7 @@ func (r *CollectorReconciler) getSubscriptionsForTenant(ctx context.Context, ten } - var validSubscriptions []v1alpha1.Subscription + validSubscriptions := []v1alpha1.Subscription{} for _, subscription := range selectedSubscriptions { if subscription.Status.Tenant != "" && subscription.Status.Tenant != tenant.Name { @@ -644,8 +634,11 @@ func (r *CollectorReconciler) getSubscriptionsForTenant(ctx context.Context, ten subscription.Status.Tenant = tenant.Name validSubscriptions = append(validSubscriptions, subscription) - r.Status().Update(ctx, &subscription) logger.Info("Setting subscription status") + err := r.Status().Update(ctx, &subscription) + if err != nil { + logger.Error(err, fmt.Sprintf("failed to set subscription (%s/%s) -> tenant (%s) reference", subscription.Namespace, subscription.Name, tenant.Name)) + } } From 122806f0cbb5a1ce9e096cd2446667727ac4d30c Mon Sep 17 00:00:00 2001 From: Kristof Gyuracz Date: Tue, 30 Jan 2024 15:49:45 +0100 Subject: [PATCH 06/15] remove cross-arch builds Signed-off-by: Kristof Gyuracz --- .github/workflows/artifacts.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/artifacts.yaml b/.github/workflows/artifacts.yaml index 49bdbcb8..01c375be 100644 --- a/.github/workflows/artifacts.yaml +++ b/.github/workflows/artifacts.yaml @@ -103,12 +103,12 @@ jobs: uses: docker/build-push-action@2eb1c1961a95fc15694676618e422e8ba1d63825 # v4.1.1 with: context: . - platforms: linux/amd64,linux/arm64,linux/arm/v7 + platforms: linux/amd64 tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha cache-to: type=gha,mode=max - outputs: ${{ steps.build-output.outputs.value }},name=target,annotation-index.org.opencontainers.image.description=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.description'] }} + outputs: ${{ steps.build-output.outputs.value }},name=target # push: ${{ inputs.publish }} - name: Set image ref From 09accbb86719410f4fe9badc159aeba0fea19aa4 Mon Sep 17 00:00:00 2001 From: Kristof Gyuracz Date: Tue, 30 Jan 2024 16:07:36 +0100 Subject: [PATCH 07/15] remove duplicate assignment Signed-off-by: Kristof Gyuracz --- internal/controller/telemetry/collector_controller.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/internal/controller/telemetry/collector_controller.go b/internal/controller/telemetry/collector_controller.go index 849e1fff..1a900977 100644 --- a/internal/controller/telemetry/collector_controller.go +++ b/internal/controller/telemetry/collector_controller.go @@ -109,8 +109,6 @@ func (r *CollectorReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( tenantNames = append(tenantNames, tenant.Name) - tenant.Status.Collector = collector.Name - subscriptionsForTenant, err := r.getSubscriptionsForTenant(ctx, &tenant) if err != nil { From b08189a806ec98a1f4adf4c720a9e5d5d11f2a99 Mon Sep 17 00:00:00 2001 From: Peter Wilcsinszky Date: Wed, 31 Jan 2024 09:59:15 +0100 Subject: [PATCH 08/15] subscription update error handling Signed-off-by: Peter Wilcsinszky --- cmd/main.go | 10 +- .../telemetry/collector_controller.go | 173 ++++++++++-------- 2 files changed, 106 insertions(+), 77 deletions(-) diff --git a/cmd/main.go b/cmd/main.go index 3294704b..c280d560 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -30,11 +30,12 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log/zap" metricsserver "sigs.k8s.io/controller-runtime/pkg/metrics/server" + rbacv1 "k8s.io/api/rbac/v1" + telemetryv1alpha1 "github.com/kube-logging/subscription-operator/api/telemetry/v1alpha1" controller "github.com/kube-logging/subscription-operator/internal/controller/telemetry" - rbacv1 "k8s.io/api/rbac/v1" - //+kubebuilder:scaffold:imports + // +kubebuilder:scaffold:imports otelv1alpha1 "github.com/open-telemetry/opentelemetry-operator/apis/v1alpha1" ) @@ -51,7 +52,7 @@ func init() { utilruntime.Must(rbacv1.AddToScheme(scheme)) utilruntime.Must(telemetryv1alpha1.AddToScheme(scheme)) - //+kubebuilder:scaffold:scheme + // +kubebuilder:scaffold:scheme } func main() { @@ -77,6 +78,7 @@ func main() { HealthProbeBindAddress: probeAddr, LeaderElection: enableLeaderElection, LeaderElectionID: "87a80094.kube-logging.dev", + // LeaderElectionReleaseOnCancel defines if the leader should step down voluntarily // when the Manager ends. This requires the binary to immediately end when the // Manager is stopped, otherwise, this setting is unsafe. Setting this significantly @@ -101,7 +103,7 @@ func main() { setupLog.Error(err, "unable to create controller", "controller", "Collector") os.Exit(1) } - //+kubebuilder:scaffold:builder + // +kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { setupLog.Error(err, "unable to set up health check") diff --git a/internal/controller/telemetry/collector_controller.go b/internal/controller/telemetry/collector_controller.go index 1a900977..ed31e041 100644 --- a/internal/controller/telemetry/collector_controller.go +++ b/internal/controller/telemetry/collector_controller.go @@ -48,14 +48,14 @@ type CollectorReconciler struct { const collectorReferenceField = ".status.collector" const tenantReferenceField = ".status.tenant" -//+kubebuilder:rbac:groups=telemetry.kube-logging.dev,resources=collectors;tenants;subscriptions;oteloutputs;,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=telemetry.kube-logging.dev,resources=collectors/status;tenants/status;subscriptions/status;oteloutputs/status;,verbs=get;update;patch -//+kubebuilder:rbac:groups=telemetry.kube-logging.dev,resources=collectors/finalizers,verbs=update -//+kubebuilder:rbac:groups="",resources=nodes;namespaces;endpoints;nodes/proxy,verbs=get;list;watch -//+kubebuilder:rbac:groups="rbac.authorization.k8s.io",resources=clusterroles;clusterrolebindings;roles;rolebindings,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups="",resources=services;persistentvolumeclaims;serviceaccounts;pods,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=apps,resources=statefulsets;daemonsets;replicasets,verbs=get;list;watch;create;update;patch;delete -//+kubebuilder:rbac:groups=opentelemetry.io,resources=opentelemetrycollectors,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=telemetry.kube-logging.dev,resources=collectors;tenants;subscriptions;oteloutputs;,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=telemetry.kube-logging.dev,resources=collectors/status;tenants/status;subscriptions/status;oteloutputs/status;,verbs=get;update;patch +// +kubebuilder:rbac:groups=telemetry.kube-logging.dev,resources=collectors/finalizers,verbs=update +// +kubebuilder:rbac:groups="",resources=nodes;namespaces;endpoints;nodes/proxy,verbs=get;list;watch +// +kubebuilder:rbac:groups="rbac.authorization.k8s.io",resources=clusterroles;clusterrolebindings;roles;rolebindings,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups="",resources=services;persistentvolumeclaims;serviceaccounts;pods,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=apps,resources=statefulsets;daemonsets;replicasets,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=opentelemetry.io,resources=opentelemetrycollectors,verbs=get;list;watch;create;update;patch;delete // Reconcile is part of the main kubernetes reconciliation loop which aims to // move the current state of the cluster closer to the desired state. @@ -83,7 +83,10 @@ func (r *CollectorReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( return ctrl.Result{}, err } - tenantsToDisown := r.getTenantsReferencingCollectorButNotSelected(ctx, collector, tenants) + tenantsToDisown, err := r.getTenantsReferencingCollectorButNotSelected(ctx, collector, tenants) + if err != nil { + return ctrl.Result{}, err + } r.disownTenants(ctx, tenantsToDisown) @@ -95,7 +98,7 @@ func (r *CollectorReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( logger.Info("Setting collector status") - subscriptions := []v1alpha1.Subscription{} + allSubscriptions := []v1alpha1.Subscription{} for _, tenant := range tenants { // check if tenant is owned by us, or make it ours only if orphan @@ -109,17 +112,19 @@ func (r *CollectorReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( tenantNames = append(tenantNames, tenant.Name) - subscriptionsForTenant, err := r.getSubscriptionsForTenant(ctx, &tenant) - + subscriptionsForTenant, updateList, err := r.getSubscriptionsForTenant(ctx, &tenant) if err != nil { return ctrl.Result{}, err } + // add all newly updated subscriptions here + subscriptionsForTenant = append(subscriptionsForTenant, r.updateSubscriptionsForTenant(ctx, tenant.Name, updateList)...) + subscriptionsToDisown := r.getSubscriptionsReferencingTenantButNotSelected(ctx, &tenant, subscriptionsForTenant) r.disownSubscriptions(ctx, subscriptionsToDisown) - subscriptions = append(subscriptions, subscriptionsForTenant...) + allSubscriptions = append(allSubscriptions, subscriptionsForTenant...) subscriptionNames := getSubscriptionNamesFromSubscription(subscriptionsForTenant) @@ -169,13 +174,13 @@ func (r *CollectorReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( subscriptionOutputMap := map[v1alpha1.NamespacedName][]v1alpha1.NamespacedName{} - for _, subscription := range subscriptions { + for _, subscription := range allSubscriptions { subscriptionOutputMap[subscription.NamespacedName()] = subscription.Spec.Outputs } otelConfigInput := OtelColConfigInput{ Tenants: tenants, - Subscriptions: subscriptions, + Subscriptions: allSubscriptions, Outputs: outputs, TenantSubscriptionMap: tenantSubscriptionMap, SubscriptionOutputMap: subscriptionOutputMap, @@ -271,90 +276,102 @@ func (r *CollectorReconciler) SetupWithManager(mgr ctrl.Manager) error { }); err != nil { return err } + addCollectorRequest := func(requests []reconcile.Request, collector string) []reconcile.Request { + requests = append(requests, reconcile.Request{ + NamespacedName: types.NamespacedName{ + Name: collector, + }, + }) + return requests + } return ctrl.NewControllerManagedBy(mgr). For(&v1alpha1.Collector{}). - Watches(&v1alpha1.Tenant{}, handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, object client.Object) []reconcile.Request { - requests := []reconcile.Request{} + Watches(&v1alpha1.Tenant{}, handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, object client.Object) (requests []reconcile.Request) { + + logger := log.FromContext(ctx) + tenant, _ := object.(*v1alpha1.Tenant) collectors := v1alpha1.CollectorList{} err := r.List(ctx, &collectors) if err != nil { + logger.Error(errors.WithStack(err), "failed listing collectors for mapping requests, unable to send requests") return nil } + CollectorLoop: for _, collector := range collectors.Items { tenantsForCollector, err := r.getTenantsMatchingSelectors(ctx, collector.Spec.TenantSelector) if err != nil { - return nil + logger.Error(errors.WithStack(err), "failed listing tenants for collector, notifying collector anyways") + requests = addCollectorRequest(requests, collector.Name) + continue CollectorLoop } for _, t := range tenantsForCollector { if t.Name == tenant.Name { - requests = append(requests, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Name: collector.Name, - }, - }) + requests = addCollectorRequest(requests, collector.Name) + continue CollectorLoop } } - tenantsToDisown := r.getTenantsReferencingCollectorButNotSelected(ctx, &collector, tenantsForCollector) + tenantsToDisown, err := r.getTenantsReferencingCollectorButNotSelected(ctx, &collector, tenantsForCollector) + if err != nil { + logger.Error(errors.WithStack(err), "failed listing tenants disowned, notifying collector anyways") + requests = addCollectorRequest(requests, collector.Name) + continue CollectorLoop + } for _, t := range tenantsToDisown { if t.Name == tenant.Name { - requests = append(requests, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Name: collector.Name, - }, - }) + requests = addCollectorRequest(requests, collector.Name) + continue CollectorLoop } } } - return requests + return })). - Watches(&v1alpha1.Subscription{}, handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, object client.Object) []reconcile.Request { - requests := []reconcile.Request{} + Watches(&v1alpha1.Subscription{}, handler.EnqueueRequestsFromMapFunc(func(ctx context.Context, object client.Object) (requests []reconcile.Request) { subscription, _ := object.(*v1alpha1.Subscription) + logger := log.FromContext(ctx) + tenants := v1alpha1.TenantList{} err := r.List(ctx, &tenants) if err != nil { - return nil + logger.Error(errors.WithStack(err), "failed listing tenants for mapping requests, unable to send requests") + return } + TenantLoop: for _, tenant := range tenants.Items { - subscriptionsForTenant, err := r.getSubscriptionsForTenant(ctx, &tenant) + subscriptionsForTenant, subscriptionsToUpdate, err := r.getSubscriptionsForTenant(ctx, &tenant) if err != nil { - return nil + logger.Error(errors.WithStack(err), "failed listing subscriptions for collector, notifying collector anyways") + requests = addCollectorRequest(requests, tenant.Status.Collector) + continue TenantLoop } - for _, s := range subscriptionsForTenant { + for _, s := range append(subscriptionsForTenant, subscriptionsToUpdate...) { if s.Name == subscription.Name { - requests = append(requests, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Name: tenant.Status.Collector, - }, - }) + requests = addCollectorRequest(requests, tenant.Status.Collector) + continue TenantLoop } } - subscriptionstoDisown := r.getSubscriptionsReferencingTenantButNotSelected(ctx, &tenant, subscriptionsForTenant) + subscriptionsToDisown := r.getSubscriptionsReferencingTenantButNotSelected(ctx, &tenant, subscriptionsForTenant) - for _, s := range subscriptionstoDisown { + for _, s := range subscriptionsToDisown { if s.Name == subscription.Name { - requests = append(requests, reconcile.Request{ - NamespacedName: types.NamespacedName{ - Name: tenant.Status.Collector, - }, - }) + requests = addCollectorRequest(requests, tenant.Status.Collector) + continue TenantLoop } } } - return requests + return })). Complete(r) } @@ -489,8 +506,7 @@ func (r *CollectorReconciler) getTenantsMatchingSelectors(ctx context.Context, l return tenantsForSelector.Items, nil } -func (r *CollectorReconciler) getTenantsReferencingCollectorButNotSelected(ctx context.Context, collector *v1alpha1.Collector, selectedTenants []v1alpha1.Tenant) []v1alpha1.Tenant { - logger := log.FromContext(ctx) +func (r *CollectorReconciler) getTenantsReferencingCollectorButNotSelected(ctx context.Context, collector *v1alpha1.Collector, selectedTenants []v1alpha1.Tenant) ([]v1alpha1.Tenant, error) { var tenantsReferencing v1alpha1.TenantList listOpts := &client.ListOptions{ @@ -498,8 +514,7 @@ func (r *CollectorReconciler) getTenantsReferencingCollectorButNotSelected(ctx c } if err := r.Client.List(ctx, &tenantsReferencing, listOpts); client.IgnoreNotFound(err) != nil { - logger.Error(err, "failed to list tenants that need to be detached from collector") - return nil + return nil, err } tenantsToDisown := []v1alpha1.Tenant{} @@ -520,7 +535,7 @@ func (r *CollectorReconciler) getTenantsReferencingCollectorButNotSelected(ctx c } - return tenantsToDisown + return tenantsToDisown, nil } @@ -570,6 +585,8 @@ func (r *CollectorReconciler) getSubscriptionsReferencingTenantButNotSelected(ct } +// disownSubscriptions fails internally by logging errors individually +// this is by design so that we don't fail the whole reconciliation when a single subscription update fails func (r *CollectorReconciler) disownSubscriptions(ctx context.Context, subscriptionsToDisown []v1alpha1.Subscription) { logger := log.FromContext(ctx) for _, subscription := range subscriptionsToDisown { @@ -577,10 +594,10 @@ func (r *CollectorReconciler) disownSubscriptions(ctx context.Context, subscript err := r.Client.Status().Update(ctx, &subscription) if err != nil { logger.Error(err, fmt.Sprintf("failed to detach subscription %s/%s from collector", subscription.Namespace, subscription.Name)) + } else { + logger.Info("disowning subscription", "subscription", fmt.Sprintf("%s/%s", subscription.Namespace, subscription.Name)) } - logger.Info("Disowning subscription", "subscription", fmt.Sprintf("%s/%s", subscription.Namespace, subscription.Name)) } - } func (r *CollectorReconciler) getAllOutputs(ctx context.Context) ([]v1alpha1.OtelOutput, error) { @@ -594,34 +611,48 @@ func (r *CollectorReconciler) getAllOutputs(ctx context.Context) ([]v1alpha1.Ote return outputList.Items, nil } -func (r *CollectorReconciler) getSubscriptionsForTenant(ctx context.Context, tenant *v1alpha1.Tenant) ([]v1alpha1.Subscription, error) { +// updateSubscriptionsForTenant fails internally and logs failures individually +// this is by design in order to avoid blocking the whole reconciliation in case we cannot update a single subscription +func (r *CollectorReconciler) updateSubscriptionsForTenant(ctx context.Context, tenantName string, subscriptions []v1alpha1.Subscription) (updatedSubscriptions []v1alpha1.Subscription) { + logger := log.FromContext(ctx, "tenant", tenantName) + for _, subscription := range subscriptions { + subscription.Status.Tenant = tenantName + + logger.Info("updating subscription status for tenant ownership") + err := r.Status().Update(ctx, &subscription) + if err != nil { + logger.Error(err, fmt.Sprintf("failed to set subscription (%s/%s) -> tenant (%s) reference", subscription.Namespace, subscription.Name, tenantName)) + } else { + updatedSubscriptions = append(updatedSubscriptions, subscription) + } + } + return +} + +func (r *CollectorReconciler) getSubscriptionsForTenant(ctx context.Context, tenant *v1alpha1.Tenant) (ownedList []v1alpha1.Subscription, updateList []v1alpha1.Subscription, err error) { logger := log.FromContext(ctx) namespaces, err := r.getNamespacesForSelectorSlice(ctx, tenant.Spec.SubscriptionNamespaceSelectors) if err != nil { - return nil, err + return nil, nil, err } var selectedSubscriptions []v1alpha1.Subscription for _, ns := range namespaces { - var subscriptionsForNS v1alpha1.SubscriptionList listOpts := &client.ListOptions{ Namespace: ns.Name, } if err := r.List(ctx, &subscriptionsForNS, listOpts); client.IgnoreNotFound(err) != nil { - return nil, err + return nil, nil, err } selectedSubscriptions = append(selectedSubscriptions, subscriptionsForNS.Items...) - } - validSubscriptions := []v1alpha1.Subscription{} - for _, subscription := range selectedSubscriptions { if subscription.Status.Tenant != "" && subscription.Status.Tenant != tenant.Name { logger.Error(errors.Errorf("subscription (%s) is owned by another tenant (%s), skipping reconciliation for this tenant (%s)", subscription.Name, subscription.Status.Tenant, tenant.Name), @@ -629,18 +660,14 @@ func (r *CollectorReconciler) getSubscriptionsForTenant(ctx context.Context, ten continue } - subscription.Status.Tenant = tenant.Name - validSubscriptions = append(validSubscriptions, subscription) - - logger.Info("Setting subscription status") - err := r.Status().Update(ctx, &subscription) - if err != nil { - logger.Error(err, fmt.Sprintf("failed to set subscription (%s/%s) -> tenant (%s) reference", subscription.Namespace, subscription.Name, tenant.Name)) + if subscription.Status.Tenant == "" { + updateList = append(updateList, subscription) + } else { + ownedList = append(ownedList, subscription) } - } - return validSubscriptions, nil + return } func (r *CollectorReconciler) getNamespacesForSelectorSlice(ctx context.Context, labelSelectors []metav1.LabelSelector) ([]apiv1.Namespace, error) { @@ -667,7 +694,7 @@ func (r *CollectorReconciler) getNamespacesForSelectorSlice(ctx context.Context, namespaces = append(namespaces, namespacesForSelector.Items...) } - normalizeNamespaceSlice(namespaces) + namespaces = normalizeNamespaceSlice(namespaces) return namespaces, nil } From ccf519c63698d143fb28f86aca74ebc3c9d3e391 Mon Sep 17 00:00:00 2001 From: Kristof Gyuracz Date: Wed, 31 Jan 2024 17:15:28 +0100 Subject: [PATCH 09/15] handle subscriptions whose tenants don't have a collector Signed-off-by: Kristof Gyuracz --- .../controller/telemetry/collector_controller.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/internal/controller/telemetry/collector_controller.go b/internal/controller/telemetry/collector_controller.go index ed31e041..aaad89d6 100644 --- a/internal/controller/telemetry/collector_controller.go +++ b/internal/controller/telemetry/collector_controller.go @@ -350,13 +350,17 @@ func (r *CollectorReconciler) SetupWithManager(mgr ctrl.Manager) error { subscriptionsForTenant, subscriptionsToUpdate, err := r.getSubscriptionsForTenant(ctx, &tenant) if err != nil { logger.Error(errors.WithStack(err), "failed listing subscriptions for collector, notifying collector anyways") - requests = addCollectorRequest(requests, tenant.Status.Collector) + if tenant.Status.Collector != "" { + requests = addCollectorRequest(requests, tenant.Status.Collector) + } continue TenantLoop } for _, s := range append(subscriptionsForTenant, subscriptionsToUpdate...) { if s.Name == subscription.Name { - requests = addCollectorRequest(requests, tenant.Status.Collector) + if tenant.Status.Collector != "" { + requests = addCollectorRequest(requests, tenant.Status.Collector) + } continue TenantLoop } } @@ -365,7 +369,9 @@ func (r *CollectorReconciler) SetupWithManager(mgr ctrl.Manager) error { for _, s := range subscriptionsToDisown { if s.Name == subscription.Name { - requests = addCollectorRequest(requests, tenant.Status.Collector) + if tenant.Status.Collector != "" { + requests = addCollectorRequest(requests, tenant.Status.Collector) + } continue TenantLoop } } From 8e67060109fc5a7551e57cd68c31915cfe3efd61 Mon Sep 17 00:00:00 2001 From: Kristof Gyuracz Date: Wed, 31 Jan 2024 17:21:00 +0100 Subject: [PATCH 10/15] remove nakedreturn check, handle orphan tenants Signed-off-by: Kristof Gyuracz --- .golangci.yml | 1 - .../controller/telemetry/collector_controller.go | 15 ++++++--------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index aed8644d..7901da5b 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -31,7 +31,6 @@ linters: - ineffassign - lll - misspell - - nakedret - prealloc - staticcheck - typecheck diff --git a/internal/controller/telemetry/collector_controller.go b/internal/controller/telemetry/collector_controller.go index aaad89d6..61e632d7 100644 --- a/internal/controller/telemetry/collector_controller.go +++ b/internal/controller/telemetry/collector_controller.go @@ -347,20 +347,19 @@ func (r *CollectorReconciler) SetupWithManager(mgr ctrl.Manager) error { TenantLoop: for _, tenant := range tenants.Items { + if tenant.Status.Collector == "" { + logger.Error(errors.WithStack(err), fmt.Sprintf("tenant %s is orphan, skipping it, and its subscriptions when looking for changes", tenant.Name)) + } subscriptionsForTenant, subscriptionsToUpdate, err := r.getSubscriptionsForTenant(ctx, &tenant) if err != nil { logger.Error(errors.WithStack(err), "failed listing subscriptions for collector, notifying collector anyways") - if tenant.Status.Collector != "" { - requests = addCollectorRequest(requests, tenant.Status.Collector) - } + requests = addCollectorRequest(requests, tenant.Status.Collector) continue TenantLoop } for _, s := range append(subscriptionsForTenant, subscriptionsToUpdate...) { if s.Name == subscription.Name { - if tenant.Status.Collector != "" { - requests = addCollectorRequest(requests, tenant.Status.Collector) - } + requests = addCollectorRequest(requests, tenant.Status.Collector) continue TenantLoop } } @@ -369,9 +368,7 @@ func (r *CollectorReconciler) SetupWithManager(mgr ctrl.Manager) error { for _, s := range subscriptionsToDisown { if s.Name == subscription.Name { - if tenant.Status.Collector != "" { - requests = addCollectorRequest(requests, tenant.Status.Collector) - } + requests = addCollectorRequest(requests, tenant.Status.Collector) continue TenantLoop } } From d286892143ca03e780a5d96bb11b80dfc5ee8523 Mon Sep 17 00:00:00 2001 From: Kristof Gyuracz Date: Wed, 31 Jan 2024 18:27:29 +0100 Subject: [PATCH 11/15] add two-collector example Signed-off-by: Kristof Gyuracz --- .../two_tenants_one_subscription_each.yaml | 110 ++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 docs/examples/two_tenants_one_subscription_each.yaml diff --git a/docs/examples/two_tenants_one_subscription_each.yaml b/docs/examples/two_tenants_one_subscription_each.yaml new file mode 100644 index 00000000..e7c9bf47 --- /dev/null +++ b/docs/examples/two_tenants_one_subscription_each.yaml @@ -0,0 +1,110 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: collector +--- +apiVersion: v1 +kind: Namespace +metadata: + labels: + nsSelector: example-tenant-1 + name: example-tenant-ns-1 +--- +apiVersion: v1 +kind: Namespace +metadata: + labels: + nsSelector: example-tenant-2 + name: example-tenant-ns-2 +--- +apiVersion: telemetry.kube-logging.dev/v1alpha1 +kind: Collector +metadata: + name: example-collector-1 +spec: + controlNamespace: collector + tenantSelector: + matchLabels: + collectorLabel: example-collector-1 +--- +apiVersion: telemetry.kube-logging.dev/v1alpha1 +kind: Collector +metadata: + name: example-collector-2 +spec: + controlNamespace: collector + tenantSelector: + matchLabels: + collectorLabel: example-collector-2 +--- +apiVersion: telemetry.kube-logging.dev/v1alpha1 +kind: Tenant +metadata: + labels: + collectorLabel: example-collector-1 + name: example-tenant-1 +spec: + subscriptionNamespaceSelectors: + - matchLabels: + nsSelector: example-tenant-1 + logSourceNamespaceSelectors: + - matchLabels: + nsSelector: example-tenant-1 +--- +apiVersion: telemetry.kube-logging.dev/v1alpha1 +kind: Tenant +metadata: + labels: + collectorLabel: example-collector-2 + name: example-tenant-2 +spec: + subscriptionNamespaceSelectors: + - matchLabels: + nsSelector: example-tenant-2 + logSourceNamespaceSelectors: + - matchLabels: + nsSelector: example-tenant-2 +--- +apiVersion: telemetry.kube-logging.dev/v1alpha1 +kind: Subscription +metadata: + name: subscription-sample-1 + namespace: example-tenant-ns-1 +spec: + ottl: 'route()' + outputs: + - name: otlp-test-output-1 + namespace: collector +--- +apiVersion: telemetry.kube-logging.dev/v1alpha1 +kind: Subscription +metadata: + name: subscription-sample-2 + namespace: example-tenant-ns-2 +spec: + ottl: 'route()' + outputs: + - name: otlp-test-output-2 + namespace: collector +--- +apiVersion: telemetry.kube-logging.dev/v1alpha1 +kind: OtelOutput +metadata: + name: otlp-test-output-1 + namespace: collector +spec: + otlp: + endpoint: receiver-collector.example-tenant-ns.svc.cluster.local:4317 + tls: + insecure: true +--- +apiVersion: telemetry.kube-logging.dev/v1alpha1 +kind: OtelOutput +metadata: + name: otlp-test-output-2 + namespace: collector +spec: + otlp: + endpoint: receiver-collector.example-tenant-ns.svc.cluster.local:4317 + tls: + insecure: true From 383fda159b7ac60e284b1cf8e80ff4dd5523e4ba Mon Sep 17 00:00:00 2001 From: Peter Wilcsinszky Date: Thu, 1 Feb 2024 08:56:24 +0100 Subject: [PATCH 12/15] update tenant status only if changed Signed-off-by: Peter Wilcsinszky --- .../controller/telemetry/collector_controller.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/internal/controller/telemetry/collector_controller.go b/internal/controller/telemetry/collector_controller.go index 61e632d7..4618b8b3 100644 --- a/internal/controller/telemetry/collector_controller.go +++ b/internal/controller/telemetry/collector_controller.go @@ -17,6 +17,7 @@ package telemetry import ( "context" "fmt" + "reflect" "strings" "emperror.dev/errors" @@ -101,9 +102,10 @@ func (r *CollectorReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( allSubscriptions := []v1alpha1.Subscription{} for _, tenant := range tenants { + originalTenantStatus := tenant.Status.DeepCopy() + // check if tenant is owned by us, or make it ours only if orphan // this update will connect the tenant and collector exclusively - if tenant.Status.Collector != "" && tenant.Status.Collector != collector.Name { logger.Error(errors.Errorf("tenant (%s) is owned by another collector (%s), skipping reconciliation for this collector (%s)", tenant.Name, tenant.Status.Collector, collector.Name), "make sure to remove tenant from the previous collector before adopting to new collector") @@ -149,12 +151,12 @@ func (r *CollectorReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( slices.Sort(logsourceNamespacesForTenant) tenant.Status.LogSourceNamespaces = logsourceNamespacesForTenant - if err := r.Status().Update(ctx, &tenant); err != nil { - return ctrl.Result{}, err + if !reflect.DeepEqual(*originalTenantStatus, tenant.Status) { + logger.Info("updating tenant tenant status") + if err := r.Status().Update(ctx, &tenant); err != nil { + return ctrl.Result{}, err + } } - - logger.Info("Setting tenant status") - } slices.Sort(tenantNames) From 1b1460c9012b74918ae63ab7e9a3ed1d0cdca284 Mon Sep 17 00:00:00 2001 From: Peter Wilcsinszky Date: Thu, 1 Feb 2024 08:59:21 +0100 Subject: [PATCH 13/15] update collector only if changed Signed-off-by: Peter Wilcsinszky --- .../controller/telemetry/collector_controller.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/internal/controller/telemetry/collector_controller.go b/internal/controller/telemetry/collector_controller.go index 4618b8b3..f2a2c374 100644 --- a/internal/controller/telemetry/collector_controller.go +++ b/internal/controller/telemetry/collector_controller.go @@ -78,6 +78,8 @@ func (r *CollectorReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( return ctrl.Result{}, err } + originalCollectorStatus := collector.Status.DeepCopy() + tenantSubscriptionMap := make(map[v1alpha1.NamespacedName][]v1alpha1.NamespacedName) tenants, err := r.getTenantsMatchingSelectors(ctx, collector.Spec.TenantSelector) if err != nil { @@ -163,10 +165,12 @@ func (r *CollectorReconciler) Reconcile(ctx context.Context, req ctrl.Request) ( collector.Status.Tenants = tenantNames - logger.Info("Setting collector status") - err = r.Status().Update(ctx, collector) - if err != nil { - return ctrl.Result{}, err + if reflect.DeepEqual(*originalCollectorStatus, collector.Status) { + logger.Info("updating collector status") + err = r.Status().Update(ctx, collector) + if err != nil { + return ctrl.Result{}, err + } } outputs, err := r.getAllOutputs(ctx) From 2613f5b9493ec9ec2ab4aed149a85419ca178158 Mon Sep 17 00:00:00 2001 From: Peter Wilcsinszky Date: Thu, 1 Feb 2024 08:59:48 +0100 Subject: [PATCH 14/15] keep the build for arm64 Signed-off-by: Peter Wilcsinszky --- .github/workflows/artifacts.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/artifacts.yaml b/.github/workflows/artifacts.yaml index 01c375be..c72cf713 100644 --- a/.github/workflows/artifacts.yaml +++ b/.github/workflows/artifacts.yaml @@ -103,7 +103,7 @@ jobs: uses: docker/build-push-action@2eb1c1961a95fc15694676618e422e8ba1d63825 # v4.1.1 with: context: . - platforms: linux/amd64 + platforms: linux/amd64,linux/arm64 tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha From 4bd14ce20555a02e7996487e1aa5a9f014e6a1e8 Mon Sep 17 00:00:00 2001 From: Kristof Gyuracz Date: Thu, 1 Feb 2024 14:19:38 +0100 Subject: [PATCH 15/15] Revert "remove unnecessary variable" This reverts commit 71834f82c4b2254979aa9741653188e9295ed6bc. Signed-off-by: Kristof Gyuracz --- internal/controller/telemetry/collector_controller.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/controller/telemetry/collector_controller.go b/internal/controller/telemetry/collector_controller.go index f2a2c374..cf4900dd 100644 --- a/internal/controller/telemetry/collector_controller.go +++ b/internal/controller/telemetry/collector_controller.go @@ -712,7 +712,7 @@ func normalizeNamespaceSlice(inputList []apiv1.Namespace) []apiv1.Namespace { allKeys := make(map[string]bool) uniqueList := []apiv1.Namespace{} for _, item := range inputList { - if allKeys[item.Name] { + if _, value := allKeys[item.Name]; !value { allKeys[item.Name] = true uniqueList = append(uniqueList, item) }