Skip to content

Commit 88c241e

Browse files
authored
Merge pull request #2084 from marvin-roesch/master
Make /tmp directory for configchecks sticky so StartWithTimeout strategy
2 parents e864e54 + d3f1194 commit 88c241e

File tree

3 files changed

+241
-5
lines changed

3 files changed

+241
-5
lines changed

e2e/common/cond/conditions.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,21 @@ func AnyPodShouldBeRunning(t *testing.T, cl client.Reader, opts ...client.ListOp
6060
}
6161
}
6262

63+
func AnyPodShouldBeFinished(t *testing.T, cl client.Reader, opts ...client.ListOption) func() bool {
64+
return func() bool {
65+
var podList corev1.PodList
66+
if err := cl.List(context.Background(), &podList, opts...); err != nil {
67+
t.Logf("an error occurred while listing pods: %v", err)
68+
}
69+
for _, pod := range podList.Items {
70+
if pod.Status.Phase == corev1.PodSucceeded || pod.Status.Phase == corev1.PodFailed {
71+
return true
72+
}
73+
}
74+
return false
75+
}
76+
}
77+
6378
func ResourceShouldBeAbsent(t *testing.T, cl client.Reader, obj client.Object) func() bool {
6479
return func() bool {
6580
err := cl.Get(context.Background(), client.ObjectKeyFromObject(obj), obj)

e2e/fluentd-aggregator/fluentd_aggregator_test.go

Lines changed: 208 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -459,23 +459,27 @@ func TestFluentdAggregator_ConfigChecks(t *testing.T) {
459459
common.RequireNoError(t, rbacv1.AddToScheme(o.Scheme))
460460
})
461461
}
462-
func TestFluentdAggregator_ConfigChecks_WhenReadOnlyRootFilesystemIsConfigured(t *testing.T) {
462+
func TestFluentdAggregator_ConfigChecks_DryRunWhenReadOnlyRootFilesystemIsConfigured(t *testing.T) {
463463
common.Initialize(t)
464464
ns := "testing-3"
465465
releaseNameOverride := "e2e"
466466
outputName := "test-output"
467467
flowName := "test-flow"
468-
common.WithCluster("fluentd-configcheck-readonly-root-filesystem", t, func(t *testing.T, c common.Cluster) {
468+
common.WithCluster("fluentd-configcheck-dry-run-readonly-rootfs", t, func(t *testing.T, c common.Cluster) {
469469
setup.LoggingOperator(t, c, setup.LoggingOperatorOptionFunc(func(options *setup.LoggingOperatorOptions) {
470470
options.Namespace = ns
471471
options.NameOverride = releaseNameOverride
472472
}))
473473

474474
ctx := context.Background()
475475

476+
configCheckLabels := map[string]string{
477+
"my-unique-label": "configcheck",
478+
}
479+
476480
logging := v1beta1.Logging{
477481
ObjectMeta: metav1.ObjectMeta{
478-
Name: "fluentd-aggregator-configchecks-ro-rootfs-test",
482+
Name: "fluentd-aggregator-configchecks-dry-run-ro-rootfs-test",
479483
Namespace: ns,
480484
},
481485
Spec: v1beta1.LoggingSpec{
@@ -536,6 +540,10 @@ func TestFluentdAggregator_ConfigChecks_WhenReadOnlyRootFilesystemIsConfigured(t
536540
ReadOnlyRootFilesystem: utils.BoolPointer(true),
537541
},
538542
},
543+
ConfigCheck: &v1beta1.ConfigCheck{
544+
Strategy: v1beta1.ConfigCheckStrategyDryRun,
545+
Labels: configCheckLabels,
546+
},
539547
},
540548
},
541549
}
@@ -603,13 +611,209 @@ func TestFluentdAggregator_ConfigChecks_WhenReadOnlyRootFilesystemIsConfigured(t
603611
t.Log("waiting for the producer")
604612
return false
605613
}
614+
if configCheckFinished := cond.AnyPodShouldBeFinished(t, c.GetClient(), client.MatchingLabels(configCheckLabels)); !configCheckFinished() {
615+
t.Log("waiting for the config check")
616+
return false
617+
}
606618
if aggregatorRunning := cond.AnyPodShouldBeRunning(t, c.GetClient(), client.MatchingLabels(aggregatorLabels)); !aggregatorRunning() {
607619
t.Log("waiting for the aggregator")
608620
return false
609621
}
610622

611-
return logging.Status.ProblemsCount == 0
623+
return true
624+
}, 5*time.Minute, 3*time.Second)
625+
626+
common.RequireNoError(t, c.GetClient().Get(ctx, utils.ObjectKeyFromObjectMeta(&logging), &logging))
627+
628+
require.Equal(t, 0, logging.Status.ProblemsCount)
629+
}, func(t *testing.T, c common.Cluster) error {
630+
path := filepath.Join(TestTempDir, fmt.Sprintf("cluster-%s.log", t.Name()))
631+
t.Logf("Printing cluster logs to %s", path)
632+
return c.PrintLogs(common.PrintLogConfig{
633+
Namespaces: []string{ns, "default"},
634+
FilePath: path,
635+
Limit: 100 * 1000,
636+
})
637+
}, func(o *cluster.Options) {
638+
if o.Scheme == nil {
639+
o.Scheme = runtime.NewScheme()
640+
}
641+
common.RequireNoError(t, v1beta1.AddToScheme(o.Scheme))
642+
common.RequireNoError(t, apiextensionsv1.AddToScheme(o.Scheme))
643+
common.RequireNoError(t, appsv1.AddToScheme(o.Scheme))
644+
common.RequireNoError(t, batchv1.AddToScheme(o.Scheme))
645+
common.RequireNoError(t, corev1.AddToScheme(o.Scheme))
646+
common.RequireNoError(t, rbacv1.AddToScheme(o.Scheme))
647+
})
648+
}
649+
func TestFluentdAggregator_ConfigChecks_StartWithTimeoutWhenReadOnlyRootFilesystemIsConfigured(t *testing.T) {
650+
common.Initialize(t)
651+
ns := "testing-3"
652+
releaseNameOverride := "e2e"
653+
outputName := "test-output"
654+
flowName := "test-flow"
655+
common.WithCluster("fluentd-configcheck-start-timeout-readonly-rootfs", t, func(t *testing.T, c common.Cluster) {
656+
setup.LoggingOperator(t, c, setup.LoggingOperatorOptionFunc(func(options *setup.LoggingOperatorOptions) {
657+
options.Namespace = ns
658+
options.NameOverride = releaseNameOverride
659+
}))
660+
661+
ctx := context.Background()
662+
663+
configCheckLabels := map[string]string{
664+
"my-unique-label": "configcheck",
665+
}
666+
667+
logging := v1beta1.Logging{
668+
ObjectMeta: metav1.ObjectMeta{
669+
Name: "fluentd-aggregator-configchecks-start-timeout-ro-rootfs-test",
670+
Namespace: ns,
671+
},
672+
Spec: v1beta1.LoggingSpec{
673+
EnableRecreateWorkloadOnImmutableFieldChange: true,
674+
ControlNamespace: ns,
675+
FluentbitSpec: &v1beta1.FluentbitSpec{
676+
Network: &v1beta1.FluentbitNetwork{
677+
Keepalive: utils.BoolPointer(false),
678+
},
679+
ConfigHotReload: &v1beta1.HotReload{
680+
Image: v1beta1.ImageSpec{
681+
Repository: common.ConfigReloaderRepo,
682+
Tag: common.ConfigReloaderTag,
683+
},
684+
},
685+
BufferVolumeImage: v1beta1.ImageSpec{
686+
Repository: common.NodeExporterRepo,
687+
Tag: common.NodeExporterTag,
688+
},
689+
},
690+
FluentdSpec: &v1beta1.FluentdSpec{
691+
Image: v1beta1.ImageSpec{
692+
Repository: common.FluentdImageRepo,
693+
Tag: common.FluentdImageTag,
694+
},
695+
ConfigReloaderImage: v1beta1.ImageSpec{
696+
Repository: common.ConfigReloaderRepo,
697+
Tag: common.ConfigReloaderTag,
698+
},
699+
BufferVolumeImage: v1beta1.ImageSpec{
700+
Repository: common.NodeExporterRepo,
701+
Tag: common.NodeExporterTag,
702+
},
703+
Resources: corev1.ResourceRequirements{
704+
Limits: corev1.ResourceList{
705+
corev1.ResourceCPU: resource.MustParse("500m"),
706+
corev1.ResourceMemory: resource.MustParse("200M"),
707+
},
708+
Requests: corev1.ResourceList{
709+
corev1.ResourceCPU: resource.MustParse("250m"),
710+
corev1.ResourceMemory: resource.MustParse("50M"),
711+
},
712+
},
713+
BufferVolumeMetrics: &v1beta1.Metrics{},
714+
Scaling: &v1beta1.FluentdScaling{
715+
Replicas: 1,
716+
Drain: v1beta1.FluentdDrainConfig{
717+
Enabled: true,
718+
Image: v1beta1.ImageSpec{
719+
Repository: common.FluentdDrainWatchRepo,
720+
Tag: common.FluentdDrainWatchTag,
721+
},
722+
},
723+
},
724+
Workers: 1,
725+
Security: &v1beta1.Security{
726+
SecurityContext: &corev1.SecurityContext{
727+
ReadOnlyRootFilesystem: utils.BoolPointer(true),
728+
},
729+
},
730+
ConfigCheck: &v1beta1.ConfigCheck{
731+
Strategy: v1beta1.ConfigCheckStrategyTimeout,
732+
TimeoutSeconds: 5,
733+
Labels: configCheckLabels,
734+
},
735+
},
736+
},
737+
}
738+
common.RequireNoError(t, c.GetClient().Create(ctx, &logging))
739+
output := v1beta1.Output{
740+
ObjectMeta: metav1.ObjectMeta{
741+
Name: outputName,
742+
Namespace: ns,
743+
},
744+
Spec: v1beta1.OutputSpec{
745+
FileOutput: &output.FileOutputConfig{
746+
Path: "/tmp/logs/${tag}/%Y/%m/%d.%H.%M",
747+
Append: true,
748+
Buffer: &output.Buffer{
749+
Type: "file",
750+
Timekey: "1m",
751+
TimekeyWait: "10s",
752+
},
753+
},
754+
},
755+
}
756+
757+
producerLabels := map[string]string{
758+
"my-unique-label": "log-producer",
759+
}
760+
761+
common.RequireNoError(t, c.GetClient().Create(ctx, &output))
762+
flow := v1beta1.Flow{
763+
ObjectMeta: metav1.ObjectMeta{
764+
Name: flowName,
765+
Namespace: ns,
766+
},
767+
Spec: v1beta1.FlowSpec{
768+
Match: []v1beta1.Match{
769+
{
770+
Select: &v1beta1.Select{
771+
Labels: producerLabels,
772+
},
773+
},
774+
},
775+
LocalOutputRefs: []string{output.Name},
776+
},
777+
}
778+
common.RequireNoError(t, c.GetClient().Create(ctx, &flow))
779+
780+
aggregatorLabels := map[string]string{
781+
"app.kubernetes.io/name": "fluentd",
782+
"app.kubernetes.io/component": "fluentd",
783+
}
784+
operatorLabels := map[string]string{
785+
"app.kubernetes.io/name": releaseNameOverride,
786+
}
787+
788+
go setup.LogProducer(t, c.GetClient(), setup.LogProducerOptionFunc(func(options *setup.LogProducerOptions) {
789+
options.Namespace = ns
790+
options.Labels = producerLabels
791+
}))
792+
793+
require.Eventually(t, func() bool {
794+
if operatorRunning := cond.AnyPodShouldBeRunning(t, c.GetClient(), client.MatchingLabels(operatorLabels))(); !operatorRunning {
795+
t.Log("waiting for the operator")
796+
return false
797+
}
798+
if producerRunning := cond.AnyPodShouldBeRunning(t, c.GetClient(), client.MatchingLabels(producerLabels))(); !producerRunning {
799+
t.Log("waiting for the producer")
800+
return false
801+
}
802+
if configCheckFinished := cond.AnyPodShouldBeFinished(t, c.GetClient(), client.MatchingLabels(configCheckLabels)); !configCheckFinished() {
803+
t.Log("waiting for the config check")
804+
return false
805+
}
806+
if aggregatorRunning := cond.AnyPodShouldBeRunning(t, c.GetClient(), client.MatchingLabels(aggregatorLabels)); !aggregatorRunning() {
807+
t.Log("waiting for the aggregator")
808+
return false
809+
}
810+
811+
return true
612812
}, 5*time.Minute, 3*time.Second)
813+
814+
common.RequireNoError(t, c.GetClient().Get(ctx, utils.ObjectKeyFromObjectMeta(&logging), &logging))
815+
816+
require.Equal(t, 0, logging.Status.ProblemsCount)
613817
}, func(t *testing.T, c common.Cluster) error {
614818
path := filepath.Join(TestTempDir, fmt.Sprintf("cluster-%s.log", t.Name()))
615819
t.Logf("Printing cluster logs to %s", path)

pkg/resources/fluentd/appconfigmap.go

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,9 +414,11 @@ func (r *Reconciler) containerCheckPod(fluentdSpec v1beta1.FluentdSpec) []corev1
414414
MountPath: OutputSecretPath,
415415
},
416416
// When deploying logging operator in secured k8s clusters (securityContext.readOnlyRootFilesystem)
417-
// A emptyDir volume is needed to be able to check the configuration for using File out type.
417+
// A emptyDir volume is needed to be able to check the configuration for using File out type
418+
// or when using the StartWithTimeout strategy.
418419
{
419420
Name: "tmp",
421+
SubPath: "fluentd",
420422
MountPath: "/tmp",
421423
},
422424
},
@@ -460,6 +462,21 @@ func (r *Reconciler) initContainerCheckPod(fluentdSpec v1beta1.FluentdSpec) []co
460462
initContainer = []corev1.Container{}
461463
}
462464

465+
// Create a dedicated tmp dir with the sticky bit set so fluentd accepts it when running in StartWithTimeout mode
466+
initContainer = append(initContainer, corev1.Container{
467+
Command: []string{"sh", "-c", "mkdir -p /mnt/tmp/fluentd/; chmod +t /mnt/tmp/fluentd"},
468+
Image: r.fluentdSpec.Image.RepositoryWithTag(),
469+
ImagePullPolicy: corev1.PullPolicy(r.fluentdSpec.Image.PullPolicy),
470+
Name: "tmp-dir-hack",
471+
Resources: r.fluentdSpec.ConfigCheckResources,
472+
SecurityContext: r.fluentdSpec.Security.SecurityContext,
473+
VolumeMounts: []corev1.VolumeMount{
474+
{
475+
Name: "tmp",
476+
MountPath: "/mnt/tmp"},
477+
},
478+
})
479+
463480
return initContainer
464481
}
465482

0 commit comments

Comments
 (0)