Skip to content

Commit 8d5f9ea

Browse files
committed
fix(ipv6): follow the cluster families for the syslog-ng bind and the metrics bind
Three points from review. The syslog-ng source bound "::" whenever enabledIPv6 was set. That reaches IPv4 clients only through v4-mapped addresses, which net.ipv6.bindv6only turns off. On a node with that setting and a cluster without IPv6, the Service is IPv4 and the source had no IPv4 listener, so ingestion failed. The bind now follows the same cluster answer the Services use. The buffer-metrics sidecars hard-coded their listen address, so a bind set on bufferVolumeMetrics was accepted and dropped. They pass it through now. An unset bind still yields the wildcard address. A cluster with no IPv6 range is re-probed instead of cached, so a range added to a running cluster is picked up without restarting the operator. Signed-off-by: Bence Csati <bence.csati@axoflow.com>
1 parent 595513b commit 8d5f9ea

8 files changed

Lines changed: 40 additions & 15 deletions

File tree

controllers/logging/logging_controller.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ func (r *LoggingReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ct
246246
syslogNGExternal, syslogNGSpec := loggingResources.GetSyslogNGSpec()
247247
if syslogNGSpec != nil {
248248
logging.AggregatorLevelConfigCheck(syslogNGSPec.ConfigCheck)
249-
syslogNGConfig, secretList, err := r.clusterConfigurationSyslogNG(loggingResources)
249+
syslogNGConfig, secretList, err := r.clusterConfigurationSyslogNG(ctx, loggingResources)
250250
if err != nil {
251251
// TODO: move config generation into Syslog-NG reconciler
252252
reconcilers = append(reconcilers, func(ctx context.Context) (*reconcile.Result, error) {
@@ -461,7 +461,7 @@ func (r *LoggingReconciler) clusterConfigurationFluentd(resources model.LoggingR
461461
return output.String(), &slf.Secrets, nil
462462
}
463463

464-
func (r *LoggingReconciler) clusterConfigurationSyslogNG(resources model.LoggingResources) (string, *secret.MountSecrets, error) {
464+
func (r *LoggingReconciler) clusterConfigurationSyslogNG(ctx context.Context, resources model.LoggingResources) (string, *secret.MountSecrets, error) {
465465
if cfg := resources.Logging.Spec.FlowConfigOverride; cfg != "" {
466466
return cfg, nil, nil
467467
}
@@ -482,6 +482,7 @@ func (r *LoggingReconciler) clusterConfigurationSyslogNG(resources model.Logging
482482
Flows: resources.SyslogNG.Flows,
483483
SecretLoaderFactory: &slf,
484484
SourcePort: syslogng.ServicePort,
485+
ClusterHasIPv6: len(r.clusterIPFamilies(ctx, &resources.Logging, syslogngSpec.EnabledIPv6)) > 0,
485486
SyslogNGSpec: syslogngSpec,
486487
SkipInvalidResources: resources.Logging.Spec.SkipInvalidResources,
487488
Logger: r.Log,

pkg/resources/fluentbit/daemonset.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,8 @@ func (r *Reconciler) bufferMetricsSidecarContainer() *corev1.Container {
314314
if r.fluentbitSpec.BufferVolumeMetrics.Port != 0 {
315315
port = r.fluentbitSpec.BufferVolumeMetrics.Port
316316
}
317-
portParam := fmt.Sprintf("--web.listen-address=:%d", port)
317+
// An unset bind keeps the wildcard address, which listens on both families.
318+
portParam := fmt.Sprintf("--web.listen-address=%s:%d", r.fluentbitSpec.BufferVolumeMetrics.Bind, port)
318319
args := []string{portParam}
319320
if len(r.fluentbitSpec.BufferVolumeArgs) != 0 {
320321
args = append(args, r.fluentbitSpec.BufferVolumeArgs...)

pkg/resources/fluentd/statefulset.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -411,7 +411,8 @@ func (r *Reconciler) bufferMetricsSidecarContainer() *corev1.Container {
411411
if r.fluentdSpec.BufferVolumeMetrics.Port != 0 {
412412
port = r.fluentdSpec.BufferVolumeMetrics.Port
413413
}
414-
portParam := fmt.Sprintf("--web.listen-address=:%d", port)
414+
// An unset bind keeps the wildcard address, which listens on both families.
415+
portParam := fmt.Sprintf("--web.listen-address=%s:%d", r.fluentdSpec.BufferVolumeMetrics.Bind, port)
415416
args := []string{portParam}
416417
if len(r.fluentdSpec.BufferVolumeArgs) != 0 {
417418
args = append(args, r.fluentdSpec.BufferVolumeArgs...)

pkg/resources/ipfamily/detector.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -70,13 +70,15 @@ func (d *Detector) Families(ctx context.Context, namespace string) []corev1.IPFa
7070
return nil
7171
}
7272

73-
switch {
74-
case hasIPv6 && hasIPv4:
75-
d.families = []corev1.IPFamily{corev1.IPv6Protocol, corev1.IPv4Protocol}
76-
case hasIPv6:
77-
d.families = []corev1.IPFamily{corev1.IPv6Protocol}
78-
default:
79-
d.log.Info("cluster has no IPv6 service range, leaving the IP families to the cluster")
73+
if !hasIPv6 {
74+
// Re-probed every time, so a range added to a running cluster is picked up without a restart.
75+
d.log.V(1).Info("cluster has no IPv6 service range, leaving the IP families to the cluster")
76+
return nil
77+
}
78+
79+
d.families = []corev1.IPFamily{corev1.IPv6Protocol}
80+
if hasIPv4 {
81+
d.families = append(d.families, corev1.IPv4Protocol)
8082
}
8183
d.resolved = true
8284
return d.families

pkg/resources/ipfamily/detector_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,10 @@ func TestFamilies(t *testing.T) {
4848
resolved: true,
4949
},
5050
{
51-
name: "an IPv4-only cluster is left to choose for itself",
51+
name: "an IPv4-only cluster is left to choose for itself, and re-probed",
5252
results: map[corev1.IPFamily]error{corev1.IPv6Protocol: invalidFamilyErr(), corev1.IPv4Protocol: nil},
5353
expected: nil,
54-
resolved: true,
54+
resolved: false,
5555
},
5656
{
5757
name: "a webhook rejecting every service leaves the answer unknown",

pkg/resources/syslogng/statefulset.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,8 @@ func (r *Reconciler) bufferMetricsSidecarContainer() *corev1.Container {
269269
if r.syslogNGSpec.BufferVolumeMetrics.Port != 0 {
270270
port = r.syslogNGSpec.BufferVolumeMetrics.Port
271271
}
272-
portParam := fmt.Sprintf("--web.listen-address=:%d", port)
272+
// An unset bind keeps the wildcard address, which listens on both families.
273+
portParam := fmt.Sprintf("--web.listen-address=%s:%d", r.syslogNGSpec.BufferVolumeMetrics.Bind, port)
273274
args := []string{portParam, "--collector.disable-defaults", "--collector.filesystem", "--collector.textfile", "--collector.textfile.directory=/prometheus/node_exporter/textfile_collector/"}
274275

275276
nodeExporterCmd := fmt.Sprintf("nodeexporter -> ./bin/node_exporter %v", strings.Join(args, " "))

pkg/sdk/logging/model/syslogng/config/config.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ type Input struct {
5555
Flows []v1beta1.SyslogNGFlow
5656
SecretLoaderFactory SecretLoaderFactory
5757
SourcePort int
58+
ClusterHasIPv6 bool
5859
SkipInvalidResources bool
5960
Logger logr.Logger
6061
}
@@ -185,7 +186,9 @@ func configRenderer(in Input) (render.Renderer, error) {
185186
// syslog-ng defaults to ip(0.0.0.0) ip-protocol(4), so an IPv6-primary Service would route to a
186187
// port nothing is listening on. "::" still accepts IPv4-mapped clients where bindv6only is off.
187188
sourceIP, sourceIPProtocol := "", 0
188-
if in.SyslogNGSpec.EnabledIPv6 {
189+
// Binding IPv6 only reaches IPv4 clients through v4-mapped addresses, which net.ipv6.bindv6only
190+
// turns off. A cluster without IPv6 gives the source an IPv4 Service, so leave it on IPv4 there.
191+
if in.SyslogNGSpec.EnabledIPv6 && in.ClusterHasIPv6 {
189192
sourceIP, sourceIPProtocol = "::", 6
190193
}
191194

pkg/sdk/logging/model/syslogng/config/config_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,10 +1202,26 @@ func TestRenderConfigIntoBindsTheSourceForIPv6(t *testing.T) {
12021202
Name: "test",
12031203
Namespace: "config-test",
12041204
SyslogNGSpec: &v1beta1.SyslogNGSpec{EnabledIPv6: test.enabledIPv6},
1205+
ClusterHasIPv6: true,
12051206
SecretLoaderFactory: &TestSecretLoaderFactory{},
12061207
}, &buf)
12071208
require.NoError(t, err)
12081209
require.Contains(t, buf.String(), test.wantSource)
12091210
})
12101211
}
12111212
}
1213+
1214+
// Binding IPv6 only reaches IPv4 clients through v4-mapped addresses, which bindv6only disables.
1215+
func TestRenderConfigIntoKeepsIPv4WhenTheClusterHasNoIPv6(t *testing.T) {
1216+
var buf strings.Builder
1217+
err := RenderConfigInto(Input{
1218+
SourcePort: 601,
1219+
Name: "test",
1220+
Namespace: "config-test",
1221+
SyslogNGSpec: &v1beta1.SyslogNGSpec{EnabledIPv6: true},
1222+
ClusterHasIPv6: false,
1223+
SecretLoaderFactory: &TestSecretLoaderFactory{},
1224+
}, &buf)
1225+
require.NoError(t, err)
1226+
require.Contains(t, buf.String(), `network(flags("no-parse") port(601) transport("tcp"));`)
1227+
}

0 commit comments

Comments
 (0)