From 690f17d1031fe871928222c54c6be51e23dba2d0 Mon Sep 17 00:00:00 2001 From: Mohamed-Amine Bouqsimi Date: Thu, 27 Apr 2023 11:59:58 +0200 Subject: [PATCH 01/23] operator: Add zone awareness spec to LokiStack --- operator/apis/loki/v1/lokistack_types.go | 46 +++- operator/apis/loki/v1/v1.go | 6 + .../apis/loki/v1/zz_generated.deepcopy.go | 40 ++++ .../loki-operator.clusterserviceversion.yaml | 31 ++- .../loki.grafana.com_lokistacks.yaml | 40 +++- .../loki-operator.clusterserviceversion.yaml | 31 ++- .../loki.grafana.com_lokistacks.yaml | 40 +++- .../loki-operator.clusterserviceversion.yaml | 31 ++- .../loki.grafana.com_lokistacks.yaml | 40 +++- .../bases/loki.grafana.com_lokistacks.yaml | 40 +++- .../loki-operator.clusterserviceversion.yaml | 29 ++- .../loki-operator.clusterserviceversion.yaml | 29 ++- .../loki-operator.clusterserviceversion.yaml | 29 ++- operator/internal/manifests/build_test.go | 1 + operator/internal/manifests/config.go | 9 + operator/internal/manifests/config_test.go | 104 ++++++++- operator/internal/manifests/distributor.go | 4 + .../internal/manifests/distributor_test.go | 41 ++++ operator/internal/manifests/ingester.go | 5 + operator/internal/manifests/ingester_test.go | 41 ++++ .../manifests/internal/config/build_test.go | 44 +++- .../internal/config/loki-config.yaml | 2 +- operator/internal/manifests/internal/sizes.go | 24 +- operator/internal/manifests/querier.go | 4 + operator/internal/manifests/querier_test.go | 41 ++++ operator/internal/manifests/query-frontend.go | 4 + .../internal/manifests/query-frontend_test.go | 41 ++++ operator/internal/manifests/var.go | 17 ++ operator/internal/validation/lokistack.go | 74 ++++++ .../internal/validation/lokistack_test.go | 217 +++++++++++++++++- operator/main.go | 4 +- 31 files changed, 1047 insertions(+), 62 deletions(-) diff --git a/operator/apis/loki/v1/lokistack_types.go b/operator/apis/loki/v1/lokistack_types.go index 4eeddec2b7a05..a106c0cbcf0c2 100644 --- a/operator/apis/loki/v1/lokistack_types.go +++ b/operator/apis/loki/v1/lokistack_types.go @@ -766,6 +766,7 @@ type LokiStackSpec struct { // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Cluster Proxy" Proxy *ClusterProxy `json:"proxy,omitempty"` + // Deprecated: Please use replication.factor instead. This field will be removed in future versions of this CRD. // ReplicationFactor defines the policy for log stream replication. // // +optional @@ -774,7 +775,14 @@ type LokiStackSpec struct { // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors="urn:alm:descriptor:com.tectonic.ui:number",displayName="Replication Factor" ReplicationFactor int32 `json:"replicationFactor,omitempty"` - // Rules defines the spec for the ruler component + // Replication defines the configuration for Loki data replication. + // + // +optional + // +kubebuilder:validation:Optional + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Replication Spec" + Replication *ReplicationSpec `json:"replication,omitempty"` + + // Rules defines the spec for the ruler component. // // +optional // +kubebuilder:validation:Optional @@ -788,7 +796,7 @@ type LokiStackSpec struct { // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors="urn:alm:descriptor:com.tectonic.ui:advanced",displayName="Rate Limiting" Limits *LimitsSpec `json:"limits,omitempty"` - // Template defines the resource/limits/tolerations/nodeselectors per component + // Template defines the resource/limits/tolerations/nodeselectors per component. // // +optional // +kubebuilder:validation:Optional @@ -803,6 +811,40 @@ type LokiStackSpec struct { Tenants *TenantsSpec `json:"tenants,omitempty"` } +type ReplicationSpec struct { + // Factor defines the policy for log stream replication. + // + // +optional + // +kubebuilder:validation:Optional + // +kubebuilder:validation:Minimum:=1 + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors="urn:alm:descriptor:com.tectonic.ui:number",displayName="Replication Factor" + Factor int32 `json:"factor,omitempty"` + + // Zone is the key that defines a topology in the Nodes' labels. + // + // +required + // +kubebuilder:validation:Required + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Zones Spec" + Zones []ZoneSpec `json:"zones"` +} + +// ZoneSpec defines the spec to support zone-aware component deployments. +type ZoneSpec struct { + // MaxSkew describes the maximum degree to which Pods can be unevenly distributed. + // + // +required + // +kubebuilder:default:=1 + // +operator-sdk:csv:customresourcedefinitions:type=spec,xDescriptors="urn:alm:descriptor:com.tectonic.ui:number",displayName="Max Skew" + MaxSkew int `json:"maxSkew"` + + // TopologyKey is the key that defines a topology in the Nodes' labels. + // + // +required + // +kubebuilder:validation:Required + // +operator-sdk:csv:customresourcedefinitions:type=spec,displayName="Topology Key" + TopologyKey string `json:"topologyKey"` +} + // LokiStackConditionType deifnes the type of condition types of a Loki deployment. type LokiStackConditionType string diff --git a/operator/apis/loki/v1/v1.go b/operator/apis/loki/v1/v1.go index 219edcedd8320..4863cd693623b 100644 --- a/operator/apis/loki/v1/v1.go +++ b/operator/apis/loki/v1/v1.go @@ -57,6 +57,12 @@ var ( ErrSchemaRetroactivelyChanged = errors.New("Cannot retroactively change schema") // ErrHeaderAuthCredentialsConflict when both Credentials and CredentialsFile are used in a header authentication client. ErrHeaderAuthCredentialsConflict = errors.New("credentials and credentialsFile cannot be used at the same time") + // ErrReplicationZonesNodes when there is an error retrieving nodes with replication zones labels. + ErrReplicationZonesNodes = errors.New("Failed to retrieve nodes for zone replication") + // ErrReplicationFactorToZonesRatio when the replication factor defined is greater than the number of available zones. + ErrReplicationFactorToZonesRatio = errors.New("replication factor is greater than the number of available zones") + // ErrReplicationSpecConflict when both the ReplicationSpec and depricated ReplicationFactor are used. + ErrReplicationSpecConflict = errors.New("replicationSpec and replicationFactor (deprecated) cannot be used at the same time") // ErrRuleMustMatchNamespace indicates that an expression used in an alerting or recording rule is missing // matchers for a namespace. diff --git a/operator/apis/loki/v1/zz_generated.deepcopy.go b/operator/apis/loki/v1/zz_generated.deepcopy.go index d30a5b8bfeef0..9eba6833e012e 100644 --- a/operator/apis/loki/v1/zz_generated.deepcopy.go +++ b/operator/apis/loki/v1/zz_generated.deepcopy.go @@ -770,6 +770,11 @@ func (in *LokiStackSpec) DeepCopyInto(out *LokiStackSpec) { *out = new(ClusterProxy) **out = **in } + if in.Replication != nil { + in, out := &in.Replication, &out.Replication + *out = new(ReplicationSpec) + (*in).DeepCopyInto(*out) + } if in.Rules != nil { in, out := &in.Rules, &out.Rules *out = new(RulesSpec) @@ -1303,6 +1308,26 @@ func (in *RemoteWriteSpec) DeepCopy() *RemoteWriteSpec { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReplicationSpec) DeepCopyInto(out *ReplicationSpec) { + *out = *in + if in.Zones != nil { + in, out := &in.Zones, &out.Zones + *out = make([]ZoneSpec, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReplicationSpec. +func (in *ReplicationSpec) DeepCopy() *ReplicationSpec { + if in == nil { + return nil + } + out := new(ReplicationSpec) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *RetentionLimitSpec) DeepCopyInto(out *RetentionLimitSpec) { *out = *in @@ -1613,3 +1638,18 @@ func (in *TenantsSpec) DeepCopy() *TenantsSpec { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ZoneSpec) DeepCopyInto(out *ZoneSpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ZoneSpec. +func (in *ZoneSpec) DeepCopy() *ZoneSpec { + if in == nil { + return nil + } + out := new(ZoneSpec) + in.DeepCopyInto(out) + return out +} diff --git a/operator/bundle/community-openshift/manifests/loki-operator.clusterserviceversion.yaml b/operator/bundle/community-openshift/manifests/loki-operator.clusterserviceversion.yaml index c7fdcbf0acff5..7a5ef1bf47d41 100644 --- a/operator/bundle/community-openshift/manifests/loki-operator.clusterserviceversion.yaml +++ b/operator/bundle/community-openshift/manifests/loki-operator.clusterserviceversion.yaml @@ -150,7 +150,7 @@ metadata: categories: OpenShift Optional, Logging & Tracing certified: "false" containerImage: docker.io/grafana/loki-operator:main-99acb9b - createdAt: "2023-04-18T07:59:30Z" + createdAt: "2023-04-27T09:00:45Z" description: The Community Loki Operator provides Kubernetes native deployment and management of Loki and related logging components. operators.operatorframework.io/builder: operator-sdk-unknown @@ -438,12 +438,35 @@ spec: - description: NoProxy configures the NO_PROXY/no_proxy env variable. displayName: NoProxy path: proxy.noProxy - - description: ReplicationFactor defines the policy for log stream replication. + - description: Replication defines the configuration for Loki data replication. + displayName: Replication Spec + path: replication + - description: Factor defines the policy for log stream replication. + displayName: Replication Factor + path: replication.factor + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:number + - description: Zone is the key that defines a topology in the Nodes' labels. + displayName: Zones Spec + path: replication.zones + - description: MaxSkew describes the maximum degree to which Pods can be unevenly + distributed. + displayName: Max Skew + path: replication.zones[0].maxSkew + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:number + - description: TopologyKey is the key that defines a topology in the Nodes' + labels. + displayName: Topology Key + path: replication.zones[0].topologyKey + - description: 'Deprecated: Please use replication.factor instead. This field + will be removed in future versions of this CRD. ReplicationFactor defines + the policy for log stream replication.' displayName: Replication Factor path: replicationFactor x-descriptors: - urn:alm:descriptor:com.tectonic.ui:number - - description: Rules defines the spec for the ruler component + - description: Rules defines the spec for the ruler component. displayName: Rules path: rules x-descriptors: @@ -514,7 +537,7 @@ spec: x-descriptors: - urn:alm:descriptor:io.kubernetes:StorageClass - description: Template defines the resource/limits/tolerations/nodeselectors - per component + per component. displayName: Node Placement path: template x-descriptors: diff --git a/operator/bundle/community-openshift/manifests/loki.grafana.com_lokistacks.yaml b/operator/bundle/community-openshift/manifests/loki.grafana.com_lokistacks.yaml index a18b976a03119..da529ae90b4de 100644 --- a/operator/bundle/community-openshift/manifests/loki.grafana.com_lokistacks.yaml +++ b/operator/bundle/community-openshift/manifests/loki.grafana.com_lokistacks.yaml @@ -335,13 +335,47 @@ spec: description: NoProxy configures the NO_PROXY/no_proxy env variable. type: string type: object + replication: + description: Replication defines the configuration for Loki data replication. + properties: + factor: + description: Factor defines the policy for log stream replication. + format: int32 + minimum: 1 + type: integer + zones: + description: Zone is the key that defines a topology in the Nodes' + labels. + items: + description: ZoneSpec defines the spec to support zone-aware + component deployments. + properties: + maxSkew: + default: 1 + description: MaxSkew describes the maximum degree to which + Pods can be unevenly distributed. + type: integer + topologyKey: + description: TopologyKey is the key that defines a topology + in the Nodes' labels. + type: string + required: + - maxSkew + - topologyKey + type: object + type: array + required: + - zones + type: object replicationFactor: - description: ReplicationFactor defines the policy for log stream replication. + description: 'Deprecated: Please use replication.factor instead. This + field will be removed in future versions of this CRD. ReplicationFactor + defines the policy for log stream replication.' format: int32 minimum: 1 type: integer rules: - description: Rules defines the spec for the ruler component + description: Rules defines the spec for the ruler component. properties: enabled: description: Enabled defines a flag to enable/disable the ruler @@ -530,7 +564,7 @@ spec: type: string template: description: Template defines the resource/limits/tolerations/nodeselectors - per component + per component. properties: compactor: description: Compactor defines the compaction component spec. diff --git a/operator/bundle/community/manifests/loki-operator.clusterserviceversion.yaml b/operator/bundle/community/manifests/loki-operator.clusterserviceversion.yaml index 6e374d0d3935c..6e2d5e8e26a5f 100644 --- a/operator/bundle/community/manifests/loki-operator.clusterserviceversion.yaml +++ b/operator/bundle/community/manifests/loki-operator.clusterserviceversion.yaml @@ -150,7 +150,7 @@ metadata: categories: OpenShift Optional, Logging & Tracing certified: "false" containerImage: docker.io/grafana/loki-operator:main-99acb9b - createdAt: "2023-04-18T07:59:27Z" + createdAt: "2023-04-27T09:00:42Z" description: The Community Loki Operator provides Kubernetes native deployment and management of Loki and related logging components. operators.operatorframework.io/builder: operator-sdk-unknown @@ -438,12 +438,35 @@ spec: - description: NoProxy configures the NO_PROXY/no_proxy env variable. displayName: NoProxy path: proxy.noProxy - - description: ReplicationFactor defines the policy for log stream replication. + - description: Replication defines the configuration for Loki data replication. + displayName: Replication Spec + path: replication + - description: Factor defines the policy for log stream replication. + displayName: Replication Factor + path: replication.factor + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:number + - description: Zone is the key that defines a topology in the Nodes' labels. + displayName: Zones Spec + path: replication.zones + - description: MaxSkew describes the maximum degree to which Pods can be unevenly + distributed. + displayName: Max Skew + path: replication.zones[0].maxSkew + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:number + - description: TopologyKey is the key that defines a topology in the Nodes' + labels. + displayName: Topology Key + path: replication.zones[0].topologyKey + - description: 'Deprecated: Please use replication.factor instead. This field + will be removed in future versions of this CRD. ReplicationFactor defines + the policy for log stream replication.' displayName: Replication Factor path: replicationFactor x-descriptors: - urn:alm:descriptor:com.tectonic.ui:number - - description: Rules defines the spec for the ruler component + - description: Rules defines the spec for the ruler component. displayName: Rules path: rules x-descriptors: @@ -514,7 +537,7 @@ spec: x-descriptors: - urn:alm:descriptor:io.kubernetes:StorageClass - description: Template defines the resource/limits/tolerations/nodeselectors - per component + per component. displayName: Node Placement path: template x-descriptors: diff --git a/operator/bundle/community/manifests/loki.grafana.com_lokistacks.yaml b/operator/bundle/community/manifests/loki.grafana.com_lokistacks.yaml index 1400d763f9881..ba9340df4ba03 100644 --- a/operator/bundle/community/manifests/loki.grafana.com_lokistacks.yaml +++ b/operator/bundle/community/manifests/loki.grafana.com_lokistacks.yaml @@ -335,13 +335,47 @@ spec: description: NoProxy configures the NO_PROXY/no_proxy env variable. type: string type: object + replication: + description: Replication defines the configuration for Loki data replication. + properties: + factor: + description: Factor defines the policy for log stream replication. + format: int32 + minimum: 1 + type: integer + zones: + description: Zone is the key that defines a topology in the Nodes' + labels. + items: + description: ZoneSpec defines the spec to support zone-aware + component deployments. + properties: + maxSkew: + default: 1 + description: MaxSkew describes the maximum degree to which + Pods can be unevenly distributed. + type: integer + topologyKey: + description: TopologyKey is the key that defines a topology + in the Nodes' labels. + type: string + required: + - maxSkew + - topologyKey + type: object + type: array + required: + - zones + type: object replicationFactor: - description: ReplicationFactor defines the policy for log stream replication. + description: 'Deprecated: Please use replication.factor instead. This + field will be removed in future versions of this CRD. ReplicationFactor + defines the policy for log stream replication.' format: int32 minimum: 1 type: integer rules: - description: Rules defines the spec for the ruler component + description: Rules defines the spec for the ruler component. properties: enabled: description: Enabled defines a flag to enable/disable the ruler @@ -530,7 +564,7 @@ spec: type: string template: description: Template defines the resource/limits/tolerations/nodeselectors - per component + per component. properties: compactor: description: Compactor defines the compaction component spec. diff --git a/operator/bundle/openshift/manifests/loki-operator.clusterserviceversion.yaml b/operator/bundle/openshift/manifests/loki-operator.clusterserviceversion.yaml index 6a9d2804ddf6b..7e88d3017c70a 100644 --- a/operator/bundle/openshift/manifests/loki-operator.clusterserviceversion.yaml +++ b/operator/bundle/openshift/manifests/loki-operator.clusterserviceversion.yaml @@ -150,7 +150,7 @@ metadata: categories: OpenShift Optional, Logging & Tracing certified: "false" containerImage: quay.io/openshift-logging/loki-operator:v0.1.0 - createdAt: "2023-04-18T07:59:33Z" + createdAt: "2023-04-27T09:00:49Z" description: | The Loki Operator for OCP provides a means for configuring and managing a Loki stack for cluster logging. ## Prerequisites and Requirements @@ -451,12 +451,35 @@ spec: - description: NoProxy configures the NO_PROXY/no_proxy env variable. displayName: NoProxy path: proxy.noProxy - - description: ReplicationFactor defines the policy for log stream replication. + - description: Replication defines the configuration for Loki data replication. + displayName: Replication Spec + path: replication + - description: Factor defines the policy for log stream replication. + displayName: Replication Factor + path: replication.factor + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:number + - description: Zone is the key that defines a topology in the Nodes' labels. + displayName: Zones Spec + path: replication.zones + - description: MaxSkew describes the maximum degree to which Pods can be unevenly + distributed. + displayName: Max Skew + path: replication.zones[0].maxSkew + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:number + - description: TopologyKey is the key that defines a topology in the Nodes' + labels. + displayName: Topology Key + path: replication.zones[0].topologyKey + - description: 'Deprecated: Please use replication.factor instead. This field + will be removed in future versions of this CRD. ReplicationFactor defines + the policy for log stream replication.' displayName: Replication Factor path: replicationFactor x-descriptors: - urn:alm:descriptor:com.tectonic.ui:number - - description: Rules defines the spec for the ruler component + - description: Rules defines the spec for the ruler component. displayName: Rules path: rules x-descriptors: @@ -527,7 +550,7 @@ spec: x-descriptors: - urn:alm:descriptor:io.kubernetes:StorageClass - description: Template defines the resource/limits/tolerations/nodeselectors - per component + per component. displayName: Node Placement path: template x-descriptors: diff --git a/operator/bundle/openshift/manifests/loki.grafana.com_lokistacks.yaml b/operator/bundle/openshift/manifests/loki.grafana.com_lokistacks.yaml index 7e58cfa685539..dd1fc9b6bf012 100644 --- a/operator/bundle/openshift/manifests/loki.grafana.com_lokistacks.yaml +++ b/operator/bundle/openshift/manifests/loki.grafana.com_lokistacks.yaml @@ -335,13 +335,47 @@ spec: description: NoProxy configures the NO_PROXY/no_proxy env variable. type: string type: object + replication: + description: Replication defines the configuration for Loki data replication. + properties: + factor: + description: Factor defines the policy for log stream replication. + format: int32 + minimum: 1 + type: integer + zones: + description: Zone is the key that defines a topology in the Nodes' + labels. + items: + description: ZoneSpec defines the spec to support zone-aware + component deployments. + properties: + maxSkew: + default: 1 + description: MaxSkew describes the maximum degree to which + Pods can be unevenly distributed. + type: integer + topologyKey: + description: TopologyKey is the key that defines a topology + in the Nodes' labels. + type: string + required: + - maxSkew + - topologyKey + type: object + type: array + required: + - zones + type: object replicationFactor: - description: ReplicationFactor defines the policy for log stream replication. + description: 'Deprecated: Please use replication.factor instead. This + field will be removed in future versions of this CRD. ReplicationFactor + defines the policy for log stream replication.' format: int32 minimum: 1 type: integer rules: - description: Rules defines the spec for the ruler component + description: Rules defines the spec for the ruler component. properties: enabled: description: Enabled defines a flag to enable/disable the ruler @@ -530,7 +564,7 @@ spec: type: string template: description: Template defines the resource/limits/tolerations/nodeselectors - per component + per component. properties: compactor: description: Compactor defines the compaction component spec. diff --git a/operator/config/crd/bases/loki.grafana.com_lokistacks.yaml b/operator/config/crd/bases/loki.grafana.com_lokistacks.yaml index 0e59d766a2e8d..e1b36c8125343 100644 --- a/operator/config/crd/bases/loki.grafana.com_lokistacks.yaml +++ b/operator/config/crd/bases/loki.grafana.com_lokistacks.yaml @@ -318,13 +318,47 @@ spec: description: NoProxy configures the NO_PROXY/no_proxy env variable. type: string type: object + replication: + description: Replication defines the configuration for Loki data replication. + properties: + factor: + description: Factor defines the policy for log stream replication. + format: int32 + minimum: 1 + type: integer + zones: + description: Zone is the key that defines a topology in the Nodes' + labels. + items: + description: ZoneSpec defines the spec to support zone-aware + component deployments. + properties: + maxSkew: + default: 1 + description: MaxSkew describes the maximum degree to which + Pods can be unevenly distributed. + type: integer + topologyKey: + description: TopologyKey is the key that defines a topology + in the Nodes' labels. + type: string + required: + - maxSkew + - topologyKey + type: object + type: array + required: + - zones + type: object replicationFactor: - description: ReplicationFactor defines the policy for log stream replication. + description: 'Deprecated: Please use replication.factor instead. This + field will be removed in future versions of this CRD. ReplicationFactor + defines the policy for log stream replication.' format: int32 minimum: 1 type: integer rules: - description: Rules defines the spec for the ruler component + description: Rules defines the spec for the ruler component. properties: enabled: description: Enabled defines a flag to enable/disable the ruler @@ -513,7 +547,7 @@ spec: type: string template: description: Template defines the resource/limits/tolerations/nodeselectors - per component + per component. properties: compactor: description: Compactor defines the compaction component spec. diff --git a/operator/config/manifests/community-openshift/bases/loki-operator.clusterserviceversion.yaml b/operator/config/manifests/community-openshift/bases/loki-operator.clusterserviceversion.yaml index a24b1a46f8533..9565ebbf42493 100644 --- a/operator/config/manifests/community-openshift/bases/loki-operator.clusterserviceversion.yaml +++ b/operator/config/manifests/community-openshift/bases/loki-operator.clusterserviceversion.yaml @@ -351,12 +351,35 @@ spec: - description: NoProxy configures the NO_PROXY/no_proxy env variable. displayName: NoProxy path: proxy.noProxy - - description: ReplicationFactor defines the policy for log stream replication. + - description: Replication defines the configuration for Loki data replication. + displayName: Replication Spec + path: replication + - description: Factor defines the policy for log stream replication. + displayName: Replication Factor + path: replication.factor + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:number + - description: Zone is the key that defines a topology in the Nodes' labels. + displayName: Zones Spec + path: replication.zones + - description: MaxSkew describes the maximum degree to which Pods can be unevenly + distributed. + displayName: Max Skew + path: replication.zones[0].maxSkew + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:number + - description: TopologyKey is the key that defines a topology in the Nodes' + labels. + displayName: Topology Key + path: replication.zones[0].topologyKey + - description: 'Deprecated: Please use replication.factor instead. This field + will be removed in future versions of this CRD. ReplicationFactor defines + the policy for log stream replication.' displayName: Replication Factor path: replicationFactor x-descriptors: - urn:alm:descriptor:com.tectonic.ui:number - - description: Rules defines the spec for the ruler component + - description: Rules defines the spec for the ruler component. displayName: Rules path: rules x-descriptors: @@ -427,7 +450,7 @@ spec: x-descriptors: - urn:alm:descriptor:io.kubernetes:StorageClass - description: Template defines the resource/limits/tolerations/nodeselectors - per component + per component. displayName: Node Placement path: template x-descriptors: diff --git a/operator/config/manifests/community/bases/loki-operator.clusterserviceversion.yaml b/operator/config/manifests/community/bases/loki-operator.clusterserviceversion.yaml index c86eb796ea3d4..bf071bd9b61ff 100644 --- a/operator/config/manifests/community/bases/loki-operator.clusterserviceversion.yaml +++ b/operator/config/manifests/community/bases/loki-operator.clusterserviceversion.yaml @@ -351,12 +351,35 @@ spec: - description: NoProxy configures the NO_PROXY/no_proxy env variable. displayName: NoProxy path: proxy.noProxy - - description: ReplicationFactor defines the policy for log stream replication. + - description: Replication defines the configuration for Loki data replication. + displayName: Replication Spec + path: replication + - description: Factor defines the policy for log stream replication. + displayName: Replication Factor + path: replication.factor + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:number + - description: Zone is the key that defines a topology in the Nodes' labels. + displayName: Zones Spec + path: replication.zones + - description: MaxSkew describes the maximum degree to which Pods can be unevenly + distributed. + displayName: Max Skew + path: replication.zones[0].maxSkew + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:number + - description: TopologyKey is the key that defines a topology in the Nodes' + labels. + displayName: Topology Key + path: replication.zones[0].topologyKey + - description: 'Deprecated: Please use replication.factor instead. This field + will be removed in future versions of this CRD. ReplicationFactor defines + the policy for log stream replication.' displayName: Replication Factor path: replicationFactor x-descriptors: - urn:alm:descriptor:com.tectonic.ui:number - - description: Rules defines the spec for the ruler component + - description: Rules defines the spec for the ruler component. displayName: Rules path: rules x-descriptors: @@ -427,7 +450,7 @@ spec: x-descriptors: - urn:alm:descriptor:io.kubernetes:StorageClass - description: Template defines the resource/limits/tolerations/nodeselectors - per component + per component. displayName: Node Placement path: template x-descriptors: diff --git a/operator/config/manifests/openshift/bases/loki-operator.clusterserviceversion.yaml b/operator/config/manifests/openshift/bases/loki-operator.clusterserviceversion.yaml index 12f59794c9ba4..87495a9875c17 100644 --- a/operator/config/manifests/openshift/bases/loki-operator.clusterserviceversion.yaml +++ b/operator/config/manifests/openshift/bases/loki-operator.clusterserviceversion.yaml @@ -363,12 +363,35 @@ spec: - description: NoProxy configures the NO_PROXY/no_proxy env variable. displayName: NoProxy path: proxy.noProxy - - description: ReplicationFactor defines the policy for log stream replication. + - description: Replication defines the configuration for Loki data replication. + displayName: Replication Spec + path: replication + - description: Factor defines the policy for log stream replication. + displayName: Replication Factor + path: replication.factor + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:number + - description: Zone is the key that defines a topology in the Nodes' labels. + displayName: Zones Spec + path: replication.zones + - description: MaxSkew describes the maximum degree to which Pods can be unevenly + distributed. + displayName: Max Skew + path: replication.zones[0].maxSkew + x-descriptors: + - urn:alm:descriptor:com.tectonic.ui:number + - description: TopologyKey is the key that defines a topology in the Nodes' + labels. + displayName: Topology Key + path: replication.zones[0].topologyKey + - description: 'Deprecated: Please use replication.factor instead. This field + will be removed in future versions of this CRD. ReplicationFactor defines + the policy for log stream replication.' displayName: Replication Factor path: replicationFactor x-descriptors: - urn:alm:descriptor:com.tectonic.ui:number - - description: Rules defines the spec for the ruler component + - description: Rules defines the spec for the ruler component. displayName: Rules path: rules x-descriptors: @@ -439,7 +462,7 @@ spec: x-descriptors: - urn:alm:descriptor:io.kubernetes:StorageClass - description: Template defines the resource/limits/tolerations/nodeselectors - per component + per component. displayName: Node Placement path: template x-descriptors: diff --git a/operator/internal/manifests/build_test.go b/operator/internal/manifests/build_test.go index bad81afc675ff..5cbb3e6bbb6e1 100644 --- a/operator/internal/manifests/build_test.go +++ b/operator/internal/manifests/build_test.go @@ -45,6 +45,7 @@ func TestApplyUserOptions_OverrideDefaults(t *testing.T) { require.Equal(t, defs.Size, opt.Stack.Size) require.Equal(t, defs.Limits, opt.Stack.Limits) require.Equal(t, defs.ReplicationFactor, opt.Stack.ReplicationFactor) + require.Equal(t, defs.Replication, opt.Stack.Replication) require.Equal(t, defs.ManagementState, opt.Stack.ManagementState) require.Equal(t, defs.Template.Ingester, opt.Stack.Template.Ingester) require.Equal(t, defs.Template.Querier, opt.Stack.Template.Querier) diff --git a/operator/internal/manifests/config.go b/operator/internal/manifests/config.go index 1bec942540bf0..2eeb8767038a4 100644 --- a/operator/internal/manifests/config.go +++ b/operator/internal/manifests/config.go @@ -103,6 +103,15 @@ func ConfigOptions(opt Options) config.Options { protocol = "https" } + // nolint:staticcheck + if (opt.Stack.Replication == nil || opt.Stack.Replication.Factor == 0) && opt.Stack.ReplicationFactor > 0 { + if opt.Stack.Replication == nil { + opt.Stack.Replication = &lokiv1.ReplicationSpec{} + } + + opt.Stack.Replication.Factor = opt.Stack.ReplicationFactor + } + return config.Options{ Stack: opt.Stack, Gates: opt.Gates, diff --git a/operator/internal/manifests/config_test.go b/operator/internal/manifests/config_test.go index f2b7cb129e97e..64e3f24c54650 100644 --- a/operator/internal/manifests/config_test.go +++ b/operator/internal/manifests/config_test.go @@ -46,10 +46,12 @@ func randomConfigOptions() manifests.Options { Namespace: uuid.New().String(), Image: uuid.New().String(), Stack: lokiv1.LokiStackSpec{ - Size: lokiv1.SizeOneXExtraSmall, - Storage: lokiv1.ObjectStorageSpec{}, - StorageClassName: uuid.New().String(), - ReplicationFactor: rand.Int31(), + Size: lokiv1.SizeOneXExtraSmall, + Storage: lokiv1.ObjectStorageSpec{}, + StorageClassName: uuid.New().String(), + Replication: &lokiv1.ReplicationSpec{ + Factor: rand.Int31(), + }, Limits: &lokiv1.LimitsSpec{ Global: &lokiv1.LimitsTemplateSpec{ IngestionLimits: &lokiv1.IngestionLimitSpec{ @@ -1041,3 +1043,97 @@ func TestConfigOptions_RulerOverrides_OCPUserWorkloadOnlyEnabled(t *testing.T) { }) } } + +func TestConfigOptions_Replication(t *testing.T) { + tt := []struct { + desc string + spec lokiv1.LokiStackSpec + wantOptions lokiv1.ReplicationSpec + }{ + { + desc: "nominal case", + spec: lokiv1.LokiStackSpec{ + Replication: &lokiv1.ReplicationSpec{ + Factor: 2, + Zones: []lokiv1.ZoneSpec{ + { + TopologyKey: "us-east-1a", + MaxSkew: 1, + }, + { + TopologyKey: "us-east-1b", + MaxSkew: 2, + }, + }, + }, + }, + wantOptions: lokiv1.ReplicationSpec{ + Factor: 2, + Zones: []lokiv1.ZoneSpec{ + { + TopologyKey: "us-east-1a", + MaxSkew: 1, + }, + { + TopologyKey: "us-east-1b", + MaxSkew: 2, + }, + }, + }, + }, + { + desc: "using deprecated ReplicationFactor", + spec: lokiv1.LokiStackSpec{ + ReplicationFactor: 3, + }, + wantOptions: lokiv1.ReplicationSpec{ + Factor: 3, + }, + }, + { + desc: "using deprecated ReplicationFactor with ReplicationSpec", + spec: lokiv1.LokiStackSpec{ + ReplicationFactor: 2, + Replication: &lokiv1.ReplicationSpec{ + Factor: 4, + Zones: []lokiv1.ZoneSpec{ + { + TopologyKey: "us-east-1a", + MaxSkew: 1, + }, + { + TopologyKey: "us-east-1b", + MaxSkew: 2, + }, + }, + }, + }, + wantOptions: lokiv1.ReplicationSpec{ + Factor: 4, + Zones: []lokiv1.ZoneSpec{ + { + TopologyKey: "us-east-1a", + MaxSkew: 1, + }, + { + TopologyKey: "us-east-1b", + MaxSkew: 2, + }, + }, + }, + }, + } + + for _, tc := range tt { + tc := tc + t.Run(tc.desc, func(t *testing.T) { + t.Parallel() + + inOpt := manifests.Options{ + Stack: tc.spec, + } + options := manifests.ConfigOptions(inOpt) + require.Equal(t, tc.wantOptions, *options.Stack.Replication) + }) + } +} diff --git a/operator/internal/manifests/distributor.go b/operator/internal/manifests/distributor.go index 2a4f1c328384b..da95075985e23 100644 --- a/operator/internal/manifests/distributor.go +++ b/operator/internal/manifests/distributor.go @@ -123,6 +123,10 @@ func NewDistributorDeployment(opts Options) *appsv1.Deployment { podSpec.NodeSelector = opts.Stack.Template.Distributor.NodeSelector } + if opts.Stack.Replication != nil { + podSpec.TopologySpreadConstraints = topologySpreadConstraints(*opts.Stack.Replication) + } + l := ComponentLabels(LabelDistributorComponent, opts.Name) a := commonAnnotations(opts.ConfigSHA1, opts.CertRotationRequiredAt) diff --git a/operator/internal/manifests/distributor_test.go b/operator/internal/manifests/distributor_test.go index 876c5406756c4..f46bb456f9955 100644 --- a/operator/internal/manifests/distributor_test.go +++ b/operator/internal/manifests/distributor_test.go @@ -6,6 +6,7 @@ import ( lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" "github.com/grafana/loki/operator/internal/manifests" "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" ) func TestNewDistributorDeployment_SelectorMatchesLabels(t *testing.T) { @@ -67,3 +68,43 @@ func TestNewDistributorDeployment_HasTemplateCertRotationRequiredAtAnnotation(t require.Contains(t, annotations, expected) require.Equal(t, annotations[expected], "deadbeef") } + +func TestNewDistributorDeployment_TopologySpreadConstraints(t *testing.T) { + depl := manifests.NewDistributorDeployment(manifests.Options{ + Name: "abcd", + Namespace: "efgh", + Stack: lokiv1.LokiStackSpec{ + Template: &lokiv1.LokiTemplateSpec{ + Distributor: &lokiv1.LokiComponentSpec{ + Replicas: 1, + }, + }, + Replication: &lokiv1.ReplicationSpec{ + Zones: []lokiv1.ZoneSpec{ + { + TopologyKey: "zone", + MaxSkew: 3, + }, + { + TopologyKey: "region", + MaxSkew: 2, + }, + }, + Factor: 1, + }, + }, + }) + + require.Equal(t, []corev1.TopologySpreadConstraint{ + { + MaxSkew: 3, + TopologyKey: "zone", + WhenUnsatisfiable: "DoNotSchedule", + }, + { + MaxSkew: 2, + TopologyKey: "region", + WhenUnsatisfiable: "DoNotSchedule", + }, + }, depl.Spec.Template.Spec.TopologySpreadConstraints) +} diff --git a/operator/internal/manifests/ingester.go b/operator/internal/manifests/ingester.go index 38518f54b8df1..3ddc50f18dcd7 100644 --- a/operator/internal/manifests/ingester.go +++ b/operator/internal/manifests/ingester.go @@ -139,8 +139,13 @@ func NewIngesterStatefulSet(opts Options) *appsv1.StatefulSet { podSpec.NodeSelector = opts.Stack.Template.Ingester.NodeSelector } + if opts.Stack.Replication != nil { + podSpec.TopologySpreadConstraints = topologySpreadConstraints(*opts.Stack.Replication) + } + l := ComponentLabels(LabelIngesterComponent, opts.Name) a := commonAnnotations(opts.ConfigSHA1, opts.CertRotationRequiredAt) + return &appsv1.StatefulSet{ TypeMeta: metav1.TypeMeta{ Kind: "StatefulSet", diff --git a/operator/internal/manifests/ingester_test.go b/operator/internal/manifests/ingester_test.go index 657c7aadc2986..2dcd51793a493 100644 --- a/operator/internal/manifests/ingester_test.go +++ b/operator/internal/manifests/ingester_test.go @@ -6,6 +6,7 @@ import ( lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" "github.com/grafana/loki/operator/internal/manifests" "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" ) func TestNewIngesterStatefulSet_HasTemplateConfigHashAnnotation(t *testing.T) { @@ -75,3 +76,43 @@ func TestNewIngesterStatefulSet_SelectorMatchesLabels(t *testing.T) { require.Equal(t, l[key], value) } } + +func TestNewIngesterStatefulSet_TopologySpreadConstraints(t *testing.T) { + ss := manifests.NewIngesterStatefulSet(manifests.Options{ + Name: "abcd", + Namespace: "efgh", + Stack: lokiv1.LokiStackSpec{ + Template: &lokiv1.LokiTemplateSpec{ + Ingester: &lokiv1.LokiComponentSpec{ + Replicas: 1, + }, + }, + Replication: &lokiv1.ReplicationSpec{ + Zones: []lokiv1.ZoneSpec{ + { + TopologyKey: "zone", + MaxSkew: 2, + }, + { + TopologyKey: "region", + MaxSkew: 1, + }, + }, + Factor: 1, + }, + }, + }) + + require.Equal(t, []corev1.TopologySpreadConstraint{ + { + MaxSkew: 2, + TopologyKey: "zone", + WhenUnsatisfiable: "DoNotSchedule", + }, + { + MaxSkew: 1, + TopologyKey: "region", + WhenUnsatisfiable: "DoNotSchedule", + }, + }, ss.Spec.Template.Spec.TopologySpreadConstraints) +} diff --git a/operator/internal/manifests/internal/config/build_test.go b/operator/internal/manifests/internal/config/build_test.go index 239be8b718091..0faab65ccc40e 100644 --- a/operator/internal/manifests/internal/config/build_test.go +++ b/operator/internal/manifests/internal/config/build_test.go @@ -174,7 +174,9 @@ overrides: ` opts := Options{ Stack: lokiv1.LokiStackSpec{ - ReplicationFactor: 1, + Replication: &lokiv1.ReplicationSpec{ + Factor: 1, + }, Limits: &lokiv1.LimitsSpec{ Global: &lokiv1.LimitsTemplateSpec{ IngestionLimits: &lokiv1.IngestionLimitSpec{ @@ -420,7 +422,9 @@ overrides: ` opts := Options{ Stack: lokiv1.LokiStackSpec{ - ReplicationFactor: 1, + Replication: &lokiv1.ReplicationSpec{ + Factor: 1, + }, Limits: &lokiv1.LimitsSpec{ Global: &lokiv1.LimitsTemplateSpec{ IngestionLimits: &lokiv1.IngestionLimitSpec{ @@ -525,7 +529,9 @@ overrides: func TestBuild_ConfigAndRuntimeConfig_CreateLokiConfigFailed(t *testing.T) { opts := Options{ Stack: lokiv1.LokiStackSpec{ - ReplicationFactor: 1, + Replication: &lokiv1.ReplicationSpec{ + Factor: 1, + }, Limits: &lokiv1.LimitsSpec{ Global: &lokiv1.LimitsTemplateSpec{ IngestionLimits: &lokiv1.IngestionLimitSpec{ @@ -815,7 +821,9 @@ overrides: ` opts := Options{ Stack: lokiv1.LokiStackSpec{ - ReplicationFactor: 1, + Replication: &lokiv1.ReplicationSpec{ + Factor: 1, + }, Limits: &lokiv1.LimitsSpec{ Global: &lokiv1.LimitsTemplateSpec{ IngestionLimits: &lokiv1.IngestionLimitSpec{ @@ -1157,7 +1165,9 @@ overrides: ` opts := Options{ Stack: lokiv1.LokiStackSpec{ - ReplicationFactor: 1, + Replication: &lokiv1.ReplicationSpec{ + Factor: 1, + }, Limits: &lokiv1.LimitsSpec{ Global: &lokiv1.LimitsTemplateSpec{ IngestionLimits: &lokiv1.IngestionLimitSpec{ @@ -1513,7 +1523,9 @@ overrides: ` opts := Options{ Stack: lokiv1.LokiStackSpec{ - ReplicationFactor: 1, + Replication: &lokiv1.ReplicationSpec{ + Factor: 1, + }, Limits: &lokiv1.LimitsSpec{ Global: &lokiv1.LimitsTemplateSpec{ IngestionLimits: &lokiv1.IngestionLimitSpec{ @@ -1837,7 +1849,9 @@ overrides: ` opts := Options{ Stack: lokiv1.LokiStackSpec{ - ReplicationFactor: 1, + Replication: &lokiv1.ReplicationSpec{ + Factor: 1, + }, Limits: &lokiv1.LimitsSpec{ Global: &lokiv1.LimitsTemplateSpec{ IngestionLimits: &lokiv1.IngestionLimitSpec{ @@ -2217,7 +2231,9 @@ overrides: ` opts := Options{ Stack: lokiv1.LokiStackSpec{ - ReplicationFactor: 1, + Replication: &lokiv1.ReplicationSpec{ + Factor: 1, + }, Limits: &lokiv1.LimitsSpec{ Global: &lokiv1.LimitsTemplateSpec{ IngestionLimits: &lokiv1.IngestionLimitSpec{ @@ -2598,7 +2614,9 @@ overrides: ` opts := Options{ Stack: lokiv1.LokiStackSpec{ - ReplicationFactor: 1, + Replication: &lokiv1.ReplicationSpec{ + Factor: 1, + }, Limits: &lokiv1.LimitsSpec{ Global: &lokiv1.LimitsTemplateSpec{ IngestionLimits: &lokiv1.IngestionLimitSpec{ @@ -2978,7 +2996,9 @@ overrides: ` opts := Options{ Stack: lokiv1.LokiStackSpec{ - ReplicationFactor: 1, + Replication: &lokiv1.ReplicationSpec{ + Factor: 1, + }, Limits: &lokiv1.LimitsSpec{ Global: &lokiv1.LimitsTemplateSpec{ IngestionLimits: &lokiv1.IngestionLimitSpec{ @@ -3352,7 +3372,9 @@ overrides: ` opts := Options{ Stack: lokiv1.LokiStackSpec{ - ReplicationFactor: 1, + Replication: &lokiv1.ReplicationSpec{ + Factor: 1, + }, Limits: &lokiv1.LimitsSpec{ Global: &lokiv1.LimitsTemplateSpec{ IngestionLimits: &lokiv1.IngestionLimitSpec{ diff --git a/operator/internal/manifests/internal/config/loki-config.yaml b/operator/internal/manifests/internal/config/loki-config.yaml index 7cbec377d4749..a2db6e3a6eeb8 100644 --- a/operator/internal/manifests/internal/config/loki-config.yaml +++ b/operator/internal/manifests/internal/config/loki-config.yaml @@ -113,7 +113,7 @@ ingester: join_after: 30s num_tokens: 512 ring: - replication_factor: {{ .Stack.ReplicationFactor }} + replication_factor: {{ .Stack.Replication.Factor }} max_transfer_retries: 0 wal: enabled: true diff --git a/operator/internal/manifests/internal/sizes.go b/operator/internal/manifests/internal/sizes.go index 355b3e31bec39..cd66fa0171fdc 100644 --- a/operator/internal/manifests/internal/sizes.go +++ b/operator/internal/manifests/internal/sizes.go @@ -222,8 +222,10 @@ var ResourceRequirementsTable = map[lokiv1.LokiStackSizeType]ComponentResources{ // StackSizeTable defines the default configurations for each size var StackSizeTable = map[lokiv1.LokiStackSizeType]lokiv1.LokiStackSpec{ lokiv1.SizeOneXDemo: { - Size: lokiv1.SizeOneXDemo, - ReplicationFactor: 1, + Size: lokiv1.SizeOneXDemo, + Replication: &lokiv1.ReplicationSpec{ + Factor: 1, + }, Limits: &lokiv1.LimitsSpec{ Global: &lokiv1.LimitsTemplateSpec{ IngestionLimits: &lokiv1.IngestionLimitSpec{ @@ -272,8 +274,10 @@ var StackSizeTable = map[lokiv1.LokiStackSizeType]lokiv1.LokiStackSpec{ }, }, lokiv1.SizeOneXExtraSmall: { - Size: lokiv1.SizeOneXExtraSmall, - ReplicationFactor: 1, + Size: lokiv1.SizeOneXExtraSmall, + Replication: &lokiv1.ReplicationSpec{ + Factor: 1, + }, Limits: &lokiv1.LimitsSpec{ Global: &lokiv1.LimitsTemplateSpec{ IngestionLimits: &lokiv1.IngestionLimitSpec{ @@ -323,8 +327,10 @@ var StackSizeTable = map[lokiv1.LokiStackSizeType]lokiv1.LokiStackSpec{ }, lokiv1.SizeOneXSmall: { - Size: lokiv1.SizeOneXSmall, - ReplicationFactor: 2, + Size: lokiv1.SizeOneXSmall, + Replication: &lokiv1.ReplicationSpec{ + Factor: 2, + }, Limits: &lokiv1.LimitsSpec{ Global: &lokiv1.LimitsTemplateSpec{ IngestionLimits: &lokiv1.IngestionLimitSpec{ @@ -376,8 +382,10 @@ var StackSizeTable = map[lokiv1.LokiStackSizeType]lokiv1.LokiStackSpec{ }, lokiv1.SizeOneXMedium: { - Size: lokiv1.SizeOneXMedium, - ReplicationFactor: 3, + Size: lokiv1.SizeOneXMedium, + Replication: &lokiv1.ReplicationSpec{ + Factor: 3, + }, Limits: &lokiv1.LimitsSpec{ Global: &lokiv1.LimitsTemplateSpec{ IngestionLimits: &lokiv1.IngestionLimitSpec{ diff --git a/operator/internal/manifests/querier.go b/operator/internal/manifests/querier.go index b0f8d20cb5fa4..153820ae3968e 100644 --- a/operator/internal/manifests/querier.go +++ b/operator/internal/manifests/querier.go @@ -131,6 +131,10 @@ func NewQuerierDeployment(opts Options) *appsv1.Deployment { podSpec.NodeSelector = opts.Stack.Template.Querier.NodeSelector } + if opts.Stack.Replication != nil { + podSpec.TopologySpreadConstraints = topologySpreadConstraints(*opts.Stack.Replication) + } + l := ComponentLabels(LabelQuerierComponent, opts.Name) a := commonAnnotations(opts.ConfigSHA1, opts.CertRotationRequiredAt) diff --git a/operator/internal/manifests/querier_test.go b/operator/internal/manifests/querier_test.go index 8342b79b02c0c..6286fc4cdef4e 100644 --- a/operator/internal/manifests/querier_test.go +++ b/operator/internal/manifests/querier_test.go @@ -6,6 +6,7 @@ import ( lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" "github.com/grafana/loki/operator/internal/manifests" "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" policyv1 "k8s.io/api/policy/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" @@ -183,3 +184,43 @@ func TestBuildQuerier_PodDisruptionBudget(t *testing.T) { }) } } + +func TestNewQuerierDeployment_TopologySpreadConstraints(t *testing.T) { + depl := manifests.NewQuerierDeployment(manifests.Options{ + Name: "abcd", + Namespace: "efgh", + Stack: lokiv1.LokiStackSpec{ + Template: &lokiv1.LokiTemplateSpec{ + Querier: &lokiv1.LokiComponentSpec{ + Replicas: 1, + }, + }, + Replication: &lokiv1.ReplicationSpec{ + Zones: []lokiv1.ZoneSpec{ + { + TopologyKey: "zone", + MaxSkew: 2, + }, + { + TopologyKey: "region", + MaxSkew: 1, + }, + }, + Factor: 1, + }, + }, + }) + + require.Equal(t, []corev1.TopologySpreadConstraint{ + { + MaxSkew: 2, + TopologyKey: "zone", + WhenUnsatisfiable: "DoNotSchedule", + }, + { + MaxSkew: 1, + TopologyKey: "region", + WhenUnsatisfiable: "DoNotSchedule", + }, + }, depl.Spec.Template.Spec.TopologySpreadConstraints) +} diff --git a/operator/internal/manifests/query-frontend.go b/operator/internal/manifests/query-frontend.go index 9a67cba83066f..1115db4cfd008 100644 --- a/operator/internal/manifests/query-frontend.go +++ b/operator/internal/manifests/query-frontend.go @@ -137,6 +137,10 @@ func NewQueryFrontendDeployment(opts Options) *appsv1.Deployment { podSpec.NodeSelector = opts.Stack.Template.QueryFrontend.NodeSelector } + if opts.Stack.Replication != nil { + podSpec.TopologySpreadConstraints = topologySpreadConstraints(*opts.Stack.Replication) + } + l := ComponentLabels(LabelQueryFrontendComponent, opts.Name) a := commonAnnotations(opts.ConfigSHA1, opts.CertRotationRequiredAt) diff --git a/operator/internal/manifests/query-frontend_test.go b/operator/internal/manifests/query-frontend_test.go index 09d0fdb4d70ff..c2e1c22cd21dd 100644 --- a/operator/internal/manifests/query-frontend_test.go +++ b/operator/internal/manifests/query-frontend_test.go @@ -5,6 +5,7 @@ import ( lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" policyv1 "k8s.io/api/policy/v1" ) @@ -91,3 +92,43 @@ func TestBuildQueryFrontend_PodDisruptionBudget(t *testing.T) { require.Equal(t, int32(1), pdb.Spec.MinAvailable.IntVal) require.EqualValues(t, ComponentLabels(LabelQueryFrontendComponent, opts.Name), pdb.Spec.Selector.MatchLabels) } + +func TestNewQueryFrontendDeployment_TopologySpreadConstraints(t *testing.T) { + depl := NewQueryFrontendDeployment(Options{ + Name: "abcd", + Namespace: "efgh", + Stack: lokiv1.LokiStackSpec{ + Template: &lokiv1.LokiTemplateSpec{ + QueryFrontend: &lokiv1.LokiComponentSpec{ + Replicas: 1, + }, + }, + Replication: &lokiv1.ReplicationSpec{ + Zones: []lokiv1.ZoneSpec{ + { + TopologyKey: "zone", + MaxSkew: 1, + }, + { + TopologyKey: "region", + MaxSkew: 2, + }, + }, + Factor: 1, + }, + }, + }) + + require.Equal(t, []corev1.TopologySpreadConstraint{ + { + MaxSkew: 1, + TopologyKey: "zone", + WhenUnsatisfiable: "DoNotSchedule", + }, + { + MaxSkew: 2, + TopologyKey: "region", + WhenUnsatisfiable: "DoNotSchedule", + }, + }, depl.Spec.Template.Spec.TopologySpreadConstraints) +} diff --git a/operator/internal/manifests/var.go b/operator/internal/manifests/var.go index 41f8f2de9beb0..3147b1a8a6e71 100644 --- a/operator/internal/manifests/var.go +++ b/operator/internal/manifests/var.go @@ -4,6 +4,7 @@ import ( "fmt" "path" + lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" "github.com/grafana/loki/operator/internal/manifests/openshift" monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" corev1 "k8s.io/api/core/v1" @@ -132,6 +133,22 @@ func serviceAnnotations(serviceName string, enableSigningService bool) map[strin return annotations } +func topologySpreadConstraints(spec lokiv1.ReplicationSpec) []corev1.TopologySpreadConstraint { + var tsc []corev1.TopologySpreadConstraint + if len(spec.Zones) > 0 { + tsc = make([]corev1.TopologySpreadConstraint, len(spec.Zones)) + for i, z := range spec.Zones { + tsc[i] = corev1.TopologySpreadConstraint{ + MaxSkew: int32(z.MaxSkew), + TopologyKey: z.TopologyKey, + WhenUnsatisfiable: corev1.DoNotSchedule, + } + } + } + + return tsc +} + // ComponentLabels is a list of all commonLabels including the app.kubernetes.io/component: label func ComponentLabels(component, stackName string) labels.Set { return labels.Merge(commonLabels(stackName), map[string]string{ diff --git a/operator/internal/validation/lokistack.go b/operator/internal/validation/lokistack.go index 9af724e7c2485..04b298f8f6916 100644 --- a/operator/internal/validation/lokistack.go +++ b/operator/internal/validation/lokistack.go @@ -6,6 +6,8 @@ import ( "time" lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" @@ -23,6 +25,7 @@ var _ admission.CustomValidator = &LokiStackValidator{} // LokiStackValidator implements a custom validator for LokiStack resources. type LokiStackValidator struct { ExtendedValidator func(context.Context, *lokiv1.LokiStack) field.ErrorList + Client client.Client } // SetupWebhookWithManager registers the LokiStackValidator as a validating webhook @@ -68,6 +71,11 @@ func (v *LokiStackValidator) validate(ctx context.Context, obj runtime.Object) e allErrs = append(allErrs, errors...) } + errors = v.validateReplicationSpec(ctx, stack.Spec) + if len(errors) != 0 { + allErrs = append(allErrs, errors...) + } + if v.ExtendedValidator != nil { allErrs = append(allErrs, v.ExtendedValidator(ctx, stack)...) } @@ -83,6 +91,72 @@ func (v *LokiStackValidator) validate(ctx context.Context, obj runtime.Object) e ) } +func (v LokiStackValidator) validateReplicationSpec(ctx context.Context, stack lokiv1.LokiStackSpec) field.ErrorList { + if stack.Replication == nil { + return nil + } + + var allErrs field.ErrorList + var nodes corev1.NodeList + + // nolint:staticcheck + if stack.Replication != nil && stack.ReplicationFactor > 0 { + allErrs = append(allErrs, field.Invalid( + field.NewPath("spec", "replicationFactor"), + stack.ReplicationFactor, + lokiv1.ErrReplicationSpecConflict.Error(), + )) + + return allErrs + } + + rs := stack.Replication + selector := make([]string, 0) + for _, z := range rs.Zones { + selector = append(selector, z.TopologyKey) + } + + if err := v.Client.List(ctx, &nodes, client.HasLabels(selector)); err != nil { + allErrs = append(allErrs, field.Invalid( + field.NewPath("spec", "replication", "zones"), + rs.Zones, + lokiv1.ErrReplicationZonesNodes.Error(), + )) + } + + // Check if there are enough nodes to fit all the pods. + if len(nodes.Items) < int(rs.Factor) { + allErrs = append(allErrs, field.Invalid( + field.NewPath("spec", "replication", "factor"), + rs.Factor, + lokiv1.ErrReplicationFactorToZonesRatio.Error(), + )) + + return allErrs + } + + // Check if there are enough regions to fit all the pods for each topology keys. + for _, tk := range selector { + m := make(map[string]struct{}) + for _, node := range nodes.Items { + m[node.Labels[tk]] = struct{}{} + } + + fmt.Printf("%+v\n", m) + + if len(m) < int(rs.Factor) { + allErrs = append(allErrs, field.Invalid( + field.NewPath("spec", "replication", "factor"), + rs.Factor, + lokiv1.ErrReplicationFactorToZonesRatio.Error(), + )) + return allErrs + } + } + + return nil +} + // ValidateSchemas ensures that the schemas are in a valid format func ValidateSchemas(v *lokiv1.ObjectStorageSpec, utcTime time.Time, status lokiv1.LokiStackStorageStatus) field.ErrorList { var allErrs field.ErrorList diff --git a/operator/internal/validation/lokistack_test.go b/operator/internal/validation/lokistack_test.go index 37a787bc3f45b..c341e91ecaf83 100644 --- a/operator/internal/validation/lokistack_test.go +++ b/operator/internal/validation/lokistack_test.go @@ -2,11 +2,15 @@ package validation_test import ( "context" + "fmt" "testing" lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" + "github.com/grafana/loki/operator/internal/external/k8s/k8sfakes" "github.com/grafana/loki/operator/internal/validation" "github.com/stretchr/testify/require" + corev1 "k8s.io/api/core/v1" + "sigs.k8s.io/controller-runtime/pkg/client" apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" @@ -285,6 +289,159 @@ var ltt = []struct { }, ), }, + { + desc: "valid replication zones", + spec: lokiv1.LokiStack{ + Spec: lokiv1.LokiStackSpec{ + Storage: lokiv1.ObjectStorageSpec{ + Schemas: []lokiv1.ObjectStorageSchema{ + { + Version: lokiv1.ObjectStorageSchemaV12, + EffectiveDate: "2020-10-11", + }, + }, + }, + Replication: &lokiv1.ReplicationSpec{ + Zones: []lokiv1.ZoneSpec{ + { + TopologyKey: "zone", + }, + }, + Factor: 1, + }, + }, + }, + }, + { + desc: "invalid zones to replication factor ratio", + spec: lokiv1.LokiStack{ + Spec: lokiv1.LokiStackSpec{ + Storage: lokiv1.ObjectStorageSpec{ + Schemas: []lokiv1.ObjectStorageSchema{ + { + Version: lokiv1.ObjectStorageSchemaV12, + EffectiveDate: "2020-10-11", + }, + }, + }, + Replication: &lokiv1.ReplicationSpec{ + Zones: []lokiv1.ZoneSpec{ + { + TopologyKey: "zone", + }, + }, + Factor: 2, + }, + }, + }, + err: apierrors.NewInvalid( + schema.GroupKind{Group: "loki.grafana.com", Kind: "LokiStack"}, + "testing-stack", + field.ErrorList{ + field.Invalid( + field.NewPath("spec", "replication", "factor"), + 2, + lokiv1.ErrReplicationFactorToZonesRatio.Error(), + ), + }, + ), + }, + { + desc: "invalid zones topologyKey", + spec: lokiv1.LokiStack{ + Spec: lokiv1.LokiStackSpec{ + Storage: lokiv1.ObjectStorageSpec{ + Schemas: []lokiv1.ObjectStorageSchema{ + { + Version: lokiv1.ObjectStorageSchemaV12, + EffectiveDate: "2020-10-11", + }, + }, + }, + Replication: &lokiv1.ReplicationSpec{ + Zones: []lokiv1.ZoneSpec{ + { + TopologyKey: "zone", + }, + { + TopologyKey: "region", + }, + { + TopologyKey: "planet", + }, + }, + Factor: 1, + }, + }, + }, + err: apierrors.NewInvalid( + schema.GroupKind{Group: "loki.grafana.com", Kind: "LokiStack"}, + "testing-stack", + field.ErrorList{ + field.Invalid( + field.NewPath("spec", "replication", "zones"), + []lokiv1.ZoneSpec{ + { + TopologyKey: "zone", + }, + { + TopologyKey: "region", + }, + { + TopologyKey: "planet", + }, + }, + lokiv1.ErrReplicationZonesNodes.Error(), + ), + field.Invalid( + field.NewPath("spec", "replication", "factor"), + 1, + lokiv1.ErrReplicationFactorToZonesRatio.Error(), + ), + }, + ), + }, + { + desc: "using both replication and replicationFactor", + spec: lokiv1.LokiStack{ + Spec: lokiv1.LokiStackSpec{ + Storage: lokiv1.ObjectStorageSpec{ + Schemas: []lokiv1.ObjectStorageSchema{ + { + Version: lokiv1.ObjectStorageSchemaV12, + EffectiveDate: "2020-10-11", + }, + }, + }, + ReplicationFactor: 2, + Replication: &lokiv1.ReplicationSpec{ + Zones: []lokiv1.ZoneSpec{ + { + TopologyKey: "zone", + }, + { + TopologyKey: "region", + }, + { + TopologyKey: "planet", + }, + }, + Factor: 1, + }, + }, + }, + err: apierrors.NewInvalid( + schema.GroupKind{Group: "loki.grafana.com", Kind: "LokiStack"}, + "testing-stack", + field.ErrorList{ + field.Invalid( + field.NewPath("spec", "replicationFactor"), + 2, + lokiv1.ErrReplicationSpecConflict.Error(), + ), + }, + ), + }, } func TestLokiStackValidationWebhook_ValidateCreate(t *testing.T) { @@ -300,7 +457,10 @@ func TestLokiStackValidationWebhook_ValidateCreate(t *testing.T) { } ctx := context.Background() - v := &validation.LokiStackValidator{} + k := prepFakeClient() + v := &validation.LokiStackValidator{ + Client: k, + } err := v.ValidateCreate(ctx, l) if err != nil { require.Equal(t, tc.err, err) @@ -324,7 +484,10 @@ func TestLokiStackValidationWebhook_ValidateUpdate(t *testing.T) { } ctx := context.Background() - v := &validation.LokiStackValidator{} + k := prepFakeClient() + v := &validation.LokiStackValidator{ + Client: k, + } err := v.ValidateUpdate(ctx, &lokiv1.LokiStack{}, l) if err != nil { require.Equal(t, tc.err, err) @@ -334,3 +497,53 @@ func TestLokiStackValidationWebhook_ValidateUpdate(t *testing.T) { }) } } + +func prepFakeClient() *k8sfakes.FakeClient { + k := &k8sfakes.FakeClient{} + nodes := corev1.NodeList{ + Items: []corev1.Node{ + { + ObjectMeta: metav1.ObjectMeta{ + Name: "node1", + Labels: map[string]string{ + "zone": "z1", + "region": "r1", + }, + }, + }, + { + ObjectMeta: metav1.ObjectMeta{ + Name: "node2", + Labels: map[string]string{ + "zone": "z2", + "region": "r1", + }, + }, + }, + }, + } + + k.ListStub = func(_ context.Context, object client.ObjectList, opts ...client.ListOption) error { + + res := corev1.NodeList{ + Items: []corev1.Node{}, + } + + for _, opt := range opts { + optLabels := opt.(client.HasLabels) + for _, l := range optLabels { + for _, node := range nodes.Items { + if _, ok := node.Labels[l]; !ok { + return fmt.Errorf("node with label %s not found", l) + } + res.Items = append(res.Items, node) + } + } + } + + k.SetClientObjectList(object, &nodes) + return nil + } + + return k +} diff --git a/operator/main.go b/operator/main.go index 08bae850f4e08..42cda5375004b 100644 --- a/operator/main.go +++ b/operator/main.go @@ -110,7 +110,9 @@ func main() { os.Exit(1) } if ctrlCfg.Gates.LokiStackWebhook { - v := &validation.LokiStackValidator{} + v := &validation.LokiStackValidator{ + Client: mgr.GetClient(), + } if err = v.SetupWebhookWithManager(mgr); err != nil { logger.Error(err, "unable to create webhook", "webhook", "lokistack") os.Exit(1) From 4043b779fcf291c71644e4fbcf92582f311c3c71 Mon Sep 17 00:00:00 2001 From: Mohamed-Amine Bouqsimi Date: Thu, 27 Apr 2023 12:26:10 +0200 Subject: [PATCH 02/23] add api docs --- operator/docs/operator/api.md | 118 ++++++++++++++++++++++++++++++++-- 1 file changed, 113 insertions(+), 5 deletions(-) diff --git a/operator/docs/operator/api.md b/operator/docs/operator/api.md index d504a742dd7a5..3d1edca849080 100644 --- a/operator/docs/operator/api.md +++ b/operator/docs/operator/api.md @@ -1602,7 +1602,15 @@ are degraded or the cluster cannot connect to object storage.

Description -

"1x.extra-small"

+

"1x.demo"

+

SizeOneXDemo defines the size of a single Loki deployment +with tiny resource requirements and without HA support. +This size is intended to run in single-node clusters on laptops, +it is only useful for very light testing, demonstrations, or prototypes. +There are no ingestion/query performance guarantees. +DO NOT USE THIS IN PRODUCTION!

+ +

"1x.extra-small"

SizeOneXExtraSmall defines the size of a single Loki deployment with extra small resources/limits requirements and without HA support. This size is ultimately dedicated for development and demo purposes. @@ -1729,7 +1737,22 @@ int32 (Optional) -

ReplicationFactor defines the policy for log stream replication.

+

Deprecated: Please use replication.factor instead. This field will be removed in future versions of this CRD. +ReplicationFactor defines the policy for log stream replication.

+ + + + +replication
+ + +ReplicationSpec + + + + +(Optional) +

Replication defines the configuration for Loki data replication.

@@ -1743,7 +1766,7 @@ RulesSpec (Optional) -

Rules defines the spec for the ruler component

+

Rules defines the spec for the ruler component.

@@ -1771,7 +1794,7 @@ LokiTemplateSpec (Optional) -

Template defines the resource/limits/tolerations/nodeselectors per component

+

Template defines the resource/limits/tolerations/nodeselectors per component.

@@ -2346,7 +2369,10 @@ string Description -

"azure"

+

"alibabacloud"

+

ObjectStorageSecretAlibabaCloud when using AlibabaCloud OSS for Loki storage

+ +

"azure"

ObjectStorageSecretAzure when using Azure for Loki storage

"gcs"

@@ -3266,6 +3292,48 @@ RemoteWriteClientQueueSpec +## ReplicationSpec { #loki-grafana-com-v1-ReplicationSpec } +

+(Appears on:LokiStackSpec) +

+
+
+ + + + + + + + + + + + + + + + + +
FieldDescription
+factor
+ +int32 + +
+(Optional) +

Factor defines the policy for log stream replication.

+
+zones
+ + +[]ZoneSpec + + +
+

Zone is the key that defines a topology in the Nodes’ labels.

+
+ ## RetentionLimitSpec { #loki-grafana-com-v1-RetentionLimitSpec }

(Appears on:LimitsTemplateSpec) @@ -3897,6 +3965,46 @@ AuthorizationSpec + +## ZoneSpec { #loki-grafana-com-v1-ZoneSpec } +

+(Appears on:ReplicationSpec) +

+
+

ZoneSpec defines the spec to support zone-aware component deployments.

+
+ + + + + + + + + + + + + + + + + +
FieldDescription
+maxSkew
+ +int + +
+

MaxSkew describes the maximum degree to which Pods can be unevenly distributed.

+
+topologyKey
+ +string + +
+

TopologyKey is the key that defines a topology in the Nodes’ labels.

+

From 75105039c6be5a4b961cabded8b789ae7082f3a6 Mon Sep 17 00:00:00 2001 From: Mohamed-Amine Bouqsimi Date: Thu, 27 Apr 2023 12:27:16 +0200 Subject: [PATCH 03/23] changelog --- operator/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/operator/CHANGELOG.md b/operator/CHANGELOG.md index 4867a0c8dbd45..3169a08e2a618 100644 --- a/operator/CHANGELOG.md +++ b/operator/CHANGELOG.md @@ -1,4 +1,5 @@ ## Main +- [9315](https://github.com/grafana/loki/pull/9315) **aminesnow**: Add zone awareness spec to LokiStack - [9262](https://github.com/grafana/loki/pull/9262) **btaani**: Add PodDisruptionBudget to the Ruler - [9188](https://github.com/grafana/loki/pull/9188) **aminesnow**: Add PodDisruptionBudgets to the query path - [9162](https://github.com/grafana/loki/pull/9162) **aminesnow**: Add a PodDisruptionBudget to lokistack-gateway From 06fe96bf3f82102a9da127595546e125642497b8 Mon Sep 17 00:00:00 2001 From: Mohamed-Amine Bouqsimi Date: Thu, 27 Apr 2023 18:15:02 +0200 Subject: [PATCH 04/23] lint --- operator/internal/manifests/config_test.go | 10 ++++++---- operator/internal/manifests/distributor_test.go | 5 +++-- operator/internal/manifests/ingester_test.go | 5 +++-- .../internal/manifests/internal/config/build_test.go | 5 +++-- operator/internal/manifests/internal/sizes.go | 3 ++- operator/internal/manifests/querier_test.go | 5 +++-- operator/internal/manifests/query-frontend_test.go | 3 ++- operator/internal/manifests/var.go | 5 +++-- operator/internal/validation/lokistack.go | 3 ++- operator/internal/validation/lokistack_test.go | 8 ++++---- 10 files changed, 31 insertions(+), 21 deletions(-) diff --git a/operator/internal/manifests/config_test.go b/operator/internal/manifests/config_test.go index 64e3f24c54650..6b0a77df058ca 100644 --- a/operator/internal/manifests/config_test.go +++ b/operator/internal/manifests/config_test.go @@ -6,14 +6,16 @@ import ( "testing" "github.com/google/uuid" - lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" - "github.com/grafana/loki/operator/internal/manifests" - "github.com/grafana/loki/operator/internal/manifests/internal/config" - "github.com/grafana/loki/operator/internal/manifests/openshift" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" "k8s.io/utils/pointer" + + lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" + "github.com/grafana/loki/operator/internal/manifests" + "github.com/grafana/loki/operator/internal/manifests/internal/config" + "github.com/grafana/loki/operator/internal/manifests/openshift" ) func TestConfigMap_ReturnsSHA1OfBinaryContents(t *testing.T) { diff --git a/operator/internal/manifests/distributor_test.go b/operator/internal/manifests/distributor_test.go index f46bb456f9955..63b0c521465ca 100644 --- a/operator/internal/manifests/distributor_test.go +++ b/operator/internal/manifests/distributor_test.go @@ -3,10 +3,11 @@ package manifests_test import ( "testing" - lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" - "github.com/grafana/loki/operator/internal/manifests" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" + + lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" + "github.com/grafana/loki/operator/internal/manifests" ) func TestNewDistributorDeployment_SelectorMatchesLabels(t *testing.T) { diff --git a/operator/internal/manifests/ingester_test.go b/operator/internal/manifests/ingester_test.go index 2dcd51793a493..8381fdeebc2c7 100644 --- a/operator/internal/manifests/ingester_test.go +++ b/operator/internal/manifests/ingester_test.go @@ -3,10 +3,11 @@ package manifests_test import ( "testing" - lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" - "github.com/grafana/loki/operator/internal/manifests" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" + + lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" + "github.com/grafana/loki/operator/internal/manifests" ) func TestNewIngesterStatefulSet_HasTemplateConfigHashAnnotation(t *testing.T) { diff --git a/operator/internal/manifests/internal/config/build_test.go b/operator/internal/manifests/internal/config/build_test.go index 0faab65ccc40e..78c8a64da6b58 100644 --- a/operator/internal/manifests/internal/config/build_test.go +++ b/operator/internal/manifests/internal/config/build_test.go @@ -3,11 +3,12 @@ package config import ( "testing" + "github.com/stretchr/testify/require" + "k8s.io/utils/pointer" + configv1 "github.com/grafana/loki/operator/apis/config/v1" lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" "github.com/grafana/loki/operator/internal/manifests/storage" - "github.com/stretchr/testify/require" - "k8s.io/utils/pointer" ) func TestBuild_ConfigAndRuntimeConfig_NoRuntimeConfigGenerated(t *testing.T) { diff --git a/operator/internal/manifests/internal/sizes.go b/operator/internal/manifests/internal/sizes.go index cd66fa0171fdc..8f479a4933e00 100644 --- a/operator/internal/manifests/internal/sizes.go +++ b/operator/internal/manifests/internal/sizes.go @@ -1,9 +1,10 @@ package internal import ( - lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/resource" + + lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" ) // ComponentResources is a map of component->requests/limits diff --git a/operator/internal/manifests/querier_test.go b/operator/internal/manifests/querier_test.go index 6286fc4cdef4e..38967a3ba91cc 100644 --- a/operator/internal/manifests/querier_test.go +++ b/operator/internal/manifests/querier_test.go @@ -3,13 +3,14 @@ package manifests_test import ( "testing" - lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" - "github.com/grafana/loki/operator/internal/manifests" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" policyv1 "k8s.io/api/policy/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/util/intstr" + + lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" + "github.com/grafana/loki/operator/internal/manifests" ) func TestNewQuerierDeployment_HasTemplateConfigHashAnnotation(t *testing.T) { diff --git a/operator/internal/manifests/query-frontend_test.go b/operator/internal/manifests/query-frontend_test.go index c2e1c22cd21dd..783cd028f83a1 100644 --- a/operator/internal/manifests/query-frontend_test.go +++ b/operator/internal/manifests/query-frontend_test.go @@ -3,10 +3,11 @@ package manifests import ( "testing" - lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" policyv1 "k8s.io/api/policy/v1" + + lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" ) func TestNewQueryFrontendDeployment_SelectorMatchesLabels(t *testing.T) { diff --git a/operator/internal/manifests/var.go b/operator/internal/manifests/var.go index 3147b1a8a6e71..904b1a2727409 100644 --- a/operator/internal/manifests/var.go +++ b/operator/internal/manifests/var.go @@ -4,13 +4,14 @@ import ( "fmt" "path" - lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" - "github.com/grafana/loki/operator/internal/manifests/openshift" monitoringv1 "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/util/intstr" "k8s.io/utils/pointer" + + lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" + "github.com/grafana/loki/operator/internal/manifests/openshift" ) const ( diff --git a/operator/internal/validation/lokistack.go b/operator/internal/validation/lokistack.go index 04b298f8f6916..1b7b4f1ccf923 100644 --- a/operator/internal/validation/lokistack.go +++ b/operator/internal/validation/lokistack.go @@ -5,10 +5,11 @@ import ( "fmt" "time" - lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" corev1 "k8s.io/api/core/v1" "sigs.k8s.io/controller-runtime/pkg/client" + lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" + apierrors "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/runtime/schema" diff --git a/operator/internal/validation/lokistack_test.go b/operator/internal/validation/lokistack_test.go index c341e91ecaf83..3bc6f1c0553e7 100644 --- a/operator/internal/validation/lokistack_test.go +++ b/operator/internal/validation/lokistack_test.go @@ -5,13 +5,14 @@ import ( "fmt" "testing" - lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" - "github.com/grafana/loki/operator/internal/external/k8s/k8sfakes" - "github.com/grafana/loki/operator/internal/validation" "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" "sigs.k8s.io/controller-runtime/pkg/client" + lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" + "github.com/grafana/loki/operator/internal/external/k8s/k8sfakes" + "github.com/grafana/loki/operator/internal/validation" + apierrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime/schema" @@ -524,7 +525,6 @@ func prepFakeClient() *k8sfakes.FakeClient { } k.ListStub = func(_ context.Context, object client.ObjectList, opts ...client.ListOption) error { - res := corev1.NodeList{ Items: []corev1.Node{}, } From ccfc5f4d371bcedb8c6695670107a83dd2072bb9 Mon Sep 17 00:00:00 2001 From: Mohamed-Amine Bouqsimi Date: Fri, 28 Apr 2023 09:55:56 +0200 Subject: [PATCH 05/23] lint --- operator/main.go | 1 + 1 file changed, 1 insertion(+) diff --git a/operator/main.go b/operator/main.go index 42cda5375004b..81e11509d17a7 100644 --- a/operator/main.go +++ b/operator/main.go @@ -8,6 +8,7 @@ import ( "github.com/ViaQ/logerr/v2/kverrors" "github.com/ViaQ/logerr/v2/log" + "github.com/grafana/loki/operator/internal/validation" "github.com/grafana/loki/operator/internal/validation/openshift" From d788c98687d9b4e33dad1f8ad8fe4726924352f3 Mon Sep 17 00:00:00 2001 From: Mohamed-Amine Bouqsimi Date: Wed, 3 May 2023 11:59:11 +0200 Subject: [PATCH 06/23] fix test --- .../internal/manifests/distributor_test.go | 75 ++++++------------- operator/internal/manifests/ingester_test.go | 75 +++++++++++++------ 2 files changed, 75 insertions(+), 75 deletions(-) diff --git a/operator/internal/manifests/distributor_test.go b/operator/internal/manifests/distributor_test.go index 6274e9f62471f..04513e50ce2bb 100644 --- a/operator/internal/manifests/distributor_test.go +++ b/operator/internal/manifests/distributor_test.go @@ -8,10 +8,8 @@ import ( corev1 "k8s.io/api/core/v1" policyv1 "k8s.io/api/policy/v1" - v1 "github.com/grafana/loki/operator/apis/config/v1" lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" "github.com/grafana/loki/operator/internal/manifests" - "github.com/grafana/loki/operator/internal/manifests/internal" ) func TestNewDistributorDeployment_SelectorMatchesLabels(t *testing.T) { @@ -74,57 +72,32 @@ func TestNewDistributorDeployment_HasTemplateCertRotationRequiredAtAnnotation(t require.Equal(t, annotations[expected], "deadbeef") } -func TestBuildIngester_PodDisruptionBudget(t *testing.T) { - for _, tc := range []struct { - Name string - PDBMinAvailable int - ExpectedMinAvailable int - }{ - { - Name: "Small stack", - PDBMinAvailable: 1, - ExpectedMinAvailable: 1, - }, - { - Name: "Medium stack", - PDBMinAvailable: 2, - ExpectedMinAvailable: 2, - }, - } { - t.Run(tc.Name, func(t *testing.T) { - opts := manifests.Options{ - Name: "abcd", - Namespace: "efgh", - Gates: v1.FeatureGates{}, - ResourceRequirements: internal.ComponentResources{ - Ingester: internal.ResourceRequirements{ - PDBMinAvailable: tc.PDBMinAvailable, - }, - }, - Stack: lokiv1.LokiStackSpec{ - Template: &lokiv1.LokiTemplateSpec{ - Ingester: &lokiv1.LokiComponentSpec{ - Replicas: rand.Int31(), - }, - }, - Tenants: &lokiv1.TenantsSpec{ - Mode: lokiv1.OpenshiftLogging, - }, +func TestBuildDistributor_PodDisruptionBudget(t *testing.T) { + opts := manifests.Options{ + Name: "abcd", + Namespace: "efgh", + Stack: lokiv1.LokiStackSpec{ + Template: &lokiv1.LokiTemplateSpec{ + Distributor: &lokiv1.LokiComponentSpec{ + Replicas: rand.Int31(), }, - } - objs, err := manifests.BuildIngester(opts) - require.NoError(t, err) - require.Len(t, objs, 4) - - pdb := objs[3].(*policyv1.PodDisruptionBudget) - require.NotNil(t, pdb) - require.Equal(t, "abcd-ingester", pdb.Name) - require.Equal(t, "efgh", pdb.Namespace) - require.NotNil(t, pdb.Spec.MinAvailable.IntVal) - require.Equal(t, int32(tc.ExpectedMinAvailable), pdb.Spec.MinAvailable.IntVal) - require.EqualValues(t, manifests.ComponentLabels(manifests.LabelIngesterComponent, opts.Name), pdb.Spec.Selector.MatchLabels) - }) + }, + Tenants: &lokiv1.TenantsSpec{ + Mode: lokiv1.OpenshiftLogging, + }, + }, } + objs, err := manifests.BuildDistributor(opts) + require.NoError(t, err) + require.Len(t, objs, 4) + + pdb := objs[3].(*policyv1.PodDisruptionBudget) + require.NotNil(t, pdb) + require.Equal(t, "abcd-distributor", pdb.Name) + require.Equal(t, "efgh", pdb.Namespace) + require.NotNil(t, pdb.Spec.MinAvailable.IntVal) + require.Equal(t, int32(1), pdb.Spec.MinAvailable.IntVal) + require.EqualValues(t, manifests.ComponentLabels(manifests.LabelDistributorComponent, opts.Name), pdb.Spec.Selector.MatchLabels) } func TestNewDistributorDeployment_TopologySpreadConstraints(t *testing.T) { diff --git a/operator/internal/manifests/ingester_test.go b/operator/internal/manifests/ingester_test.go index 655aaa42af8d3..e72f3773100a3 100644 --- a/operator/internal/manifests/ingester_test.go +++ b/operator/internal/manifests/ingester_test.go @@ -9,8 +9,10 @@ import ( policyv1 "k8s.io/api/policy/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + v1 "github.com/grafana/loki/operator/apis/config/v1" lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" "github.com/grafana/loki/operator/internal/manifests" + "github.com/grafana/loki/operator/internal/manifests/internal" ) func TestNewIngesterStatefulSet_HasTemplateConfigHashAnnotation(t *testing.T) { @@ -81,32 +83,57 @@ func TestNewIngesterStatefulSet_SelectorMatchesLabels(t *testing.T) { } } -func TestBuildDistributor_PodDisruptionBudget(t *testing.T) { - opts := manifests.Options{ - Name: "abcd", - Namespace: "efgh", - Stack: lokiv1.LokiStackSpec{ - Template: &lokiv1.LokiTemplateSpec{ - Distributor: &lokiv1.LokiComponentSpec{ - Replicas: rand.Int31(), - }, - }, - Tenants: &lokiv1.TenantsSpec{ - Mode: lokiv1.OpenshiftLogging, - }, +func TestBuildIngester_PodDisruptionBudget(t *testing.T) { + for _, tc := range []struct { + Name string + PDBMinAvailable int + ExpectedMinAvailable int + }{ + { + Name: "Small stack", + PDBMinAvailable: 1, + ExpectedMinAvailable: 1, }, - } - objs, err := manifests.BuildDistributor(opts) - require.NoError(t, err) - require.Len(t, objs, 4) + { + Name: "Medium stack", + PDBMinAvailable: 2, + ExpectedMinAvailable: 2, + }, + } { + t.Run(tc.Name, func(t *testing.T) { + opts := manifests.Options{ + Name: "abcd", + Namespace: "efgh", + Gates: v1.FeatureGates{}, + ResourceRequirements: internal.ComponentResources{ + Ingester: internal.ResourceRequirements{ + PDBMinAvailable: tc.PDBMinAvailable, + }, + }, + Stack: lokiv1.LokiStackSpec{ + Template: &lokiv1.LokiTemplateSpec{ + Ingester: &lokiv1.LokiComponentSpec{ + Replicas: rand.Int31(), + }, + }, + Tenants: &lokiv1.TenantsSpec{ + Mode: lokiv1.OpenshiftLogging, + }, + }, + } + objs, err := manifests.BuildIngester(opts) + require.NoError(t, err) + require.Len(t, objs, 4) - pdb := objs[3].(*policyv1.PodDisruptionBudget) - require.NotNil(t, pdb) - require.Equal(t, "abcd-distributor", pdb.Name) - require.Equal(t, "efgh", pdb.Namespace) - require.NotNil(t, pdb.Spec.MinAvailable.IntVal) - require.Equal(t, int32(1), pdb.Spec.MinAvailable.IntVal) - require.EqualValues(t, manifests.ComponentLabels(manifests.LabelDistributorComponent, opts.Name), pdb.Spec.Selector.MatchLabels) + pdb := objs[3].(*policyv1.PodDisruptionBudget) + require.NotNil(t, pdb) + require.Equal(t, "abcd-ingester", pdb.Name) + require.Equal(t, "efgh", pdb.Namespace) + require.NotNil(t, pdb.Spec.MinAvailable.IntVal) + require.Equal(t, int32(tc.ExpectedMinAvailable), pdb.Spec.MinAvailable.IntVal) + require.EqualValues(t, manifests.ComponentLabels(manifests.LabelIngesterComponent, opts.Name), pdb.Spec.Selector.MatchLabels) + }) + } } func TestNewIngesterStatefulSet_TopologySpreadConstraints(t *testing.T) { From 8d72ce125b1ba37e8595063cf0be18a704c44a34 Mon Sep 17 00:00:00 2001 From: Mohamed-Amine Bouqsimi Date: Wed, 3 May 2023 12:03:25 +0200 Subject: [PATCH 07/23] changelog --- operator/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/operator/CHANGELOG.md b/operator/CHANGELOG.md index 61fa6b087ebbd..b52f75e00dc4b 100644 --- a/operator/CHANGELOG.md +++ b/operator/CHANGELOG.md @@ -1,5 +1,6 @@ ## Main +- [9378](https://github.com/grafana/loki/pull/9378) **aminesnow**: Add zone aware API spec validation - [9315](https://github.com/grafana/loki/pull/9315) **aminesnow**: Add zone awareness spec to LokiStack - [9339](https://github.com/grafana/loki/pull/9339) **JoaoBraveCoding**: Add default PodAntiAffinity to Ruler - [9329](https://github.com/grafana/loki/pull/9329) **JoaoBraveCoding**: Add default PodAntiAffinity to Ingester From a27ba96dc29afb933de2c9e4e0750a9ec2e75d5d Mon Sep 17 00:00:00 2001 From: Mohamed-Amine Bouqsimi Date: Thu, 4 May 2023 18:01:16 +0200 Subject: [PATCH 08/23] move client --- operator/internal/validation/lokistack.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/operator/internal/validation/lokistack.go b/operator/internal/validation/lokistack.go index 1b7b4f1ccf923..f020cb6fa0af5 100644 --- a/operator/internal/validation/lokistack.go +++ b/operator/internal/validation/lokistack.go @@ -25,8 +25,8 @@ var _ admission.CustomValidator = &LokiStackValidator{} // LokiStackValidator implements a custom validator for LokiStack resources. type LokiStackValidator struct { - ExtendedValidator func(context.Context, *lokiv1.LokiStack) field.ErrorList Client client.Client + ExtendedValidator func(context.Context, *lokiv1.LokiStack) field.ErrorList } // SetupWebhookWithManager registers the LokiStackValidator as a validating webhook From dda3bf4efaa6c3d643ff00aaad565c82e5143cb0 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Wed, 3 May 2023 10:40:43 +0200 Subject: [PATCH 09/23] Update loki-build-image with go1.20.4 (#9372) Continuation of #9370 Signed-off-by: Danny Kopping --- .devcontainer/devcontainer.json | 2 +- .drone/drone.yml | 42 +++++++++---------- Makefile | 2 +- clients/cmd/docker-driver/Dockerfile | 2 +- clients/cmd/promtail/Dockerfile.cross | 2 +- clients/cmd/promtail/Dockerfile.debug | 2 +- cmd/loki-canary/Dockerfile.cross | 2 +- cmd/loki/Dockerfile.cross | 2 +- cmd/loki/Dockerfile.debug | 2 +- cmd/querytee/Dockerfile.cross | 2 +- .../maintaining/release-loki-build-image.md | 2 +- operator/Dockerfile.cross | 2 +- 12 files changed, 32 insertions(+), 32 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 14f0f5963288f..6b9b792f7ee2f 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,5 +1,5 @@ { - "image": "grafana/loki-build-image:0.28.2", + "image": "grafana/loki-build-image:0.28.3", "containerEnv": { "BUILD_IN_CONTAINER": "false" }, diff --git a/.drone/drone.yml b/.drone/drone.yml index 4abbdefdfbbee..002067ded35f3 100644 --- a/.drone/drone.yml +++ b/.drone/drone.yml @@ -93,14 +93,14 @@ steps: depends_on: - clone environment: {} - image: grafana/loki-build-image:0.28.2 + image: grafana/loki-build-image:0.28.3 name: check-drone-drift - commands: - make BUILD_IN_CONTAINER=false check-generated-files depends_on: - clone environment: {} - image: grafana/loki-build-image:0.28.2 + image: grafana/loki-build-image:0.28.3 name: check-generated-files - commands: - cd .. @@ -110,7 +110,7 @@ steps: depends_on: - clone environment: {} - image: grafana/loki-build-image:0.28.2 + image: grafana/loki-build-image:0.28.3 name: clone-target-branch when: event: @@ -121,7 +121,7 @@ steps: - clone-target-branch - check-generated-files environment: {} - image: grafana/loki-build-image:0.28.2 + image: grafana/loki-build-image:0.28.3 name: test - commands: - cd ../loki-target-branch @@ -129,7 +129,7 @@ steps: depends_on: - clone-target-branch environment: {} - image: grafana/loki-build-image:0.28.2 + image: grafana/loki-build-image:0.28.3 name: test-target-branch when: event: @@ -142,7 +142,7 @@ steps: - test - test-target-branch environment: {} - image: grafana/loki-build-image:0.28.2 + image: grafana/loki-build-image:0.28.3 name: compare-coverage when: event: @@ -160,7 +160,7 @@ steps: TOKEN: from_secret: github_token USER: grafanabot - image: grafana/loki-build-image:0.28.2 + image: grafana/loki-build-image:0.28.3 name: report-coverage when: event: @@ -170,7 +170,7 @@ steps: depends_on: - check-generated-files environment: {} - image: grafana/loki-build-image:0.28.2 + image: grafana/loki-build-image:0.28.3 name: lint - commands: - make BUILD_IN_CONTAINER=false check-mod @@ -178,7 +178,7 @@ steps: - test - lint environment: {} - image: grafana/loki-build-image:0.28.2 + image: grafana/loki-build-image:0.28.3 name: check-mod - commands: - apk add make bash && make lint-scripts @@ -189,21 +189,21 @@ steps: depends_on: - check-generated-files environment: {} - image: grafana/loki-build-image:0.28.2 + image: grafana/loki-build-image:0.28.3 name: loki - commands: - make BUILD_IN_CONTAINER=false check-doc depends_on: - loki environment: {} - image: grafana/loki-build-image:0.28.2 + image: grafana/loki-build-image:0.28.3 name: check-doc - commands: - make BUILD_IN_CONTAINER=false check-format GIT_TARGET_BRANCH="$DRONE_TARGET_BRANCH" depends_on: - loki environment: {} - image: grafana/loki-build-image:0.28.2 + image: grafana/loki-build-image:0.28.3 name: check-format when: event: @@ -213,14 +213,14 @@ steps: depends_on: - loki environment: {} - image: grafana/loki-build-image:0.28.2 + image: grafana/loki-build-image:0.28.3 name: validate-example-configs - commands: - make BUILD_IN_CONTAINER=false check-example-config-doc depends_on: - clone environment: {} - image: grafana/loki-build-image:0.28.2 + image: grafana/loki-build-image:0.28.3 name: check-example-config-doc - commands: - mkdir -p /hugo/content/docs/loki/latest @@ -253,7 +253,7 @@ steps: depends_on: - clone environment: {} - image: grafana/loki-build-image:0.28.2 + image: grafana/loki-build-image:0.28.3 name: loki-mixin-check when: event: @@ -278,7 +278,7 @@ steps: depends_on: - clone environment: {} - image: grafana/loki-build-image:0.28.2 + image: grafana/loki-build-image:0.28.3 name: documentation-helm-reference-check trigger: ref: @@ -1439,7 +1439,7 @@ steps: NFPM_SIGNING_KEY: from_secret: gpg_private_key NFPM_SIGNING_KEY_FILE: /drone/src/private-key.key - image: grafana/loki-build-image:0.28.2 + image: grafana/loki-build-image:0.28.3 name: write-key - commands: - make BUILD_IN_CONTAINER=false packages @@ -1447,7 +1447,7 @@ steps: NFPM_PASSPHRASE: from_secret: gpg_passphrase NFPM_SIGNING_KEY_FILE: /drone/src/private-key.key - image: grafana/loki-build-image:0.28.2 + image: grafana/loki-build-image:0.28.3 name: test packaging - commands: - ./tools/packaging/verify-deb-install.sh @@ -1473,7 +1473,7 @@ steps: NFPM_PASSPHRASE: from_secret: gpg_passphrase NFPM_SIGNING_KEY_FILE: /drone/src/private-key.key - image: grafana/loki-build-image:0.28.2 + image: grafana/loki-build-image:0.28.3 name: publish when: event: @@ -1507,7 +1507,7 @@ steps: from_secret: docker_password DOCKER_USERNAME: from_secret: docker_username - image: grafana/loki-build-image:0.28.2 + image: grafana/loki-build-image:0.28.3 name: build and push privileged: true volumes: @@ -1772,6 +1772,6 @@ kind: secret name: gpg_private_key --- kind: signature -hmac: 81941d0775a351bf94e90c6d4845e78c72de1d63f0b46f767b7deb147e2c7905 +hmac: 81437a4d7383dd556801f441c1510191471ae0349da15361a0b661bdc44bb8cd ... diff --git a/Makefile b/Makefile index ccd98f41e6238..93dc6b7c05e49 100644 --- a/Makefile +++ b/Makefile @@ -31,7 +31,7 @@ DOCKER_IMAGE_DIRS := $(patsubst %/Dockerfile,%,$(DOCKERFILES)) BUILD_IN_CONTAINER ?= true # ensure you run `make drone` after changing this -BUILD_IMAGE_VERSION := 0.28.2 +BUILD_IMAGE_VERSION := 0.28.3 # Docker image info IMAGE_PREFIX ?= grafana diff --git a/clients/cmd/docker-driver/Dockerfile b/clients/cmd/docker-driver/Dockerfile index 35e86703a1ce8..be31406698e7f 100644 --- a/clients/cmd/docker-driver/Dockerfile +++ b/clients/cmd/docker-driver/Dockerfile @@ -1,4 +1,4 @@ -ARG BUILD_IMAGE=grafana/loki-build-image:0.28.1 +ARG BUILD_IMAGE=grafana/loki-build-image:0.28.3 # Directories in this file are referenced from the root of the project not this folder # This file is intended to be called from the root like so: # docker build -t grafana/loki -f cmd/loki/Dockerfile . diff --git a/clients/cmd/promtail/Dockerfile.cross b/clients/cmd/promtail/Dockerfile.cross index d9835f8fa6847..b3a5ae68493ac 100644 --- a/clients/cmd/promtail/Dockerfile.cross +++ b/clients/cmd/promtail/Dockerfile.cross @@ -1,4 +1,4 @@ -ARG BUILD_IMAGE=grafana/loki-build-image:0.28.1 +ARG BUILD_IMAGE=grafana/loki-build-image:0.28.3 # Directories in this file are referenced from the root of the project not this folder # This file is intended to be called from the root like so: # docker build -t grafana/promtail -f clients/cmd/promtail/Dockerfile . diff --git a/clients/cmd/promtail/Dockerfile.debug b/clients/cmd/promtail/Dockerfile.debug index d08b431955506..eaacec0b41e02 100644 --- a/clients/cmd/promtail/Dockerfile.debug +++ b/clients/cmd/promtail/Dockerfile.debug @@ -2,7 +2,7 @@ # This file is intended to be called from the root like so: # docker build -t grafana/promtail -f clients/cmd/promtail/Dockerfile.debug . -FROM grafana/loki-build-image:0.28.1 as build +FROM grafana/loki-build-image:0.28.3 as build ARG GOARCH="amd64" COPY . /src/loki WORKDIR /src/loki diff --git a/cmd/loki-canary/Dockerfile.cross b/cmd/loki-canary/Dockerfile.cross index 01fcd710df56b..2265143045276 100644 --- a/cmd/loki-canary/Dockerfile.cross +++ b/cmd/loki-canary/Dockerfile.cross @@ -1,4 +1,4 @@ -ARG BUILD_IMAGE=grafana/loki-build-image:0.28.1 +ARG BUILD_IMAGE=grafana/loki-build-image:0.28.3 # Directories in this file are referenced from the root of the project not this folder # This file is intended to be called from the root like so: # docker build -t grafana/promtail -f cmd/promtail/Dockerfile . diff --git a/cmd/loki/Dockerfile.cross b/cmd/loki/Dockerfile.cross index 726676ba8b1fe..bab069938b895 100644 --- a/cmd/loki/Dockerfile.cross +++ b/cmd/loki/Dockerfile.cross @@ -1,4 +1,4 @@ -ARG BUILD_IMAGE=grafana/loki-build-image:0.28.1 +ARG BUILD_IMAGE=grafana/loki-build-image:0.28.3 # Directories in this file are referenced from the root of the project not this folder # This file is intended to be called from the root like so: # docker build -t grafana/loki -f cmd/loki/Dockerfile . diff --git a/cmd/loki/Dockerfile.debug b/cmd/loki/Dockerfile.debug index 3ef5d39b5def8..982a6be8e64e4 100644 --- a/cmd/loki/Dockerfile.debug +++ b/cmd/loki/Dockerfile.debug @@ -1,4 +1,4 @@ -ARG BUILD_IMAGE=grafana/loki-build-image:0.28.1 +ARG BUILD_IMAGE=grafana/loki-build-image:0.28.3 # Directories in this file are referenced from the root of the project not this folder # This file is intended to be called from the root like so: # docker build -t grafana/loki -f cmd/loki/Dockerfile.debug . diff --git a/cmd/querytee/Dockerfile.cross b/cmd/querytee/Dockerfile.cross index 411058e511810..6d75614b338d9 100644 --- a/cmd/querytee/Dockerfile.cross +++ b/cmd/querytee/Dockerfile.cross @@ -1,4 +1,4 @@ -ARG BUILD_IMAGE=grafana/loki-build-image:0.28.1 +ARG BUILD_IMAGE=grafana/loki-build-image:0.28.3 # Directories in this file are referenced from the root of the project not this folder # This file is intended to be called from the root like so: # docker build -t grafana/promtail -f cmd/promtail/Dockerfile . diff --git a/docs/sources/maintaining/release-loki-build-image.md b/docs/sources/maintaining/release-loki-build-image.md index 56c297a3592d0..2ce9c311902f1 100644 --- a/docs/sources/maintaining/release-loki-build-image.md +++ b/docs/sources/maintaining/release-loki-build-image.md @@ -28,5 +28,5 @@ if any changes were made in the folder `./loki-build-image/`. 2. update the `BUILD_IMAGE_VERSION` variable in the `Makefile` 3. run `loki-build-image/version-updater.sh ` to update all the references 4. run `DRONE_SERVER=https://drone.grafana.net/ DRONE_TOKEN= make drone` to update the Drone config to use the new build image -5. push the changes to the branch you created in step 1 and create a new PR +5. create a new PR diff --git a/operator/Dockerfile.cross b/operator/Dockerfile.cross index f3c77c8a29c62..813b81e351843 100644 --- a/operator/Dockerfile.cross +++ b/operator/Dockerfile.cross @@ -1,4 +1,4 @@ -ARG BUILD_IMAGE=grafana/loki-build-image:0.28.1 +ARG BUILD_IMAGE=grafana/loki-build-image:0.28.3 FROM golang:1.20.4-alpine as goenv RUN go env GOARCH > /goarch && \ From 3e5089758aea63060e63af969180f51584cc4276 Mon Sep 17 00:00:00 2001 From: Danny Kopping Date: Wed, 3 May 2023 11:34:07 +0200 Subject: [PATCH 10/23] Adding CHANGELOG entry missed in #9370 (#9376) Signed-off-by: Danny Kopping --- CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2a2d4eea713f..d839a78100351 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ #### Loki +##### Security + +* [9370](https://github.com/grafana/loki/pull/9370) **dannykopping**: upgrade to go1.20.4 + ##### Enhancements * [8067](https://github.com/grafana/loki/pull/8067) **DylanGuedes**: Distributor: Add auto-forget unhealthy members support. From 9fd5cd9df0e6b8b63f80a4051710f07c08ffa974 Mon Sep 17 00:00:00 2001 From: Salva Corts Date: Wed, 3 May 2023 13:09:31 +0200 Subject: [PATCH 11/23] Update docs 2.8.2 (#9379) **What this PR does / why we need it**: Update docs and changelog with Loki 2.8.2 changes. **Which issue(s) this PR fixes**: Fixes # **Special notes for your reviewer**: **Checklist** - [ ] Reviewed the [`CONTRIBUTING.md`](https://github.com/grafana/loki/blob/main/CONTRIBUTING.md) guide (**required**) - [ ] Documentation added - [ ] Tests updated - [ ] `CHANGELOG.md` updated - [ ] Changes that require user attention or interaction to upgrade are documented in `docs/sources/upgrading/_index.md` --- CHANGELOG.md | 19 ++++++++++++++----- docs/sources/installation/docker.md | 18 +++++++++--------- examples/getting-started/docker-compose.yaml | 6 +++--- .../loki-operator.clusterserviceversion.yaml | 4 ++-- .../loki-operator.clusterserviceversion.yaml | 4 ++-- .../manager_related_image_patch.yaml | 2 +- .../manager_related_image_patch.yaml | 2 +- .../manager_related_image_patch.yaml | 2 +- operator/hack/addons_dev.yaml | 4 ++-- operator/hack/addons_ocp.yaml | 4 ++-- operator/internal/manifests/var.go | 2 +- production/docker-compose.yaml | 4 ++-- production/docker/docker-compose.yaml | 8 ++++---- 13 files changed, 44 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d839a78100351..ef5707f17ddce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,10 +4,6 @@ #### Loki -##### Security - -* [9370](https://github.com/grafana/loki/pull/9370) **dannykopping**: upgrade to go1.20.4 - ##### Enhancements * [8067](https://github.com/grafana/loki/pull/8067) **DylanGuedes**: Distributor: Add auto-forget unhealthy members support. @@ -49,7 +45,6 @@ ##### Enhancements * [8474](https://github.com/grafana/loki/pull/8787) **andriikushch**: Promtail: Add a new target for the Azure Event Hubs -* [8994](https://github.com/grafana/loki/pull/8994) **DylanGuedes**: Promtail: Add new `decompression` configuration to customize the decompressor behavior. * [8874](https://github.com/grafana/loki/pull/8874) **rfratto**: Promtail: Support expoential backoff when polling unchanged files for logs. ##### Fixes @@ -80,6 +75,20 @@ * [8855](https://github.com/grafana/loki/pull/8855) **JoaoBraveCoding**: Add gRPC port to loki compactor mixin * [8880](https://github.com/grafana/loki/pull/8880) **JoaoBraveCoding**: Normalize headless service name for query-frontend/scheduler +## 2.8.2 (2023-05-03) + +#### Loki + +##### Security + +* [9370](https://github.com/grafana/loki/pull/9370) **dannykopping**: upgrade to go1.20.4 + +#### Promtail + +##### Enhancements + +* [8994](https://github.com/grafana/loki/pull/8994) **DylanGuedes**: Promtail: Add new `decompression` configuration to customize the decompressor behavior. + ## 2.8.1 (2023-04-24) #### Loki diff --git a/docs/sources/installation/docker.md b/docs/sources/installation/docker.md index 915b5e8a71bda..d037288ee3fa5 100644 --- a/docs/sources/installation/docker.md +++ b/docs/sources/installation/docker.md @@ -22,10 +22,10 @@ The configuration acquired with these installation instructions run Loki as a si Copy and paste the commands below into your command line. ```bash -wget https://raw.githubusercontent.com/grafana/loki/v2.8.0/cmd/loki/loki-local-config.yaml -O loki-config.yaml -docker run --name loki -d -v $(pwd):/mnt/config -p 3100:3100 grafana/loki:2.8.0 -config.file=/mnt/config/loki-config.yaml -wget https://raw.githubusercontent.com/grafana/loki/v2.8.0/clients/cmd/promtail/promtail-docker-config.yaml -O promtail-config.yaml -docker run --name promtail -d -v $(pwd):/mnt/config -v /var/log:/var/log --link loki grafana/promtail:2.8.0 -config.file=/mnt/config/promtail-config.yaml +wget https://raw.githubusercontent.com/grafana/loki/v2.8.2/cmd/loki/loki-local-config.yaml -O loki-config.yaml +docker run --name loki -d -v $(pwd):/mnt/config -p 3100:3100 grafana/loki:2.8.2 -config.file=/mnt/config/loki-config.yaml +wget https://raw.githubusercontent.com/grafana/loki/v2.8.2/clients/cmd/promtail/promtail-docker-config.yaml -O promtail-config.yaml +docker run --name promtail -d -v $(pwd):/mnt/config -v /var/log:/var/log --link loki grafana/promtail:2.8.2 -config.file=/mnt/config/promtail-config.yaml ``` When finished, `loki-config.yaml` and `promtail-config.yaml` are downloaded in the directory you chose. Docker containers are running Loki and Promtail using those config files. @@ -40,10 +40,10 @@ Copy and paste the commands below into your terminal. Note that you will need to ```bash cd "" -wget https://raw.githubusercontent.com/grafana/loki/v2.8.0/cmd/loki/loki-local-config.yaml -O loki-config.yaml -docker run --name loki -v :/mnt/config -p 3100:3100 grafana/loki:2.8.0 --config.file=/mnt/config/loki-config.yaml -wget https://raw.githubusercontent.com/grafana/loki/v2.8.0/clients/cmd/promtail/promtail-docker-config.yaml -O promtail-config.yaml -docker run -v :/mnt/config -v /var/log:/var/log --link loki grafana/promtail:2.8.0 --config.file=/mnt/config/promtail-config.yaml +wget https://raw.githubusercontent.com/grafana/loki/v2.8.2/cmd/loki/loki-local-config.yaml -O loki-config.yaml +docker run --name loki -v :/mnt/config -p 3100:3100 grafana/loki:2.8.2 --config.file=/mnt/config/loki-config.yaml +wget https://raw.githubusercontent.com/grafana/loki/v2.8.2/clients/cmd/promtail/promtail-docker-config.yaml -O promtail-config.yaml +docker run -v :/mnt/config -v /var/log:/var/log --link loki grafana/promtail:2.8.2 --config.file=/mnt/config/promtail-config.yaml ``` When finished, `loki-config.yaml` and `promtail-config.yaml` are downloaded in the directory you chose. Docker containers are running Loki and Promtail using those config files. @@ -55,6 +55,6 @@ Navigate to http://localhost:3100/metrics to view the output. Run the following commands in your command line. They work for Windows or Linux systems. ```bash -wget https://raw.githubusercontent.com/grafana/loki/v2.8.0/production/docker-compose.yaml -O docker-compose.yaml +wget https://raw.githubusercontent.com/grafana/loki/v2.8.2/production/docker-compose.yaml -O docker-compose.yaml docker-compose -f docker-compose.yaml up ``` diff --git a/examples/getting-started/docker-compose.yaml b/examples/getting-started/docker-compose.yaml index 7956d9ddeda39..c04787611922e 100644 --- a/examples/getting-started/docker-compose.yaml +++ b/examples/getting-started/docker-compose.yaml @@ -6,7 +6,7 @@ networks: services: read: - image: grafana/loki:2.8.0 + image: grafana/loki:2.8.2 command: "-config.file=/etc/loki/config.yaml -target=read" ports: - 3101:3100 @@ -27,7 +27,7 @@ services: - loki write: - image: grafana/loki:2.8.0 + image: grafana/loki:2.8.2 command: "-config.file=/etc/loki/config.yaml -target=write" ports: - 3102:3100 @@ -46,7 +46,7 @@ services: <<: *loki-dns promtail: - image: grafana/promtail:2.8.0 + image: grafana/promtail:2.8.2 volumes: - ./promtail-local-config.yaml:/etc/promtail/config.yaml:ro - /var/run/docker.sock:/var/run/docker.sock diff --git a/operator/bundle/community-openshift/manifests/loki-operator.clusterserviceversion.yaml b/operator/bundle/community-openshift/manifests/loki-operator.clusterserviceversion.yaml index 56cf062946f42..649b53ccd107b 100644 --- a/operator/bundle/community-openshift/manifests/loki-operator.clusterserviceversion.yaml +++ b/operator/bundle/community-openshift/manifests/loki-operator.clusterserviceversion.yaml @@ -1532,7 +1532,7 @@ spec: - /manager env: - name: RELATED_IMAGE_LOKI - value: docker.io/grafana/loki:2.8.0 + value: docker.io/grafana/loki:2.8.2 - name: RELATED_IMAGE_GATEWAY value: quay.io/observatorium/api:latest - name: RELATED_IMAGE_OPA @@ -1653,7 +1653,7 @@ spec: provider: name: Grafana Loki SIG Operator relatedImages: - - image: docker.io/grafana/loki:2.8.0 + - image: docker.io/grafana/loki:2.8.2 name: loki - image: quay.io/observatorium/api:latest name: gateway diff --git a/operator/bundle/community/manifests/loki-operator.clusterserviceversion.yaml b/operator/bundle/community/manifests/loki-operator.clusterserviceversion.yaml index ad1c201ec1b05..53ab5d9b254d0 100644 --- a/operator/bundle/community/manifests/loki-operator.clusterserviceversion.yaml +++ b/operator/bundle/community/manifests/loki-operator.clusterserviceversion.yaml @@ -1518,7 +1518,7 @@ spec: - /manager env: - name: RELATED_IMAGE_LOKI - value: docker.io/grafana/loki:2.8.0 + value: docker.io/grafana/loki:2.8.2 - name: RELATED_IMAGE_GATEWAY value: quay.io/observatorium/api:latest - name: RELATED_IMAGE_OPA @@ -1634,7 +1634,7 @@ spec: provider: name: Grafana Loki SIG Operator relatedImages: - - image: docker.io/grafana/loki:2.8.0 + - image: docker.io/grafana/loki:2.8.2 name: loki - image: quay.io/observatorium/api:latest name: gateway diff --git a/operator/config/overlays/community-openshift/manager_related_image_patch.yaml b/operator/config/overlays/community-openshift/manager_related_image_patch.yaml index 18d4ebbab8cf1..f5748d4053c45 100644 --- a/operator/config/overlays/community-openshift/manager_related_image_patch.yaml +++ b/operator/config/overlays/community-openshift/manager_related_image_patch.yaml @@ -9,7 +9,7 @@ spec: - name: manager env: - name: RELATED_IMAGE_LOKI - value: docker.io/grafana/loki:2.8.0 + value: docker.io/grafana/loki:2.8.2 - name: RELATED_IMAGE_GATEWAY value: quay.io/observatorium/api:latest - name: RELATED_IMAGE_OPA diff --git a/operator/config/overlays/community/manager_related_image_patch.yaml b/operator/config/overlays/community/manager_related_image_patch.yaml index 18d4ebbab8cf1..f5748d4053c45 100644 --- a/operator/config/overlays/community/manager_related_image_patch.yaml +++ b/operator/config/overlays/community/manager_related_image_patch.yaml @@ -9,7 +9,7 @@ spec: - name: manager env: - name: RELATED_IMAGE_LOKI - value: docker.io/grafana/loki:2.8.0 + value: docker.io/grafana/loki:2.8.2 - name: RELATED_IMAGE_GATEWAY value: quay.io/observatorium/api:latest - name: RELATED_IMAGE_OPA diff --git a/operator/config/overlays/development/manager_related_image_patch.yaml b/operator/config/overlays/development/manager_related_image_patch.yaml index 6a1a2966ab737..a561bb1cf0b78 100644 --- a/operator/config/overlays/development/manager_related_image_patch.yaml +++ b/operator/config/overlays/development/manager_related_image_patch.yaml @@ -9,6 +9,6 @@ spec: - name: manager env: - name: RELATED_IMAGE_LOKI - value: docker.io/grafana/loki:2.8.0 + value: docker.io/grafana/loki:2.8.2 - name: RELATED_IMAGE_GATEWAY value: quay.io/observatorium/api:latest diff --git a/operator/hack/addons_dev.yaml b/operator/hack/addons_dev.yaml index 1f6d1ad24dfea..4ff2198487394 100644 --- a/operator/hack/addons_dev.yaml +++ b/operator/hack/addons_dev.yaml @@ -29,7 +29,7 @@ spec: spec: containers: - name: logcli - image: docker.io/grafana/logcli:2.8.0-amd64 + image: docker.io/grafana/logcli:2.8.2-amd64 imagePullPolicy: IfNotPresent command: - /bin/sh @@ -73,7 +73,7 @@ spec: spec: containers: - name: promtail - image: docker.io/grafana/promtail:2.8.0 + image: docker.io/grafana/promtail:2.8.2 args: - -config.file=/etc/promtail/promtail.yaml - -log.level=info diff --git a/operator/hack/addons_ocp.yaml b/operator/hack/addons_ocp.yaml index 3eaf05acc1c76..1cbac3a630251 100644 --- a/operator/hack/addons_ocp.yaml +++ b/operator/hack/addons_ocp.yaml @@ -29,7 +29,7 @@ spec: spec: containers: - name: logcli - image: docker.io/grafana/logcli:2.8.0-amd64 + image: docker.io/grafana/logcli:2.8.2-amd64 imagePullPolicy: IfNotPresent command: - /bin/sh @@ -70,7 +70,7 @@ spec: spec: containers: - name: promtail - image: docker.io/grafana/promtail:2.8.0 + image: docker.io/grafana/promtail:2.8.2 args: - -config.file=/etc/promtail/promtail.yaml - -log.level=info diff --git a/operator/internal/manifests/var.go b/operator/internal/manifests/var.go index 56e7b1a99b375..a207b789e3df1 100644 --- a/operator/internal/manifests/var.go +++ b/operator/internal/manifests/var.go @@ -58,7 +58,7 @@ const ( EnvRelatedImageGateway = "RELATED_IMAGE_GATEWAY" // DefaultContainerImage declares the default fallback for loki image. - DefaultContainerImage = "docker.io/grafana/loki:2.8.0" + DefaultContainerImage = "docker.io/grafana/loki:2.8.2" // DefaultLokiStackGatewayImage declares the default image for lokiStack-gateway. DefaultLokiStackGatewayImage = "quay.io/observatorium/api:latest" diff --git a/production/docker-compose.yaml b/production/docker-compose.yaml index bc044b1f7d6d5..cdb2c3a6b2410 100644 --- a/production/docker-compose.yaml +++ b/production/docker-compose.yaml @@ -5,7 +5,7 @@ networks: services: loki: - image: grafana/loki:2.8.0 + image: grafana/loki:2.8.2 ports: - "3100:3100" command: -config.file=/etc/loki/local-config.yaml @@ -13,7 +13,7 @@ services: - loki promtail: - image: grafana/promtail:2.8.0 + image: grafana/promtail:2.8.2 volumes: - /var/log:/var/log command: -config.file=/etc/promtail/config.yml diff --git a/production/docker/docker-compose.yaml b/production/docker/docker-compose.yaml index 70f2de1a9da1f..fc3c0da7ead11 100644 --- a/production/docker/docker-compose.yaml +++ b/production/docker/docker-compose.yaml @@ -16,7 +16,7 @@ services: # Loki would not have permissions to create the directories. # Therefore the init container changes permissions of the mounted directory. init: - image: grafana/loki:2.8.0 + image: grafana/loki:2.8.2 user: root entrypoint: - "chown" @@ -73,7 +73,7 @@ services: - ./loki/:/var/log/ promtail: - image: grafana/promtail:2.8.0 + image: grafana/promtail:2.8.2 volumes: - ./loki/:/var/log/ - ./config:/etc/promtail/ @@ -115,7 +115,7 @@ services: - loki loki-read: - image: grafana/loki:2.8.0 + image: grafana/loki:2.8.2 volumes: - ./config:/etc/loki/ - ./rules:/loki/rules:ro @@ -138,7 +138,7 @@ services: # only needed for interactive debugging with dlv loki-write: - image: grafana/loki:2.8.0 + image: grafana/loki:2.8.2 volumes: - ./config:/etc/loki/ ports: From 5843fc4bc981592ab790699d31bd257b17f5cd45 Mon Sep 17 00:00:00 2001 From: Joao Marcal Date: Wed, 3 May 2023 13:10:21 +0200 Subject: [PATCH 12/23] Add default PodAntiAffinity to Query-Frontend (#9343) Signed-off-by: Joao Marcal --- operator/CHANGELOG.md | 1 + .../internal/manifests/query-frontend_test.go | 33 +++++++++++++++++++ operator/internal/manifests/var.go | 5 +-- 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/operator/CHANGELOG.md b/operator/CHANGELOG.md index b52f75e00dc4b..7811e824a92d9 100644 --- a/operator/CHANGELOG.md +++ b/operator/CHANGELOG.md @@ -2,6 +2,7 @@ - [9378](https://github.com/grafana/loki/pull/9378) **aminesnow**: Add zone aware API spec validation - [9315](https://github.com/grafana/loki/pull/9315) **aminesnow**: Add zone awareness spec to LokiStack +- [9343](https://github.com/grafana/loki/pull/9343) **JoaoBraveCoding**: Add default PodAntiAffinity to Query Frontend - [9339](https://github.com/grafana/loki/pull/9339) **JoaoBraveCoding**: Add default PodAntiAffinity to Ruler - [9329](https://github.com/grafana/loki/pull/9329) **JoaoBraveCoding**: Add default PodAntiAffinity to Ingester - [9262](https://github.com/grafana/loki/pull/9262) **btaani**: Add PodDisruptionBudget to the Ruler diff --git a/operator/internal/manifests/query-frontend_test.go b/operator/internal/manifests/query-frontend_test.go index 783cd028f83a1..943a69ba47be8 100644 --- a/operator/internal/manifests/query-frontend_test.go +++ b/operator/internal/manifests/query-frontend_test.go @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/require" corev1 "k8s.io/api/core/v1" policyv1 "k8s.io/api/policy/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" ) @@ -133,3 +134,35 @@ func TestNewQueryFrontendDeployment_TopologySpreadConstraints(t *testing.T) { }, }, depl.Spec.Template.Spec.TopologySpreadConstraints) } + +func TestQueryFrontendPodAntiAffinity(t *testing.T) { + sts := NewQueryFrontendDeployment(Options{ + Name: "abcd", + Namespace: "efgh", + Stack: lokiv1.LokiStackSpec{ + Template: &lokiv1.LokiTemplateSpec{ + QueryFrontend: &lokiv1.LokiComponentSpec{ + Replicas: 1, + }, + }, + }, + }) + expectedPodAntiAffinity := &corev1.PodAntiAffinity{ + PreferredDuringSchedulingIgnoredDuringExecution: []corev1.WeightedPodAffinityTerm{ + { + Weight: 100, + PodAffinityTerm: corev1.PodAffinityTerm{ + LabelSelector: &metav1.LabelSelector{ + MatchLabels: map[string]string{ + "app.kubernetes.io/component": LabelQueryFrontendComponent, + "app.kubernetes.io/instance": "abcd", + }, + }, + TopologyKey: "kubernetes.io/hostname", + }, + }, + }, + } + require.NotNil(t, sts.Spec.Template.Spec.Affinity) + require.Equal(t, expectedPodAntiAffinity, sts.Spec.Template.Spec.Affinity.PodAntiAffinity) +} \ No newline at end of file diff --git a/operator/internal/manifests/var.go b/operator/internal/manifests/var.go index a207b789e3df1..b692a4dfb8924 100644 --- a/operator/internal/manifests/var.go +++ b/operator/internal/manifests/var.go @@ -113,8 +113,9 @@ var ( defaultConfigMapMode = int32(420) volumeFileSystemMode = corev1.PersistentVolumeFilesystem podAntiAffinityComponents = map[string]struct{}{ - LabelIngesterComponent: {}, - LabelRulerComponent: {}, + LabelIngesterComponent: {}, + LabelRulerComponent: {}, + LabelQueryFrontendComponent: {}, } ) From 7768ee89103d03b7bc1c39c7f3cccbf7e59c5d27 Mon Sep 17 00:00:00 2001 From: "Grot (@grafanabot)" <43478413+grafanabot@users.noreply.github.com> Date: Wed, 3 May 2023 07:29:55 -0400 Subject: [PATCH 13/23] [CI/CD] Update yaml file `./production/helm/loki/Chart.yaml` (+1 other) (#9385) **Here is a summary of the updates contained in this PR:** *** Update attribute `$.appVersion` in yaml file `./production/helm/loki/Chart.yaml` to the following value: `2.8.2` *** Bump version of Helm Chart Add changelog entry to `./production/helm/loki/CHANGELOG.md` Re-generate docs Co-authored-by: Salva Corts --- production/helm/loki/CHANGELOG.md | 5 +++++ production/helm/loki/Chart.yaml | 4 ++-- production/helm/loki/README.md | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/production/helm/loki/CHANGELOG.md b/production/helm/loki/CHANGELOG.md index 3e268b5cb40ee..6f95f0302c687 100644 --- a/production/helm/loki/CHANGELOG.md +++ b/production/helm/loki/CHANGELOG.md @@ -13,6 +13,11 @@ Entries should include a reference to the pull request that introduced the chang [//]: # ( : do not remove this line. This locator is used by the CI pipeline to automatically create a changelog entry for each new Loki release. Add other chart versions and respective changelog entries bellow this line.) +## 5.4.0 + +- [CHANGE] Changed version of Loki to 2.8.2 + + - [CHANGE] Change default GEL and Loki versions to 1.7.1 and 2.8.1 respectively - [BUGFIX] Fix dns port in network-policy diff --git a/production/helm/loki/Chart.yaml b/production/helm/loki/Chart.yaml index e80f529f507ee..09e35dd190525 100644 --- a/production/helm/loki/Chart.yaml +++ b/production/helm/loki/Chart.yaml @@ -2,8 +2,8 @@ apiVersion: v2 name: loki description: Helm chart for Grafana Loki in simple, scalable mode type: application -appVersion: 2.8.1 -version: 5.3.1 +appVersion: 2.8.2 +version: 5.4.0 home: https://grafana.github.io/helm-charts sources: - https://github.com/grafana/loki diff --git a/production/helm/loki/README.md b/production/helm/loki/README.md index e32eabd5884bf..6e5ba59704769 100644 --- a/production/helm/loki/README.md +++ b/production/helm/loki/README.md @@ -1,6 +1,6 @@ # loki -![Version: 5.3.1](https://img.shields.io/badge/Version-5.3.1-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 2.8.1](https://img.shields.io/badge/AppVersion-2.8.1-informational?style=flat-square) +![Version: 5.4.0](https://img.shields.io/badge/Version-5.4.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 2.8.2](https://img.shields.io/badge/AppVersion-2.8.2-informational?style=flat-square) Helm chart for Grafana Loki in simple, scalable mode From dbab2def46ea65881672421d3dba44da5888e4aa Mon Sep 17 00:00:00 2001 From: "Grot (@grafanabot)" <43478413+grafanabot@users.noreply.github.com> Date: Wed, 3 May 2023 10:21:02 -0400 Subject: [PATCH 14/23] [CI/CD] Update yaml file `./production/helm/loki/values.yaml` (+1 other) (#9388) **Here is a summary of the updates contained in this PR:** *** Update attribute `$.enterprise.version` in yaml file `./production/helm/loki/values.yaml` to the following value: `v1.7.2` *** Bump version of Helm Chart Add changelog entry to `./production/helm/loki/CHANGELOG.md` Re-generate docs --------- Co-authored-by: Salva Corts --- docs/sources/installation/helm/reference.md | 2 +- production/helm/loki/CHANGELOG.md | 5 +++++ production/helm/loki/Chart.yaml | 2 +- production/helm/loki/README.md | 2 +- production/helm/loki/values.yaml | 2 +- 5 files changed, 9 insertions(+), 4 deletions(-) diff --git a/docs/sources/installation/helm/reference.md b/docs/sources/installation/helm/reference.md index 43133692efccc..963784d28cd27 100644 --- a/docs/sources/installation/helm/reference.md +++ b/docs/sources/installation/helm/reference.md @@ -706,7 +706,7 @@ false string
-"v1.7.1"
+"v1.7.2"
 
diff --git a/production/helm/loki/CHANGELOG.md b/production/helm/loki/CHANGELOG.md index 6f95f0302c687..b8270c071a5d7 100644 --- a/production/helm/loki/CHANGELOG.md +++ b/production/helm/loki/CHANGELOG.md @@ -13,6 +13,11 @@ Entries should include a reference to the pull request that introduced the chang [//]: # ( : do not remove this line. This locator is used by the CI pipeline to automatically create a changelog entry for each new Loki release. Add other chart versions and respective changelog entries bellow this line.) +## 5.5.0 + +- [CHANGE] Changed version of Grafana Enterprise Logs to v1.7.2 + + ## 5.4.0 - [CHANGE] Changed version of Loki to 2.8.2 diff --git a/production/helm/loki/Chart.yaml b/production/helm/loki/Chart.yaml index 09e35dd190525..a279716899a6d 100644 --- a/production/helm/loki/Chart.yaml +++ b/production/helm/loki/Chart.yaml @@ -3,7 +3,7 @@ name: loki description: Helm chart for Grafana Loki in simple, scalable mode type: application appVersion: 2.8.2 -version: 5.4.0 +version: 5.5.0 home: https://grafana.github.io/helm-charts sources: - https://github.com/grafana/loki diff --git a/production/helm/loki/README.md b/production/helm/loki/README.md index 6e5ba59704769..35e10be99320c 100644 --- a/production/helm/loki/README.md +++ b/production/helm/loki/README.md @@ -1,6 +1,6 @@ # loki -![Version: 5.4.0](https://img.shields.io/badge/Version-5.4.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 2.8.2](https://img.shields.io/badge/AppVersion-2.8.2-informational?style=flat-square) +![Version: 5.5.0](https://img.shields.io/badge/Version-5.5.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 2.8.2](https://img.shields.io/badge/AppVersion-2.8.2-informational?style=flat-square) Helm chart for Grafana Loki in simple, scalable mode diff --git a/production/helm/loki/values.yaml b/production/helm/loki/values.yaml index dda4c1bbc3129..14fade0a14404 100644 --- a/production/helm/loki/values.yaml +++ b/production/helm/loki/values.yaml @@ -295,7 +295,7 @@ enterprise: # Enable enterprise features, license must be provided enabled: false # Default verion of GEL to deploy - version: v1.7.1 + version: v1.7.2 # -- Optional name of the GEL cluster, otherwise will use .Release.Name # The cluster name must match what is in your GEL license cluster_name: null From e66fac769cb54ac8b9ed6da2f8319b720d98f1fa Mon Sep 17 00:00:00 2001 From: Salva Corts Date: Wed, 3 May 2023 16:35:01 +0200 Subject: [PATCH 15/23] Add missing release notes for 2.8.2 (#9389) **What this PR does / why we need it**: Part of v2.8.2 release --------- Co-authored-by: J Stickler --- docs/sources/release-notes/v2-8.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/sources/release-notes/v2-8.md b/docs/sources/release-notes/v2-8.md index b85afeb4d0168..b5c601cbdd3e9 100644 --- a/docs/sources/release-notes/v2-8.md +++ b/docs/sources/release-notes/v2-8.md @@ -22,8 +22,12 @@ As always, please read the [upgrade guide]({{}}) bef ## Bug fixes -### 2.8.1 (2023-04-21) +### 2.8.2 (2023-05-03) + +* Update Go to 1.20.4 to address security vulnerabilities in the previous Go version. +* *Promtail*: Add new `decompression` configuration to customize the decompressor behavior. +### 2.8.1 (2023-04-21) * Fix bug that was dropping index if period is a zero value. * Fix redis client to prevent it from incorrectly choosing cluster mode with local address. From dec4e82b842d1fcee883cf825922e6460b59e9da Mon Sep 17 00:00:00 2001 From: Periklis Tsirakidis Date: Wed, 3 May 2023 18:18:21 +0200 Subject: [PATCH 16/23] operator: Add support for custom tenant topology in rules (#9366) --- operator/CHANGELOG.md | 1 + operator/apis/loki/v1/v1.go | 5 + .../validation/openshift/alertingrule.go | 33 ++++-- .../validation/openshift/alertingrule_test.go | 109 ++++++++++++++++++ .../internal/validation/openshift/common.go | 20 ++++ .../validation/openshift/recordingrule.go | 9 ++ .../openshift/recordingrule_test.go | 57 +++++++++ 7 files changed, 222 insertions(+), 12 deletions(-) diff --git a/operator/CHANGELOG.md b/operator/CHANGELOG.md index 7811e824a92d9..7f6dfd97ef058 100644 --- a/operator/CHANGELOG.md +++ b/operator/CHANGELOG.md @@ -1,6 +1,7 @@ ## Main - [9378](https://github.com/grafana/loki/pull/9378) **aminesnow**: Add zone aware API spec validation +- [9366](https://github.com/grafana/loki/pull/9366) **periklis**: Add support for custom tenant topology in rules - [9315](https://github.com/grafana/loki/pull/9315) **aminesnow**: Add zone awareness spec to LokiStack - [9343](https://github.com/grafana/loki/pull/9343) **JoaoBraveCoding**: Add default PodAntiAffinity to Query Frontend - [9339](https://github.com/grafana/loki/pull/9339) **JoaoBraveCoding**: Add default PodAntiAffinity to Ruler diff --git a/operator/apis/loki/v1/v1.go b/operator/apis/loki/v1/v1.go index 4863cd693623b..f728e8dc70255 100644 --- a/operator/apis/loki/v1/v1.go +++ b/operator/apis/loki/v1/v1.go @@ -28,6 +28,11 @@ const ( StorageSchemaUpdateBuffer = time.Hour * 2 ) +const ( + // The AnnotationDisableTenantValidation annotation can contain a boolean value that, if true, disables the tenant-ID validation. + AnnotationDisableTenantValidation = "loki.grafana.com/disable-tenant-validation" +) + var ( // ErrGroupNamesNotUnique is the error type when loki groups have not unique names. ErrGroupNamesNotUnique = errors.New("Group names are not unique") diff --git a/operator/internal/validation/openshift/alertingrule.go b/operator/internal/validation/openshift/alertingrule.go index 1fc43d061164f..e184729794036 100644 --- a/operator/internal/validation/openshift/alertingrule.go +++ b/operator/internal/validation/openshift/alertingrule.go @@ -14,24 +14,33 @@ import ( func AlertingRuleValidator(_ context.Context, alertingRule *lokiv1.AlertingRule) field.ErrorList { var allErrs field.ErrorList + validateTenantIDs, fieldErr := tenantIDValidationEnabled(alertingRule.Annotations) + if fieldErr != nil { + return field.ErrorList{fieldErr} + } + // Check tenant matches expected value tenantID := alertingRule.Spec.TenantID - wantTenant := tenantForNamespace(alertingRule.Namespace) - if !slices.Contains(wantTenant, tenantID) { - allErrs = append(allErrs, field.Invalid( - field.NewPath("spec").Child("tenantID"), - tenantID, - fmt.Sprintf("AlertingRule does not use correct tenant %q", wantTenant))) + if validateTenantIDs { + wantTenant := tenantForNamespace(alertingRule.Namespace) + if !slices.Contains(wantTenant, tenantID) { + allErrs = append(allErrs, field.Invalid( + field.NewPath("spec").Child("tenantID"), + tenantID, + fmt.Sprintf("AlertingRule does not use correct tenant %q", wantTenant))) + } } for i, g := range alertingRule.Spec.Groups { for j, rule := range g.Rules { - if err := validateRuleExpression(alertingRule.Namespace, tenantID, rule.Expr); err != nil { - allErrs = append(allErrs, field.Invalid( - field.NewPath("spec").Child("groups").Index(i).Child("rules").Index(j).Child("expr"), - rule.Expr, - err.Error(), - )) + if validateTenantIDs { + if err := validateRuleExpression(alertingRule.Namespace, tenantID, rule.Expr); err != nil { + allErrs = append(allErrs, field.Invalid( + field.NewPath("spec").Child("groups").Index(i).Child("rules").Index(j).Child("expr"), + rule.Expr, + err.Error(), + )) + } } if err := validateRuleLabels(rule.Labels); err != nil { diff --git a/operator/internal/validation/openshift/alertingrule_test.go b/operator/internal/validation/openshift/alertingrule_test.go index f2f32acba7bb7..ae911d537c67e 100644 --- a/operator/internal/validation/openshift/alertingrule_test.go +++ b/operator/internal/validation/openshift/alertingrule_test.go @@ -113,6 +113,115 @@ func TestAlertingRuleValidator(t *testing.T) { }, }, }, + { + desc: "custom tenant topology enabled", + spec: &lokiv1.AlertingRule{ + ObjectMeta: metav1.ObjectMeta{ + Name: "alerting-rule", + Namespace: "openshift-example", + Annotations: map[string]string{ + lokiv1.AnnotationDisableTenantValidation: "true", + }, + }, + Spec: lokiv1.AlertingRuleSpec{ + TenantID: "foobar", + Groups: []*lokiv1.AlertingRuleGroup{ + { + Rules: []*lokiv1.AlertingRuleGroupSpec{ + { + Expr: `sum(rate({kubernetes_namespace_name="openshift-example", level="error"}[5m])) by (job) > 0.1`, + Labels: map[string]string{ + severityLabelName: "warning", + }, + Annotations: map[string]string{ + summaryAnnotationName: "alert summary", + descriptionAnnotationName: "alert description", + }, + }, + }, + }, + }, + }, + }, + }, + { + desc: "custom tenant topology disabled", + spec: &lokiv1.AlertingRule{ + ObjectMeta: metav1.ObjectMeta{ + Name: "alerting-rule", + Namespace: "openshift-example", + Annotations: map[string]string{ + lokiv1.AnnotationDisableTenantValidation: "false", + }, + }, + Spec: lokiv1.AlertingRuleSpec{ + TenantID: "foobar", + Groups: []*lokiv1.AlertingRuleGroup{ + { + Rules: []*lokiv1.AlertingRuleGroupSpec{ + { + Expr: `sum(rate({kubernetes_namespace_name="openshift-example", level="error"}[5m])) by (job) > 0.1`, + Labels: map[string]string{ + severityLabelName: "warning", + }, + Annotations: map[string]string{ + summaryAnnotationName: "alert summary", + descriptionAnnotationName: "alert description", + }, + }, + }, + }, + }, + }, + }, + wantErrors: []*field.Error{ + { + Type: field.ErrorTypeInvalid, + Field: "spec.tenantID", + BadValue: "foobar", + Detail: `AlertingRule does not use correct tenant ["infrastructure"]`, + }, + }, + }, + { + desc: "wrong tenant topology", + spec: &lokiv1.AlertingRule{ + ObjectMeta: metav1.ObjectMeta{ + Name: "alerting-rule", + Namespace: "openshift-example", + Annotations: map[string]string{ + lokiv1.AnnotationDisableTenantValidation: "not-valid", + }, + }, + Spec: lokiv1.AlertingRuleSpec{ + TenantID: "foobar", + Groups: []*lokiv1.AlertingRuleGroup{ + { + Rules: []*lokiv1.AlertingRuleGroupSpec{ + { + Expr: `sum(rate({kubernetes_namespace_name="openshift-example", level="error"}[5m])) by (job) > 0.1`, + Labels: map[string]string{ + severityLabelName: "warning", + }, + Annotations: map[string]string{ + summaryAnnotationName: "alert summary", + descriptionAnnotationName: "alert description", + }, + }, + }, + }, + }, + }, + }, + wantErrors: []*field.Error{ + { + Type: field.ErrorTypeInvalid, + Field: `metadata.annotations[loki.grafana.com/disable-tenant-validation]`, + BadValue: "not-valid", + Detail: `strconv.ParseBool: parsing "not-valid": invalid syntax`, + }, + }, + }, { desc: "expression does not parse", spec: &lokiv1.AlertingRule{ diff --git a/operator/internal/validation/openshift/common.go b/operator/internal/validation/openshift/common.go index c85a0e02bac5f..810a58e567ca5 100644 --- a/operator/internal/validation/openshift/common.go +++ b/operator/internal/validation/openshift/common.go @@ -2,9 +2,11 @@ package openshift import ( "regexp" + "strconv" "strings" lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" + "k8s.io/apimachinery/pkg/util/validation/field" "github.com/grafana/loki/pkg/logql/syntax" "github.com/prometheus/prometheus/model/labels" @@ -26,6 +28,24 @@ const ( var severityRe = regexp.MustCompile("^critical|warning|info$") +func tenantIDValidationEnabled(annotations map[string]string) (bool, *field.Error) { + v, ok := annotations[lokiv1.AnnotationDisableTenantValidation] + if !ok { + return true, nil + } + + disableValidation, err := strconv.ParseBool(v) + if err != nil { + return false, field.Invalid( + field.NewPath("metadata").Child("annotations").Key(lokiv1.AnnotationDisableTenantValidation), + v, + err.Error(), + ) + } + + return !disableValidation, nil +} + func validateRuleExpression(namespace, tenantID, rawExpr string) error { // Check if the LogQL parser can parse the rule expression expr, err := syntax.ParseExpr(rawExpr) diff --git a/operator/internal/validation/openshift/recordingrule.go b/operator/internal/validation/openshift/recordingrule.go index 3f15c9eb4a607..89893d1378ddb 100644 --- a/operator/internal/validation/openshift/recordingrule.go +++ b/operator/internal/validation/openshift/recordingrule.go @@ -12,6 +12,15 @@ import ( // RecordingRuleValidator does extended-validation of RecordingRule resources for Openshift-based deployments. func RecordingRuleValidator(_ context.Context, recordingRule *lokiv1.RecordingRule) field.ErrorList { + validateTenantIDs, fieldErr := tenantIDValidationEnabled(recordingRule.Annotations) + if fieldErr != nil { + return field.ErrorList{fieldErr} + } + + if !validateTenantIDs { + return nil + } + var allErrs field.ErrorList // Check tenant matches expected value diff --git a/operator/internal/validation/openshift/recordingrule_test.go b/operator/internal/validation/openshift/recordingrule_test.go index 57ab3e69c5d19..139b9e8dfd6ad 100644 --- a/operator/internal/validation/openshift/recordingrule_test.go +++ b/operator/internal/validation/openshift/recordingrule_test.go @@ -68,6 +68,63 @@ func TestRecordingRuleValidator(t *testing.T) { }, }, }, + { + desc: "custom tenant topology enabled", + spec: &lokiv1.RecordingRule{ + ObjectMeta: metav1.ObjectMeta{ + Name: "recording-rule", + Namespace: "openshift-example", + Annotations: map[string]string{ + lokiv1.AnnotationDisableTenantValidation: "true", + }, + }, + Spec: lokiv1.RecordingRuleSpec{ + TenantID: "foobar", + Groups: []*lokiv1.RecordingRuleGroup{ + { + Rules: []*lokiv1.RecordingRuleGroupSpec{ + { + Expr: `sum(rate({kubernetes_namespace_name="openshift-example", level="error"}[5m])) by (job) > 0.1`, + }, + }, + }, + }, + }, + }, + }, + { + desc: "wrong tenant topology", + spec: &lokiv1.RecordingRule{ + ObjectMeta: metav1.ObjectMeta{ + Name: "recording-rule", + Namespace: "openshift-example", + Annotations: map[string]string{ + lokiv1.AnnotationDisableTenantValidation: "not-valid", + }, + }, + Spec: lokiv1.RecordingRuleSpec{ + TenantID: "foobar", + Groups: []*lokiv1.RecordingRuleGroup{ + { + Rules: []*lokiv1.RecordingRuleGroupSpec{ + { + Expr: `sum(rate({kubernetes_namespace_name="openshift-example", level="error"}[5m])) by (job) > 0.1`, + }, + }, + }, + }, + }, + }, + wantErrors: []*field.Error{ + { + Type: field.ErrorTypeInvalid, + Field: `metadata.annotations[loki.grafana.com/disable-tenant-validation]`, + BadValue: "not-valid", + Detail: `strconv.ParseBool: parsing "not-valid": invalid syntax`, + }, + }, + }, + { desc: "expression does not parse", spec: &lokiv1.RecordingRule{ From 287d16e87cf3840c364e9adfb492d8df25372fe0 Mon Sep 17 00:00:00 2001 From: MattiasSegerdahl <102952046+MattiasSegerdahl@users.noreply.github.com> Date: Wed, 3 May 2023 18:22:51 +0200 Subject: [PATCH 17/23] Update _index.md (#9331) **What this PR does / why we need it**: **Which issue(s) this PR fixes**: Fixes # **Special notes for your reviewer**: **Checklist** - [ ] Reviewed the [`CONTRIBUTING.md`](https://github.com/grafana/loki/blob/main/CONTRIBUTING.md) guide (**required**) - [ ] Documentation added - [ ] Tests updated - [ ] `CHANGELOG.md` updated - [ ] Changes that require user attention or interaction to upgrade are documented in `docs/sources/upgrading/_index.md` --- docs/sources/clients/fluentd/_index.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/sources/clients/fluentd/_index.md b/docs/sources/clients/fluentd/_index.md index aa59f7fbdfde0..34f01e72deeb7 100644 --- a/docs/sources/clients/fluentd/_index.md +++ b/docs/sources/clients/fluentd/_index.md @@ -5,7 +5,7 @@ weight: 60 --- # Fluentd -Grafana Loki has a [Fluentd](https://www.fluentd.org/) output plugin called +The [Fluentd output plugin](https://www.fluentd.org/) for Grafana Loki is called `fluent-plugin-grafana-loki` that enables shipping logs to a private Loki instance or [Grafana Cloud](/products/cloud/). @@ -27,7 +27,7 @@ The Docker image `grafana/fluent-plugin-loki:master` contains [default configura This image also uses `LOKI_URL`, `LOKI_USERNAME`, and `LOKI_PASSWORD` environment variables to specify the Loki's endpoint, user, and password (you can leave the USERNAME and PASSWORD blank if they're not used). -This image will start an instance of Fluentd to forward incoming logs to the specified Loki URL. As an alternate, containerized applications can also use [docker driver plugin]({{}}) to ship logs without needing Fluentd. +This image starts an instance of Fluentd that forwards incoming logs to the specified Loki URL. As an alternate, containerized applications can also use [docker driver plugin]({{}}) to ship logs without needing Fluentd. ### Example @@ -68,7 +68,7 @@ services: **Note**: use either `` or `extra_labels` to set at least one label. -In your Fluentd configuration, use `@type loki`. Additional configuration is optional. Default values would look like this: +In your Fluentd configuration, add `@type loki`. Additional configuration is optional. Default values would look like this: ```conf @@ -126,7 +126,7 @@ You can use [record accessor](https://docs.fluentd.org/plugin-helper-overview/ap ### Extracting Kubernetes labels -As Kubernetes labels are a list of nested key-value pairs there is a separate option to extract them. +Since Kubernetes labels are a list of nested key-value pairs, a separate option is available to extract them. Note that special characters like "`. - /`" will be overwritten with `_`. Use with the `remove_keys kubernetes` option to eliminate metadata from the log. @@ -147,7 +147,7 @@ Use with the `remove_keys kubernetes` option to eliminate metadata from the log. ### Multi-worker usage -Out-of-order inserts are enabled by default in Loki; refer to [accept out-of-order writes]({{}}). +Loki enables out-of-order inserts by default; refer to [accept out-of-order writes]({{}}). If out-of-order inserts are _disabled_, attempting to insert a log entry with an earlier timestamp after a log entry with identical labels but a later timestamp, the insert will fail with `HTTP status code: 500, message: rpc error: code = Unknown desc = Entry out of order`. Therefore, in order to use this plugin in a multi worker Fluentd setup, you'll need to include the worker ID in the labels or otherwise [ensure log streams are always sent to the same worker](https://docs.fluentd.org/deployment/multi-process-workers#less-than-worker-n-greater-than-directive). For example, using [fluent-plugin-record-modifier](https://github.com/repeatedly/fluent-plugin-record-modifier): @@ -191,15 +191,15 @@ Starting with version 0.8.0, this gem uses [excon, which supports proxy with env ### `username` / `password` -Specify a username and password if the Loki server requires authentication. +If the Loki server requires authentication, specify a username and password. If using the GrafanaLab's hosted Loki, the username needs to be set to your instanceId and the password should be a Grafana.com api key. ### tenant -Loki is a multi-tenant log storage platform and all requests sent must include a tenant. For some installations the tenant will be set automatically by an authenticating proxy. Otherwise you can define a tenant to be passed through. +All requests sent to Loki, a multi-tenant log storage platform, must include a tenant. For some installations the tenant will be set automatically by an authenticating proxy. Otherwise you can define a tenant to be passed through. The tenant can be any string value. -The tenant field also supports placeholders, so it can dynamically change based on tag and record fields. Each placeholder must be added as a buffer chunk key. The following is an example of setting the tenant based on a k8s pod label: +The tenant field also supports placeholders, allowing it to dynamically change based on tag and record fields. Each placeholder must be added as a buffer chunk key. The following is an example of setting the tenant based on a k8s pod label: ```conf @@ -216,7 +216,7 @@ The tenant field also supports placeholders, so it can dynamically change based ### Client certificate verification -Specify a pair of client certificate and private key with `cert` and `key` if a reverse proxy with client certificate verification is configured in front of Loki. `ca_cert` can also be specified if the server uses custom certificate authority. +If a reverse proxy with client certificate verification is configured in front of Loki, specify a pair of client certificate and private key with `cert` and `key`. `ca_cert` can also be specified if the server uses custom certificate authority. ```conf @@ -234,7 +234,7 @@ Specify a pair of client certificate and private key with `cert` and `key` if a ### Server certificate verification -A flag to disable a server certificate verification. By default the `insecure_tls` is set to false. +A flag to disable server certificate verification. By default the `insecure_tls` is set to false. ```conf @@ -252,7 +252,7 @@ A flag to disable a server certificate verification. By default the `insecure_tl Loki is intended to index and group log streams using only a small set of labels. It is not intended for full-text indexing. When sending logs to Loki the majority of log message will be sent as a single log "line". -There are few configurations settings to control the output format. +Several configuration settings are available to control the output format. - extra_labels: (default: nil) set of labels to include with every Loki stream. eg `{"env":"dev", "datacenter": "dc1"}` - remove_keys: (default: nil) comma separated list of needless record keys to remove. All other keys will be placed into the log line. You can use [record_accessor syntax](https://docs.fluentd.org/plugin-helper-overview/api-plugin-helper-record_accessor#syntax). From 53dadd3481b1b1761a26f992a131ff5c35761f89 Mon Sep 17 00:00:00 2001 From: Ed Welch Date: Thu, 4 May 2023 04:51:47 -0400 Subject: [PATCH 18/23] Update docs to make file rotation support clearer (#9391) --- docs/sources/clients/promtail/_index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/clients/promtail/_index.md b/docs/sources/clients/promtail/_index.md index d173964b0cae0..053a21056d18c 100644 --- a/docs/sources/clients/promtail/_index.md +++ b/docs/sources/clients/promtail/_index.md @@ -94,7 +94,7 @@ Important details are: of your compressed file Loki will rate-limit your ingestion. In that case you might configure Promtail's [`limits` stage](/docs/loki/latest/clients/promtail/stages/limit/) to slow the pace or increase [ingestion limits on Loki](/docs/loki/latest/configuration/#limits_config). -* Log rotations **aren't supported as of now**, mostly because it requires us modifying Promtail to +* Log rotations on compressed files **aren't supported as of now** (log rotation is fully supported for normal files), mostly because it requires us modifying Promtail to rely on file inodes instead of file names. If you'd like to see support for it, please create a new issue on Github asking for it and explaining your use case. * If you compress a file under a folder being scraped, Promtail might try to ingest your file before you finish compressing it. To avoid it, pick a `initial_delay` that is enough to avoid it. From e12dea6a6503e0d46031891b8f1e2446b83e3219 Mon Sep 17 00:00:00 2001 From: irizzant Date: Thu, 4 May 2023 12:23:19 +0200 Subject: [PATCH 19/23] Loki microservices Tanka: fix error during manifest generation (#9362) **What this PR does / why we need it**: Fixes an error on the ServiceMonitor generated when ``` memberlist_ring_enabled: true, create_service_monitor: true, ``` It also adds some checks on `memberlist.libsonnet` to avoid generating invalid kubernetes manifests. **Which issue(s) this PR fixes**: Fixes #9361 --- production/ksonnet/loki/memberlist.libsonnet | 4 ++-- production/ksonnet/loki/servicemonitor.libsonnet | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/production/ksonnet/loki/memberlist.libsonnet b/production/ksonnet/loki/memberlist.libsonnet index e6898212d2a16..10f5b307d746e 100644 --- a/production/ksonnet/loki/memberlist.libsonnet +++ b/production/ksonnet/loki/memberlist.libsonnet @@ -121,7 +121,7 @@ compactor_statefulset+: if !$._config.memberlist_ring_enabled then {} else gossipLabel, distributor_deployment+: if !$._config.memberlist_ring_enabled then {} else gossipLabel, - index_gateway_statefulset+: if !$._config.memberlist_ring_enabled then {} else gossipLabel, + index_gateway_statefulset+: if !$._config.memberlist_ring_enabled || !$._config.use_index_gateway then {} else gossipLabel, ingester_statefulset: if $._config.multi_zone_ingester_enabled && !$._config.multi_zone_ingester_migration_enabled then {} else (super.ingester_statefulset + if !$._config.memberlist_ring_enabled then {} else gossipLabel), ingester_zone_a_statefulset+: @@ -136,7 +136,7 @@ if $._config.multi_zone_ingester_enabled && $._config.memberlist_ring_enabled then gossipLabel else {}, - query_scheduler_deployment+: if !$._config.memberlist_ring_enabled then {} else gossipLabel, + query_scheduler_deployment+: if !$._config.memberlist_ring_enabled || !$._config.query_scheduler_enabled then {} else gossipLabel, ruler_deployment+: if !$._config.memberlist_ring_enabled || !$._config.ruler_enabled || $._config.stateful_rulers then {} else gossipLabel, ruler_statefulset+: if !$._config.memberlist_ring_enabled || !$._config.ruler_enabled || !$._config.stateful_rulers then {} else gossipLabel, // Headless service (= no assigned IP, DNS returns all targets instead) pointing to gossip network members. diff --git a/production/ksonnet/loki/servicemonitor.libsonnet b/production/ksonnet/loki/servicemonitor.libsonnet index 7986117e3a50a..6c937a87b61f7 100644 --- a/production/ksonnet/loki/servicemonitor.libsonnet +++ b/production/ksonnet/loki/servicemonitor.libsonnet @@ -41,7 +41,7 @@ values: [ this[name].spec.selector.name for name in std.objectFields(this) - if std.isObject(this[name]) && std.objectHas(this[name], 'kind') && this[name].kind == 'Service' + if std.isObject(this[name]) && std.objectHas(this[name], 'kind') && this[name].kind == 'Service' && std.objectHasAll(this[name].spec.selector, 'name') ], }], }, From 39f580f319e1f7618d85b0b37b6d8e15d74fe520 Mon Sep 17 00:00:00 2001 From: Jan Jansen Date: Thu, 4 May 2023 14:11:56 +0200 Subject: [PATCH 20/23] Promtail: Break on iterate journal failure (#9155) --- CHANGELOG.md | 1 + clients/pkg/promtail/targets/journal/journaltarget.go | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ef5707f17ddce..becd094a79d49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -50,6 +50,7 @@ ##### Fixes * [8988](https://github.com/grafana/loki/pull/8988) **darxriggs**: Promtail: Prevent logging errors on normal shutdown. +* [9155](https://github.com/grafana/loki/pull/9155) **farodin91**: Promtail: Break on iterate journal failure. #### LogCLI diff --git a/clients/pkg/promtail/targets/journal/journaltarget.go b/clients/pkg/promtail/targets/journal/journaltarget.go index d528d28d43554..02bceaf535b09 100644 --- a/clients/pkg/promtail/targets/journal/journaltarget.go +++ b/clients/pkg/promtail/targets/journal/journaltarget.go @@ -206,7 +206,7 @@ func journalTargetWithReader( return } - if err == syscall.EBADMSG || err == io.EOF { + if err == syscall.EBADMSG || err == io.EOF || strings.HasPrefix(err.Error(), "failed to iterate journal:") { level.Error(t.logger).Log("msg", "unable to follow journal", "err", err.Error()) return } From 0cd388934289e80b29ad9748f6ea93fe167d50c9 Mon Sep 17 00:00:00 2001 From: Alain Pham Date: Thu, 4 May 2023 17:26:31 +0200 Subject: [PATCH 21/23] Update retention doc tsdb support of compactor (#9397) compactor now also supports tsdb in addition to boltdb-schipper **What this PR does / why we need it**: **Which issue(s) this PR fixes**: Fixes # **Special notes for your reviewer**: **Checklist** - [ ] Reviewed the [`CONTRIBUTING.md`](https://github.com/grafana/loki/blob/main/CONTRIBUTING.md) guide (**required**) - [ ] Documentation added - [ ] Tests updated - [ ] `CHANGELOG.md` updated - [ ] Changes that require user attention or interaction to upgrade are documented in `docs/sources/upgrading/_index.md` --- docs/sources/operations/storage/retention.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/sources/operations/storage/retention.md b/docs/sources/operations/storage/retention.md index 93c112652f504..7c3dcf1a4d978 100644 --- a/docs/sources/operations/storage/retention.md +++ b/docs/sources/operations/storage/retention.md @@ -8,7 +8,7 @@ Retention in Grafana Loki is achieved either through the [Table Manager](#table- By default, when `table_manager.retention_deletes_enabled` or `compactor.retention_enabled` flags are not set, then logs sent to Loki live forever. -Retention through the [Table Manager]({{}}) is achieved by relying on the object store TTL feature, and will work for both [boltdb-shipper]({{}}) store and chunk/index store. However retention through the [Compactor]({{}}) is supported only with the [boltdb-shipper]({{}}) store. +Retention through the [Table Manager]({{}}) is achieved by relying on the object store TTL feature, and will work for both [boltdb-shipper]({{}}) store and chunk/index store. However retention through the [Compactor]({{}}) is supported only with the [boltdb-shipper]({{}}) and tsdb store. The Compactor retention will become the default and have long term support. It supports more granular retention policies on per tenant and per stream use cases. From 61ee40e447dc5eee7d9d481c9048252dc02787ec Mon Sep 17 00:00:00 2001 From: Mohamed-Amine Bouqsimi Date: Wed, 10 May 2023 18:38:02 +0200 Subject: [PATCH 22/23] remove replication to zones validation --- operator/apis/loki/v1/lokistack_types.go | 1 + .../loki-operator.clusterserviceversion.yaml | 7 +- .../loki.grafana.com_lokistacks.yaml | 5 +- .../loki-operator.clusterserviceversion.yaml | 7 +- .../loki.grafana.com_lokistacks.yaml | 5 +- .../loki-operator.clusterserviceversion.yaml | 7 +- .../loki.grafana.com_lokistacks.yaml | 5 +- .../bases/loki.grafana.com_lokistacks.yaml | 5 +- .../loki-operator.clusterserviceversion.yaml | 5 +- .../loki-operator.clusterserviceversion.yaml | 5 +- .../loki-operator.clusterserviceversion.yaml | 5 +- operator/internal/validation/lokistack.go | 49 ------ .../internal/validation/lokistack_test.go | 152 +----------------- operator/main.go | 4 +- 14 files changed, 37 insertions(+), 225 deletions(-) diff --git a/operator/apis/loki/v1/lokistack_types.go b/operator/apis/loki/v1/lokistack_types.go index e0bf4139042fc..981e1b9026161 100644 --- a/operator/apis/loki/v1/lokistack_types.go +++ b/operator/apis/loki/v1/lokistack_types.go @@ -821,6 +821,7 @@ type ReplicationSpec struct { Factor int32 `json:"factor,omitempty"` // Zones defines an array of ZoneSpec that the scheduler will try to satisfy. + // IMPORTANT: Make sure that the replication factor defined is less than the number of available zones. // // +optional // +kubebuilder:validation:Optional diff --git a/operator/bundle/community-openshift/manifests/loki-operator.clusterserviceversion.yaml b/operator/bundle/community-openshift/manifests/loki-operator.clusterserviceversion.yaml index ef311319322c6..9546fbe806d55 100644 --- a/operator/bundle/community-openshift/manifests/loki-operator.clusterserviceversion.yaml +++ b/operator/bundle/community-openshift/manifests/loki-operator.clusterserviceversion.yaml @@ -150,7 +150,7 @@ metadata: categories: OpenShift Optional, Logging & Tracing certified: "false" containerImage: docker.io/grafana/loki-operator:main-ac1c1fd - createdAt: "2023-05-05T07:23:07Z" + createdAt: "2023-05-10T15:32:45Z" description: The Community Loki Operator provides Kubernetes native deployment and management of Loki and related logging components. operators.operatorframework.io/builder: operator-sdk-unknown @@ -446,8 +446,9 @@ spec: path: replication.factor x-descriptors: - urn:alm:descriptor:com.tectonic.ui:number - - description: Zones defines an array of ZoneSpec that the scheduler will try - to satisfy. + - description: 'Zones defines an array of ZoneSpec that the scheduler will try + to satisfy. IMPORTANT: Make sure that the replication factor defined is + less than the number of available zones.' displayName: Zones Spec path: replication.zones - description: MaxSkew describes the maximum degree to which Pods can be unevenly diff --git a/operator/bundle/community-openshift/manifests/loki.grafana.com_lokistacks.yaml b/operator/bundle/community-openshift/manifests/loki.grafana.com_lokistacks.yaml index 65b38988f4f8b..aca0863ec45d3 100644 --- a/operator/bundle/community-openshift/manifests/loki.grafana.com_lokistacks.yaml +++ b/operator/bundle/community-openshift/manifests/loki.grafana.com_lokistacks.yaml @@ -344,8 +344,9 @@ spec: minimum: 1 type: integer zones: - description: Zones defines an array of ZoneSpec that the scheduler - will try to satisfy. + description: 'Zones defines an array of ZoneSpec that the scheduler + will try to satisfy. IMPORTANT: Make sure that the replication + factor defined is less than the number of available zones.' items: description: ZoneSpec defines the spec to support zone-aware component deployments. diff --git a/operator/bundle/community/manifests/loki-operator.clusterserviceversion.yaml b/operator/bundle/community/manifests/loki-operator.clusterserviceversion.yaml index d824934b9cfc4..f448dc7f39f07 100644 --- a/operator/bundle/community/manifests/loki-operator.clusterserviceversion.yaml +++ b/operator/bundle/community/manifests/loki-operator.clusterserviceversion.yaml @@ -150,7 +150,7 @@ metadata: categories: OpenShift Optional, Logging & Tracing certified: "false" containerImage: docker.io/grafana/loki-operator:main-ac1c1fd - createdAt: "2023-05-05T07:23:04Z" + createdAt: "2023-05-10T15:32:41Z" description: The Community Loki Operator provides Kubernetes native deployment and management of Loki and related logging components. operators.operatorframework.io/builder: operator-sdk-unknown @@ -446,8 +446,9 @@ spec: path: replication.factor x-descriptors: - urn:alm:descriptor:com.tectonic.ui:number - - description: Zones defines an array of ZoneSpec that the scheduler will try - to satisfy. + - description: 'Zones defines an array of ZoneSpec that the scheduler will try + to satisfy. IMPORTANT: Make sure that the replication factor defined is + less than the number of available zones.' displayName: Zones Spec path: replication.zones - description: MaxSkew describes the maximum degree to which Pods can be unevenly diff --git a/operator/bundle/community/manifests/loki.grafana.com_lokistacks.yaml b/operator/bundle/community/manifests/loki.grafana.com_lokistacks.yaml index 2109df5b68b53..3b29dbee1ffab 100644 --- a/operator/bundle/community/manifests/loki.grafana.com_lokistacks.yaml +++ b/operator/bundle/community/manifests/loki.grafana.com_lokistacks.yaml @@ -344,8 +344,9 @@ spec: minimum: 1 type: integer zones: - description: Zones defines an array of ZoneSpec that the scheduler - will try to satisfy. + description: 'Zones defines an array of ZoneSpec that the scheduler + will try to satisfy. IMPORTANT: Make sure that the replication + factor defined is less than the number of available zones.' items: description: ZoneSpec defines the spec to support zone-aware component deployments. diff --git a/operator/bundle/openshift/manifests/loki-operator.clusterserviceversion.yaml b/operator/bundle/openshift/manifests/loki-operator.clusterserviceversion.yaml index 7f543bd2620d8..565764be48b95 100644 --- a/operator/bundle/openshift/manifests/loki-operator.clusterserviceversion.yaml +++ b/operator/bundle/openshift/manifests/loki-operator.clusterserviceversion.yaml @@ -150,7 +150,7 @@ metadata: categories: OpenShift Optional, Logging & Tracing certified: "false" containerImage: quay.io/openshift-logging/loki-operator:v0.1.0 - createdAt: "2023-05-05T07:23:09Z" + createdAt: "2023-05-10T15:32:48Z" description: | The Loki Operator for OCP provides a means for configuring and managing a Loki stack for cluster logging. ## Prerequisites and Requirements @@ -459,8 +459,9 @@ spec: path: replication.factor x-descriptors: - urn:alm:descriptor:com.tectonic.ui:number - - description: Zones defines an array of ZoneSpec that the scheduler will try - to satisfy. + - description: 'Zones defines an array of ZoneSpec that the scheduler will try + to satisfy. IMPORTANT: Make sure that the replication factor defined is + less than the number of available zones.' displayName: Zones Spec path: replication.zones - description: MaxSkew describes the maximum degree to which Pods can be unevenly diff --git a/operator/bundle/openshift/manifests/loki.grafana.com_lokistacks.yaml b/operator/bundle/openshift/manifests/loki.grafana.com_lokistacks.yaml index 5e304b86bf270..467fa48093e4a 100644 --- a/operator/bundle/openshift/manifests/loki.grafana.com_lokistacks.yaml +++ b/operator/bundle/openshift/manifests/loki.grafana.com_lokistacks.yaml @@ -344,8 +344,9 @@ spec: minimum: 1 type: integer zones: - description: Zones defines an array of ZoneSpec that the scheduler - will try to satisfy. + description: 'Zones defines an array of ZoneSpec that the scheduler + will try to satisfy. IMPORTANT: Make sure that the replication + factor defined is less than the number of available zones.' items: description: ZoneSpec defines the spec to support zone-aware component deployments. diff --git a/operator/config/crd/bases/loki.grafana.com_lokistacks.yaml b/operator/config/crd/bases/loki.grafana.com_lokistacks.yaml index d55aa81b29c2e..34ca8095894d6 100644 --- a/operator/config/crd/bases/loki.grafana.com_lokistacks.yaml +++ b/operator/config/crd/bases/loki.grafana.com_lokistacks.yaml @@ -327,8 +327,9 @@ spec: minimum: 1 type: integer zones: - description: Zones defines an array of ZoneSpec that the scheduler - will try to satisfy. + description: 'Zones defines an array of ZoneSpec that the scheduler + will try to satisfy. IMPORTANT: Make sure that the replication + factor defined is less than the number of available zones.' items: description: ZoneSpec defines the spec to support zone-aware component deployments. diff --git a/operator/config/manifests/community-openshift/bases/loki-operator.clusterserviceversion.yaml b/operator/config/manifests/community-openshift/bases/loki-operator.clusterserviceversion.yaml index 43e205adde91b..5f04711b76a99 100644 --- a/operator/config/manifests/community-openshift/bases/loki-operator.clusterserviceversion.yaml +++ b/operator/config/manifests/community-openshift/bases/loki-operator.clusterserviceversion.yaml @@ -359,8 +359,9 @@ spec: path: replication.factor x-descriptors: - urn:alm:descriptor:com.tectonic.ui:number - - description: Zones defines an array of ZoneSpec that the scheduler will try - to satisfy. + - description: 'Zones defines an array of ZoneSpec that the scheduler will try + to satisfy. IMPORTANT: Make sure that the replication factor defined is + less than the number of available zones.' displayName: Zones Spec path: replication.zones - description: MaxSkew describes the maximum degree to which Pods can be unevenly diff --git a/operator/config/manifests/community/bases/loki-operator.clusterserviceversion.yaml b/operator/config/manifests/community/bases/loki-operator.clusterserviceversion.yaml index a1194efee4f14..67664a789bd76 100644 --- a/operator/config/manifests/community/bases/loki-operator.clusterserviceversion.yaml +++ b/operator/config/manifests/community/bases/loki-operator.clusterserviceversion.yaml @@ -359,8 +359,9 @@ spec: path: replication.factor x-descriptors: - urn:alm:descriptor:com.tectonic.ui:number - - description: Zones defines an array of ZoneSpec that the scheduler will try - to satisfy. + - description: 'Zones defines an array of ZoneSpec that the scheduler will try + to satisfy. IMPORTANT: Make sure that the replication factor defined is + less than the number of available zones.' displayName: Zones Spec path: replication.zones - description: MaxSkew describes the maximum degree to which Pods can be unevenly diff --git a/operator/config/manifests/openshift/bases/loki-operator.clusterserviceversion.yaml b/operator/config/manifests/openshift/bases/loki-operator.clusterserviceversion.yaml index beeb299074274..9e036f9b48bbf 100644 --- a/operator/config/manifests/openshift/bases/loki-operator.clusterserviceversion.yaml +++ b/operator/config/manifests/openshift/bases/loki-operator.clusterserviceversion.yaml @@ -371,8 +371,9 @@ spec: path: replication.factor x-descriptors: - urn:alm:descriptor:com.tectonic.ui:number - - description: Zones defines an array of ZoneSpec that the scheduler will try - to satisfy. + - description: 'Zones defines an array of ZoneSpec that the scheduler will try + to satisfy. IMPORTANT: Make sure that the replication factor defined is + less than the number of available zones.' displayName: Zones Spec path: replication.zones - description: MaxSkew describes the maximum degree to which Pods can be unevenly diff --git a/operator/internal/validation/lokistack.go b/operator/internal/validation/lokistack.go index f020cb6fa0af5..a11c2783a097c 100644 --- a/operator/internal/validation/lokistack.go +++ b/operator/internal/validation/lokistack.go @@ -5,9 +5,6 @@ import ( "fmt" "time" - corev1 "k8s.io/api/core/v1" - "sigs.k8s.io/controller-runtime/pkg/client" - lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -25,7 +22,6 @@ var _ admission.CustomValidator = &LokiStackValidator{} // LokiStackValidator implements a custom validator for LokiStack resources. type LokiStackValidator struct { - Client client.Client ExtendedValidator func(context.Context, *lokiv1.LokiStack) field.ErrorList } @@ -98,7 +94,6 @@ func (v LokiStackValidator) validateReplicationSpec(ctx context.Context, stack l } var allErrs field.ErrorList - var nodes corev1.NodeList // nolint:staticcheck if stack.Replication != nil && stack.ReplicationFactor > 0 { @@ -111,50 +106,6 @@ func (v LokiStackValidator) validateReplicationSpec(ctx context.Context, stack l return allErrs } - rs := stack.Replication - selector := make([]string, 0) - for _, z := range rs.Zones { - selector = append(selector, z.TopologyKey) - } - - if err := v.Client.List(ctx, &nodes, client.HasLabels(selector)); err != nil { - allErrs = append(allErrs, field.Invalid( - field.NewPath("spec", "replication", "zones"), - rs.Zones, - lokiv1.ErrReplicationZonesNodes.Error(), - )) - } - - // Check if there are enough nodes to fit all the pods. - if len(nodes.Items) < int(rs.Factor) { - allErrs = append(allErrs, field.Invalid( - field.NewPath("spec", "replication", "factor"), - rs.Factor, - lokiv1.ErrReplicationFactorToZonesRatio.Error(), - )) - - return allErrs - } - - // Check if there are enough regions to fit all the pods for each topology keys. - for _, tk := range selector { - m := make(map[string]struct{}) - for _, node := range nodes.Items { - m[node.Labels[tk]] = struct{}{} - } - - fmt.Printf("%+v\n", m) - - if len(m) < int(rs.Factor) { - allErrs = append(allErrs, field.Invalid( - field.NewPath("spec", "replication", "factor"), - rs.Factor, - lokiv1.ErrReplicationFactorToZonesRatio.Error(), - )) - return allErrs - } - } - return nil } diff --git a/operator/internal/validation/lokistack_test.go b/operator/internal/validation/lokistack_test.go index 3bc6f1c0553e7..9720332181dc9 100644 --- a/operator/internal/validation/lokistack_test.go +++ b/operator/internal/validation/lokistack_test.go @@ -2,15 +2,11 @@ package validation_test import ( "context" - "fmt" "testing" "github.com/stretchr/testify/require" - corev1 "k8s.io/api/core/v1" - "sigs.k8s.io/controller-runtime/pkg/client" lokiv1 "github.com/grafana/loki/operator/apis/loki/v1" - "github.com/grafana/loki/operator/internal/external/k8s/k8sfakes" "github.com/grafana/loki/operator/internal/validation" apierrors "k8s.io/apimachinery/pkg/api/errors" @@ -313,95 +309,6 @@ var ltt = []struct { }, }, }, - { - desc: "invalid zones to replication factor ratio", - spec: lokiv1.LokiStack{ - Spec: lokiv1.LokiStackSpec{ - Storage: lokiv1.ObjectStorageSpec{ - Schemas: []lokiv1.ObjectStorageSchema{ - { - Version: lokiv1.ObjectStorageSchemaV12, - EffectiveDate: "2020-10-11", - }, - }, - }, - Replication: &lokiv1.ReplicationSpec{ - Zones: []lokiv1.ZoneSpec{ - { - TopologyKey: "zone", - }, - }, - Factor: 2, - }, - }, - }, - err: apierrors.NewInvalid( - schema.GroupKind{Group: "loki.grafana.com", Kind: "LokiStack"}, - "testing-stack", - field.ErrorList{ - field.Invalid( - field.NewPath("spec", "replication", "factor"), - 2, - lokiv1.ErrReplicationFactorToZonesRatio.Error(), - ), - }, - ), - }, - { - desc: "invalid zones topologyKey", - spec: lokiv1.LokiStack{ - Spec: lokiv1.LokiStackSpec{ - Storage: lokiv1.ObjectStorageSpec{ - Schemas: []lokiv1.ObjectStorageSchema{ - { - Version: lokiv1.ObjectStorageSchemaV12, - EffectiveDate: "2020-10-11", - }, - }, - }, - Replication: &lokiv1.ReplicationSpec{ - Zones: []lokiv1.ZoneSpec{ - { - TopologyKey: "zone", - }, - { - TopologyKey: "region", - }, - { - TopologyKey: "planet", - }, - }, - Factor: 1, - }, - }, - }, - err: apierrors.NewInvalid( - schema.GroupKind{Group: "loki.grafana.com", Kind: "LokiStack"}, - "testing-stack", - field.ErrorList{ - field.Invalid( - field.NewPath("spec", "replication", "zones"), - []lokiv1.ZoneSpec{ - { - TopologyKey: "zone", - }, - { - TopologyKey: "region", - }, - { - TopologyKey: "planet", - }, - }, - lokiv1.ErrReplicationZonesNodes.Error(), - ), - field.Invalid( - field.NewPath("spec", "replication", "factor"), - 1, - lokiv1.ErrReplicationFactorToZonesRatio.Error(), - ), - }, - ), - }, { desc: "using both replication and replicationFactor", spec: lokiv1.LokiStack{ @@ -458,10 +365,7 @@ func TestLokiStackValidationWebhook_ValidateCreate(t *testing.T) { } ctx := context.Background() - k := prepFakeClient() - v := &validation.LokiStackValidator{ - Client: k, - } + v := &validation.LokiStackValidator{} err := v.ValidateCreate(ctx, l) if err != nil { require.Equal(t, tc.err, err) @@ -485,10 +389,7 @@ func TestLokiStackValidationWebhook_ValidateUpdate(t *testing.T) { } ctx := context.Background() - k := prepFakeClient() - v := &validation.LokiStackValidator{ - Client: k, - } + v := &validation.LokiStackValidator{} err := v.ValidateUpdate(ctx, &lokiv1.LokiStack{}, l) if err != nil { require.Equal(t, tc.err, err) @@ -498,52 +399,3 @@ func TestLokiStackValidationWebhook_ValidateUpdate(t *testing.T) { }) } } - -func prepFakeClient() *k8sfakes.FakeClient { - k := &k8sfakes.FakeClient{} - nodes := corev1.NodeList{ - Items: []corev1.Node{ - { - ObjectMeta: metav1.ObjectMeta{ - Name: "node1", - Labels: map[string]string{ - "zone": "z1", - "region": "r1", - }, - }, - }, - { - ObjectMeta: metav1.ObjectMeta{ - Name: "node2", - Labels: map[string]string{ - "zone": "z2", - "region": "r1", - }, - }, - }, - }, - } - - k.ListStub = func(_ context.Context, object client.ObjectList, opts ...client.ListOption) error { - res := corev1.NodeList{ - Items: []corev1.Node{}, - } - - for _, opt := range opts { - optLabels := opt.(client.HasLabels) - for _, l := range optLabels { - for _, node := range nodes.Items { - if _, ok := node.Labels[l]; !ok { - return fmt.Errorf("node with label %s not found", l) - } - res.Items = append(res.Items, node) - } - } - } - - k.SetClientObjectList(object, &nodes) - return nil - } - - return k -} diff --git a/operator/main.go b/operator/main.go index 2d086dcbc29b5..765c102ec4d73 100644 --- a/operator/main.go +++ b/operator/main.go @@ -111,9 +111,7 @@ func main() { os.Exit(1) } if ctrlCfg.Gates.LokiStackWebhook { - v := &validation.LokiStackValidator{ - Client: mgr.GetClient(), - } + v := &validation.LokiStackValidator{} if err = v.SetupWebhookWithManager(mgr); err != nil { logger.Error(err, "unable to create webhook", "webhook", "lokistack") os.Exit(1) From ce576b3d28d7cd11875ca1e993f8eb5623a602f7 Mon Sep 17 00:00:00 2001 From: Mohamed-Amine Bouqsimi Date: Thu, 11 May 2023 10:09:01 +0200 Subject: [PATCH 23/23] comment --- operator/apis/loki/v1/lokistack_types.go | 2 +- .../manifests/loki-operator.clusterserviceversion.yaml | 4 ++-- .../manifests/loki.grafana.com_lokistacks.yaml | 3 ++- .../manifests/loki-operator.clusterserviceversion.yaml | 4 ++-- .../community/manifests/loki.grafana.com_lokistacks.yaml | 3 ++- .../manifests/loki-operator.clusterserviceversion.yaml | 4 ++-- .../openshift/manifests/loki.grafana.com_lokistacks.yaml | 3 ++- operator/config/crd/bases/loki.grafana.com_lokistacks.yaml | 3 ++- .../bases/loki-operator.clusterserviceversion.yaml | 2 +- .../community/bases/loki-operator.clusterserviceversion.yaml | 2 +- .../openshift/bases/loki-operator.clusterserviceversion.yaml | 2 +- 11 files changed, 18 insertions(+), 14 deletions(-) diff --git a/operator/apis/loki/v1/lokistack_types.go b/operator/apis/loki/v1/lokistack_types.go index 981e1b9026161..3b57aede34276 100644 --- a/operator/apis/loki/v1/lokistack_types.go +++ b/operator/apis/loki/v1/lokistack_types.go @@ -821,7 +821,7 @@ type ReplicationSpec struct { Factor int32 `json:"factor,omitempty"` // Zones defines an array of ZoneSpec that the scheduler will try to satisfy. - // IMPORTANT: Make sure that the replication factor defined is less than the number of available zones. + // IMPORTANT: Make sure that the replication factor defined is less than or equal to the number of available zones. // // +optional // +kubebuilder:validation:Optional diff --git a/operator/bundle/community-openshift/manifests/loki-operator.clusterserviceversion.yaml b/operator/bundle/community-openshift/manifests/loki-operator.clusterserviceversion.yaml index 9546fbe806d55..9533a66859cef 100644 --- a/operator/bundle/community-openshift/manifests/loki-operator.clusterserviceversion.yaml +++ b/operator/bundle/community-openshift/manifests/loki-operator.clusterserviceversion.yaml @@ -150,7 +150,7 @@ metadata: categories: OpenShift Optional, Logging & Tracing certified: "false" containerImage: docker.io/grafana/loki-operator:main-ac1c1fd - createdAt: "2023-05-10T15:32:45Z" + createdAt: "2023-05-11T08:04:29Z" description: The Community Loki Operator provides Kubernetes native deployment and management of Loki and related logging components. operators.operatorframework.io/builder: operator-sdk-unknown @@ -448,7 +448,7 @@ spec: - urn:alm:descriptor:com.tectonic.ui:number - description: 'Zones defines an array of ZoneSpec that the scheduler will try to satisfy. IMPORTANT: Make sure that the replication factor defined is - less than the number of available zones.' + less than or equal to the number of available zones.' displayName: Zones Spec path: replication.zones - description: MaxSkew describes the maximum degree to which Pods can be unevenly diff --git a/operator/bundle/community-openshift/manifests/loki.grafana.com_lokistacks.yaml b/operator/bundle/community-openshift/manifests/loki.grafana.com_lokistacks.yaml index aca0863ec45d3..817863d5f0645 100644 --- a/operator/bundle/community-openshift/manifests/loki.grafana.com_lokistacks.yaml +++ b/operator/bundle/community-openshift/manifests/loki.grafana.com_lokistacks.yaml @@ -346,7 +346,8 @@ spec: zones: description: 'Zones defines an array of ZoneSpec that the scheduler will try to satisfy. IMPORTANT: Make sure that the replication - factor defined is less than the number of available zones.' + factor defined is less than or equal to the number of available + zones.' items: description: ZoneSpec defines the spec to support zone-aware component deployments. diff --git a/operator/bundle/community/manifests/loki-operator.clusterserviceversion.yaml b/operator/bundle/community/manifests/loki-operator.clusterserviceversion.yaml index f448dc7f39f07..e474745ba345d 100644 --- a/operator/bundle/community/manifests/loki-operator.clusterserviceversion.yaml +++ b/operator/bundle/community/manifests/loki-operator.clusterserviceversion.yaml @@ -150,7 +150,7 @@ metadata: categories: OpenShift Optional, Logging & Tracing certified: "false" containerImage: docker.io/grafana/loki-operator:main-ac1c1fd - createdAt: "2023-05-10T15:32:41Z" + createdAt: "2023-05-11T08:04:26Z" description: The Community Loki Operator provides Kubernetes native deployment and management of Loki and related logging components. operators.operatorframework.io/builder: operator-sdk-unknown @@ -448,7 +448,7 @@ spec: - urn:alm:descriptor:com.tectonic.ui:number - description: 'Zones defines an array of ZoneSpec that the scheduler will try to satisfy. IMPORTANT: Make sure that the replication factor defined is - less than the number of available zones.' + less than or equal to the number of available zones.' displayName: Zones Spec path: replication.zones - description: MaxSkew describes the maximum degree to which Pods can be unevenly diff --git a/operator/bundle/community/manifests/loki.grafana.com_lokistacks.yaml b/operator/bundle/community/manifests/loki.grafana.com_lokistacks.yaml index 3b29dbee1ffab..a26bc4eddcf8d 100644 --- a/operator/bundle/community/manifests/loki.grafana.com_lokistacks.yaml +++ b/operator/bundle/community/manifests/loki.grafana.com_lokistacks.yaml @@ -346,7 +346,8 @@ spec: zones: description: 'Zones defines an array of ZoneSpec that the scheduler will try to satisfy. IMPORTANT: Make sure that the replication - factor defined is less than the number of available zones.' + factor defined is less than or equal to the number of available + zones.' items: description: ZoneSpec defines the spec to support zone-aware component deployments. diff --git a/operator/bundle/openshift/manifests/loki-operator.clusterserviceversion.yaml b/operator/bundle/openshift/manifests/loki-operator.clusterserviceversion.yaml index 565764be48b95..b0f0b6d5f628f 100644 --- a/operator/bundle/openshift/manifests/loki-operator.clusterserviceversion.yaml +++ b/operator/bundle/openshift/manifests/loki-operator.clusterserviceversion.yaml @@ -150,7 +150,7 @@ metadata: categories: OpenShift Optional, Logging & Tracing certified: "false" containerImage: quay.io/openshift-logging/loki-operator:v0.1.0 - createdAt: "2023-05-10T15:32:48Z" + createdAt: "2023-05-11T08:04:32Z" description: | The Loki Operator for OCP provides a means for configuring and managing a Loki stack for cluster logging. ## Prerequisites and Requirements @@ -461,7 +461,7 @@ spec: - urn:alm:descriptor:com.tectonic.ui:number - description: 'Zones defines an array of ZoneSpec that the scheduler will try to satisfy. IMPORTANT: Make sure that the replication factor defined is - less than the number of available zones.' + less than or equal to the number of available zones.' displayName: Zones Spec path: replication.zones - description: MaxSkew describes the maximum degree to which Pods can be unevenly diff --git a/operator/bundle/openshift/manifests/loki.grafana.com_lokistacks.yaml b/operator/bundle/openshift/manifests/loki.grafana.com_lokistacks.yaml index 467fa48093e4a..5edc7044871a7 100644 --- a/operator/bundle/openshift/manifests/loki.grafana.com_lokistacks.yaml +++ b/operator/bundle/openshift/manifests/loki.grafana.com_lokistacks.yaml @@ -346,7 +346,8 @@ spec: zones: description: 'Zones defines an array of ZoneSpec that the scheduler will try to satisfy. IMPORTANT: Make sure that the replication - factor defined is less than the number of available zones.' + factor defined is less than or equal to the number of available + zones.' items: description: ZoneSpec defines the spec to support zone-aware component deployments. diff --git a/operator/config/crd/bases/loki.grafana.com_lokistacks.yaml b/operator/config/crd/bases/loki.grafana.com_lokistacks.yaml index 34ca8095894d6..d5d37e38fd2a6 100644 --- a/operator/config/crd/bases/loki.grafana.com_lokistacks.yaml +++ b/operator/config/crd/bases/loki.grafana.com_lokistacks.yaml @@ -329,7 +329,8 @@ spec: zones: description: 'Zones defines an array of ZoneSpec that the scheduler will try to satisfy. IMPORTANT: Make sure that the replication - factor defined is less than the number of available zones.' + factor defined is less than or equal to the number of available + zones.' items: description: ZoneSpec defines the spec to support zone-aware component deployments. diff --git a/operator/config/manifests/community-openshift/bases/loki-operator.clusterserviceversion.yaml b/operator/config/manifests/community-openshift/bases/loki-operator.clusterserviceversion.yaml index 5f04711b76a99..4ea5273c0e438 100644 --- a/operator/config/manifests/community-openshift/bases/loki-operator.clusterserviceversion.yaml +++ b/operator/config/manifests/community-openshift/bases/loki-operator.clusterserviceversion.yaml @@ -361,7 +361,7 @@ spec: - urn:alm:descriptor:com.tectonic.ui:number - description: 'Zones defines an array of ZoneSpec that the scheduler will try to satisfy. IMPORTANT: Make sure that the replication factor defined is - less than the number of available zones.' + less than or equal to the number of available zones.' displayName: Zones Spec path: replication.zones - description: MaxSkew describes the maximum degree to which Pods can be unevenly diff --git a/operator/config/manifests/community/bases/loki-operator.clusterserviceversion.yaml b/operator/config/manifests/community/bases/loki-operator.clusterserviceversion.yaml index 67664a789bd76..ef56e2b838348 100644 --- a/operator/config/manifests/community/bases/loki-operator.clusterserviceversion.yaml +++ b/operator/config/manifests/community/bases/loki-operator.clusterserviceversion.yaml @@ -361,7 +361,7 @@ spec: - urn:alm:descriptor:com.tectonic.ui:number - description: 'Zones defines an array of ZoneSpec that the scheduler will try to satisfy. IMPORTANT: Make sure that the replication factor defined is - less than the number of available zones.' + less than or equal to the number of available zones.' displayName: Zones Spec path: replication.zones - description: MaxSkew describes the maximum degree to which Pods can be unevenly diff --git a/operator/config/manifests/openshift/bases/loki-operator.clusterserviceversion.yaml b/operator/config/manifests/openshift/bases/loki-operator.clusterserviceversion.yaml index 9e036f9b48bbf..ecd13cbdeb74b 100644 --- a/operator/config/manifests/openshift/bases/loki-operator.clusterserviceversion.yaml +++ b/operator/config/manifests/openshift/bases/loki-operator.clusterserviceversion.yaml @@ -373,7 +373,7 @@ spec: - urn:alm:descriptor:com.tectonic.ui:number - description: 'Zones defines an array of ZoneSpec that the scheduler will try to satisfy. IMPORTANT: Make sure that the replication factor defined is - less than the number of available zones.' + less than or equal to the number of available zones.' displayName: Zones Spec path: replication.zones - description: MaxSkew describes the maximum degree to which Pods can be unevenly