diff --git a/charts/logging-operator/charts/logging-operator-crds/templates/logging.banzaicloud.io_loggings.yaml b/charts/logging-operator/charts/logging-operator-crds/templates/logging.banzaicloud.io_loggings.yaml index 9402b8534..353b8a8c2 100644 --- a/charts/logging-operator/charts/logging-operator-crds/templates/logging.banzaicloud.io_loggings.yaml +++ b/charts/logging-operator/charts/logging-operator-crds/templates/logging.banzaicloud.io_loggings.yaml @@ -69,6 +69,9 @@ spec: properties: allowClusterResourcesFromAllNamespaces: type: boolean + x-kubernetes-validations: + - message: Value is immutable, please recreate the resource + rule: self == oldSelf clusterDomain: type: string configCheck: diff --git a/charts/logging-operator/crds/logging.banzaicloud.io_loggings.yaml b/charts/logging-operator/crds/logging.banzaicloud.io_loggings.yaml index 0c28a6aef..e51d0cf6b 100644 --- a/charts/logging-operator/crds/logging.banzaicloud.io_loggings.yaml +++ b/charts/logging-operator/crds/logging.banzaicloud.io_loggings.yaml @@ -66,6 +66,9 @@ spec: properties: allowClusterResourcesFromAllNamespaces: type: boolean + x-kubernetes-validations: + - message: Value is immutable, please recreate the resource + rule: self == oldSelf clusterDomain: type: string configCheck: diff --git a/config/crd/bases/logging.banzaicloud.io_loggings.yaml b/config/crd/bases/logging.banzaicloud.io_loggings.yaml index 0c28a6aef..e51d0cf6b 100644 --- a/config/crd/bases/logging.banzaicloud.io_loggings.yaml +++ b/config/crd/bases/logging.banzaicloud.io_loggings.yaml @@ -66,6 +66,9 @@ spec: properties: allowClusterResourcesFromAllNamespaces: type: boolean + x-kubernetes-validations: + - message: Value is immutable, please recreate the resource + rule: self == oldSelf clusterDomain: type: string configCheck: diff --git a/docs/configuration/crds/v1beta1/logging_types.md b/docs/configuration/crds/v1beta1/logging_types.md index b3ce30ad4..32e66e32e 100644 --- a/docs/configuration/crds/v1beta1/logging_types.md +++ b/docs/configuration/crds/v1beta1/logging_types.md @@ -10,7 +10,7 @@ LoggingSpec defines the desired state of Logging ### allowClusterResourcesFromAllNamespaces (bool, optional) {#loggingspec-allowclusterresourcesfromallnamespaces} -Allow configuration of cluster resources from any namespace. Mutually exclusive with ControlNamespace restriction of Cluster resources +Allow configuration of cluster resources from any namespace. Mutually exclusive with ControlNamespace restriction of Cluster resources WARNING: Becareful when turning this on and off as it can result in some resources being orphaned. ### clusterDomain (*string, optional) {#loggingspec-clusterdomain} diff --git a/pkg/resources/model/reconciler.go b/pkg/resources/model/reconciler.go index 1e60dba92..121282d1b 100644 --- a/pkg/resources/model/reconciler.go +++ b/pkg/resources/model/reconciler.go @@ -120,13 +120,19 @@ func NewValidationReconciler( } for _, ref := range flow.Spec.GlobalOutputRefs { - if output := resources.Fluentd.ClusterOutputs.FindByName(ref); output != nil { + switch output := resources.Fluentd.ClusterOutputs.FindByName(ref); { + case output == nil: + flow.Status.Problems = append(flow.Status.Problems, fmt.Sprintf("dangling global output reference: %s", ref)) + + case output.Status.ProblemsCount > 0: + flow.Status.Problems = append(flow.Status.Problems, fmt.Sprintf("global output reference: %s has problems", output.Name)) + + default: flow.Status.Active = utils.BoolPointer(true) output.Status.Active = utils.BoolPointer(true) - } else { - flow.Status.Problems = append(flow.Status.Problems, fmt.Sprintf("dangling global output reference: %s", ref)) } } + flow.Status.ProblemsCount = len(flow.Status.Problems) } @@ -146,11 +152,12 @@ func NewValidationReconciler( switch output := resources.Fluentd.ClusterOutputs.FindByName(ref); { case output == nil: flow.Status.Problems = append(flow.Status.Problems, fmt.Sprintf("dangling global output reference: %s", ref)) - continue case output.Spec.Protected: flow.Status.Problems = append(flow.Status.Problems, fmt.Sprintf("global output reference is protected: %s", ref)) - continue + + case output.Status.ProblemsCount > 0: + flow.Status.Problems = append(flow.Status.Problems, fmt.Sprintf("global output reference: %s has problems", output.Name)) default: output.Status.Active = utils.BoolPointer(true) @@ -159,11 +166,16 @@ func NewValidationReconciler( } for _, ref := range flow.Spec.LocalOutputRefs { - if output := resources.Fluentd.Outputs.FindByNamespacedName(flow.Namespace, ref); output != nil { + switch output := resources.Fluentd.Outputs.FindByNamespacedName(flow.Namespace, ref); { + case output == nil: + flow.Status.Problems = append(flow.Status.Problems, fmt.Sprintf("dangling local output reference: %s", ref)) + + case output.Status.ProblemsCount > 0: + flow.Status.Problems = append(flow.Status.Problems, fmt.Sprintf("local output reference: %s has problems", output.Name)) + + default: output.Status.Active = utils.BoolPointer(true) hasValidOutput = true - } else { - flow.Status.Problems = append(flow.Status.Problems, fmt.Sprintf("dangling local output reference: %s", ref)) } } @@ -185,13 +197,19 @@ func NewValidationReconciler( flow.Status.Problems = nil for _, ref := range flow.Spec.GlobalOutputRefs { - if output := resources.SyslogNG.ClusterOutputs.FindByName(ref); output != nil { + switch output := resources.SyslogNG.ClusterOutputs.FindByName(ref); { + case output == nil: + flow.Status.Problems = append(flow.Status.Problems, fmt.Sprintf("dangling global output reference: %s", ref)) + + case output.Status.ProblemsCount > 0: + flow.Status.Problems = append(flow.Status.Problems, fmt.Sprintf("global output reference: %s has problems", output.Name)) + + default: flow.Status.Active = utils.BoolPointer(true) output.Status.Active = utils.BoolPointer(true) - } else { - flow.Status.Problems = append(flow.Status.Problems, fmt.Sprintf("dangling global output reference: %s", ref)) } } + flow.Status.ProblemsCount = len(flow.Status.Problems) } @@ -207,11 +225,12 @@ func NewValidationReconciler( switch output := resources.SyslogNG.ClusterOutputs.FindByName(ref); { case output == nil: flow.Status.Problems = append(flow.Status.Problems, fmt.Sprintf("dangling global output reference: %s", ref)) - continue case output.Spec.Protected: flow.Status.Problems = append(flow.Status.Problems, fmt.Sprintf("global output reference is protected: %s", ref)) - continue + + case output.Status.ProblemsCount > 0: + flow.Status.Problems = append(flow.Status.Problems, fmt.Sprintf("global output reference: %s has problems", output.Name)) default: output.Status.Active = utils.BoolPointer(true) @@ -220,11 +239,16 @@ func NewValidationReconciler( } for _, ref := range flow.Spec.LocalOutputRefs { - if output := resources.SyslogNG.Outputs.FindByNamespacedName(flow.Namespace, ref); output != nil { + switch output := resources.SyslogNG.Outputs.FindByNamespacedName(flow.Namespace, ref); { + case output == nil: + flow.Status.Problems = append(flow.Status.Problems, fmt.Sprintf("dangling local output reference: %s", ref)) + + case output.Status.ProblemsCount > 0: + flow.Status.Problems = append(flow.Status.Problems, fmt.Sprintf("local output reference: %s has problems", output.Name)) + + default: output.Status.Active = utils.BoolPointer(true) hasValidOutput = true - } else { - flow.Status.Problems = append(flow.Status.Problems, fmt.Sprintf("dangling local output reference: %s", ref)) } } @@ -313,6 +337,8 @@ func NewValidationReconciler( if !resources.Logging.WatchAllNamespaces() { resources.Logging.Status.WatchNamespaces = resources.WatchNamespaces + } else { + resources.Logging.Status.WatchNamespaces = []string{"*"} } if resources.Logging.Spec.WatchNamespaceSelector != nil && diff --git a/pkg/resources/model/repository.go b/pkg/resources/model/repository.go index 8d5579371..1d4603737 100644 --- a/pkg/resources/model/repository.go +++ b/pkg/resources/model/repository.go @@ -113,6 +113,8 @@ func (r LoggingResourceRepository) LoggingResourcesFor(ctx context.Context, logg return } +// UniqueWatchNamespaces returns the unique list of namespaces to watch for a logging resource. +// if both watchNamespaces and watchNamespaceSelector are empty, it returns all namespaces. func UniqueWatchNamespaces(ctx context.Context, reader client.Reader, logging *v1beta1.Logging) ([]string, error) { watchNamespaces := logging.Spec.WatchNamespaces nsLabelSelector := logging.Spec.WatchNamespaceSelector diff --git a/pkg/sdk/logging/api/v1beta1/logging_types.go b/pkg/sdk/logging/api/v1beta1/logging_types.go index b3908d995..201616b29 100644 --- a/pkg/sdk/logging/api/v1beta1/logging_types.go +++ b/pkg/sdk/logging/api/v1beta1/logging_types.go @@ -80,7 +80,11 @@ type LoggingSpec struct { // This should be a protected namespace from regular users. // Resources like fluentbit and fluentd will run in this namespace as well. ControlNamespace string `json:"controlNamespace"` + + // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Value is immutable, please recreate the resource" + // Allow configuration of cluster resources from any namespace. Mutually exclusive with ControlNamespace restriction of Cluster resources + // WARNING: Becareful when turning this on and off as it can result in some resources being orphaned. AllowClusterResourcesFromAllNamespaces bool `json:"allowClusterResourcesFromAllNamespaces,omitempty"` // InlineNodeAgent Configuration // Deprecated, will be removed with next major version