Like Prometheus, but for logs.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
loki/operator/internal/manifests/ingester_test.go

212 lines
5.8 KiB

package manifests
import (
"math/rand"
"testing"
"github.com/stretchr/testify/require"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
policyv1 "k8s.io/api/policy/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1 "github.com/grafana/loki/operator/api/config/v1"
lokiv1 "github.com/grafana/loki/operator/api/loki/v1"
"github.com/grafana/loki/operator/internal/manifests/internal"
"github.com/grafana/loki/operator/internal/manifests/storage"
)
func TestNewIngesterStatefulSet_HasTemplateConfigHashAnnotation(t *testing.T) {
ss := NewIngesterStatefulSet(Options{
Name: "abcd",
Namespace: "efgh",
ConfigSHA1: "deadbeef",
Stack: lokiv1.LokiStackSpec{
StorageClassName: "standard",
Template: &lokiv1.LokiTemplateSpec{
Ingester: &lokiv1.LokiComponentSpec{
Replicas: 1,
},
},
},
})
annotations := ss.Spec.Template.Annotations
require.Contains(t, annotations, AnnotationLokiConfigHash)
require.Equal(t, annotations[AnnotationLokiConfigHash], "deadbeef")
}
func TestNewIngesterStatefulSet_HasTemplateObjectStoreHashAnnotation(t *testing.T) {
ss := NewIngesterStatefulSet(Options{
Name: "abcd",
Namespace: "efgh",
ObjectStorage: storage.Options{
SecretSHA1: "deadbeef",
},
Stack: lokiv1.LokiStackSpec{
StorageClassName: "standard",
Template: &lokiv1.LokiTemplateSpec{
Ingester: &lokiv1.LokiComponentSpec{
Replicas: 1,
},
},
},
})
annotations := ss.Spec.Template.Annotations
require.Contains(t, annotations, AnnotationLokiObjectStoreHash)
require.Equal(t, annotations[AnnotationLokiObjectStoreHash], "deadbeef")
}
func TestNewIngesterStatefulSet_HasTemplateCertRotationRequiredAtAnnotation(t *testing.T) {
ss := NewIngesterStatefulSet(Options{
Name: "abcd",
Namespace: "efgh",
CertRotationRequiredAt: "deadbeef",
Stack: lokiv1.LokiStackSpec{
StorageClassName: "standard",
Template: &lokiv1.LokiTemplateSpec{
Ingester: &lokiv1.LokiComponentSpec{
Replicas: 1,
},
},
},
})
annotations := ss.Spec.Template.Annotations
require.Contains(t, annotations, AnnotationCertRotationRequiredAt)
require.Equal(t, annotations[AnnotationCertRotationRequiredAt], "deadbeef")
}
func TestNewIngesterStatefulSet_SelectorMatchesLabels(t *testing.T) {
// You must set the .spec.selector field of a StatefulSet to match the labels of
// its .spec.template.metadata.labels. Prior to Kubernetes 1.8, the
// .spec.selector field was defaulted when omitted. In 1.8 and later versions,
// failing to specify a matching Pod Selector will result in a validation error
// during StatefulSet creation.
// See https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/#pod-selector
sts := NewIngesterStatefulSet(Options{
Name: "abcd",
Namespace: "efgh",
Stack: lokiv1.LokiStackSpec{
StorageClassName: "standard",
Template: &lokiv1.LokiTemplateSpec{
Ingester: &lokiv1.LokiComponentSpec{
Replicas: 1,
},
},
},
})
l := sts.Spec.Template.GetObjectMeta().GetLabels()
for key, value := range sts.Spec.Selector.MatchLabels {
require.Contains(t, l, key)
require.Equal(t, l[key], value)
}
}
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 := 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 := 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, ComponentLabels(LabelIngesterComponent, opts.Name), pdb.Spec.Selector.MatchLabels)
})
}
}
func TestNewIngesterStatefulSet_TopologySpreadConstraints(t *testing.T) {
obj, _ := BuildIngester(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,
},
},
})
ss := obj[0].(*appsv1.StatefulSet)
require.Equal(t, []corev1.TopologySpreadConstraint{
{
MaxSkew: 2,
TopologyKey: "zone",
WhenUnsatisfiable: "DoNotSchedule",
LabelSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"app.kubernetes.io/component": "ingester",
"app.kubernetes.io/instance": "abcd",
},
},
},
{
MaxSkew: 1,
TopologyKey: "region",
WhenUnsatisfiable: "DoNotSchedule",
LabelSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"app.kubernetes.io/component": "ingester",
"app.kubernetes.io/instance": "abcd",
},
},
},
}, ss.Spec.Template.Spec.TopologySpreadConstraints)
}