Repository: metallb/metallb
Pull request #2121 (2023-10-15 21:00:54)

Allow custom bind address for memberlist
The bind address for memberlist is currently always set to the pod's IP address:
` - name: METALLB_ML_BIND_ADDR
          valueFrom:
            fieldRef:
              fieldPath: status.podIP`
This PR allows this to be customised. 

In my scenario I wanted it to listen to a different address as the speaker pods were connecting to each other via a VIP which didn't work unless I changed the bind address.

The current behaviour is kept as the default behaviour, but it can be overridden using the new `speaker.memberlist.mlBindAddrOverride` configuration in values.yaml.


Patch:
diff --git a/.github/workflows/cancel.yaml b/.github/workflows/cancel.yaml
deleted file mode 100644
index 5da6a52e..00000000
--- a/.github/workflows/cancel.yaml
+++ /dev/null
@@ -1,13 +0,0 @@
-name: Cancel
-on:
-  workflow_run:
-    workflows: ["CI"]
-    types:
-      - requested
-jobs:
-  cancel:
-    runs-on: ubuntu-22.04
-    steps:
-    - uses: styfle/cancel-workflow-action@0.9.1
-      with:
-        workflow_id: ${{ github.event.workflow.id }}
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 1c466eaf..264d8754 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -19,6 +19,10 @@ on:
       - "v**"
   workflow_dispatch:
 
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
+
 jobs:
   static-security-analysis:
     runs-on: ubuntu-22.04
@@ -48,11 +52,6 @@ jobs:
   unit-tests:
     runs-on: ubuntu-22.04
     steps:
-      - name: Cancel Previous Runs
-        uses: styfle/cancel-workflow-action@0.9.1
-        with:
-          access_token: ${{ github.token }}
-
       - name: Checkout
         uses: actions/checkout@v4
 
diff --git a/.github/workflows/composite/setup/action.yaml b/.github/workflows/composite/setup/action.yaml
index 3e391aaa..fcee5541 100644
--- a/.github/workflows/composite/setup/action.yaml
+++ b/.github/workflows/composite/setup/action.yaml
@@ -4,11 +4,6 @@ description: "Install deps required for metallb CI"
 runs:
   using: "composite"
   steps:
-    - name: Cancel Previous Runs
-      uses: styfle/cancel-workflow-action@0.11.0
-      with:
-        access_token: ${{ github.token }}
-
     - uses: actions/setup-go@v3
       with:
         go-version-file: "go.mod"
diff --git a/.github/workflows/publish.yaml b/.github/workflows/publish.yaml
index 3878a731..2522405a 100644
--- a/.github/workflows/publish.yaml
+++ b/.github/workflows/publish.yaml
@@ -7,15 +7,14 @@ on:
     tags:
       - v*
 
+concurrency:
+  group: ${{ github.workflow }}-${{ github.ref }}
+  cancel-in-progress: true
+
 jobs:
   unit-tests:
     runs-on: ubuntu-22.04
     steps:
-      - name: Cancel Previous Runs
-        uses: styfle/cancel-workflow-action@0.9.1
-        with:
-          access_token: ${{ github.token }}
-
       - name: Checkout
         uses: actions/checkout@v4
 
diff --git a/charts/metallb/README.md b/charts/metallb/README.md
index 11bbe7d3..396af74c 100644
--- a/charts/metallb/README.md
+++ b/charts/metallb/README.md
@@ -130,6 +130,7 @@ Kubernetes: `>= 1.19.0-0`
 | speaker.livenessProbe.timeoutSeconds | int | `1` |  |
 | speaker.logLevel | string | `"info"` | Speaker log level. Must be one of: `all`, `debug`, `info`, `warn`, `error` or `none` |
 | speaker.memberlist.enabled | bool | `true` |  |
+| speaker.memberlist.mlBindAddrOverride | string | `""` |  |
 | speaker.memberlist.mlBindPort | int | `7946` |  |
 | speaker.memberlist.mlSecretKeyPath | string | `"/etc/ml_secret_key"` |  |
 | speaker.nodeSelector | object | `{}` |  |
@@ -144,6 +145,7 @@ Kubernetes: `>= 1.19.0-0`
 | speaker.reloader.resources | object | `{}` |  |
 | speaker.resources | object | `{}` |  |
 | speaker.runtimeClassName | string | `""` |  |
+| speaker.securityContext | object | `{}` |  |
 | speaker.serviceAccount.annotations | object | `{}` |  |
 | speaker.serviceAccount.create | bool | `true` |  |
 | speaker.serviceAccount.name | string | `""` |  |
diff --git a/charts/metallb/templates/speaker.yaml b/charts/metallb/templates/speaker.yaml
index 1a4c7b2a..35f93814 100644
--- a/charts/metallb/templates/speaker.yaml
+++ b/charts/metallb/templates/speaker.yaml
@@ -154,6 +154,10 @@ spec:
       serviceAccountName: {{ template "metallb.speaker.serviceAccountName" . }}
       terminationGracePeriodSeconds: 0
       hostNetwork: true
+      {{- if .Values.speaker.securityContext }}
+      securityContext:
+        {{- toYaml .Values.speaker.securityContext | nindent 8 }}
+      {{- end }}
       volumes:
       {{- if .Values.speaker.memberlist.enabled }}
         - name: memberlist
@@ -241,10 +245,15 @@ spec:
             fieldRef:
               fieldPath: status.hostIP
         {{- if .Values.speaker.memberlist.enabled }}
+        {{- if .Values.speaker.memberlist.mlBindAddrOverride }}
+        - name: METALLB_ML_BIND_ADDR
+          value: "{{ .Values.speaker.memberlist.mlBindAddrOverride }}"
+        {{ else }}
         - name: METALLB_ML_BIND_ADDR
           valueFrom:
             fieldRef:
               fieldPath: status.podIP
+        {{ end }}
         - name: METALLB_ML_LABELS
           value: "app.kubernetes.io/name={{ include "metallb.name" . }},app.kubernetes.io/component=speaker"
         - name: METALLB_ML_BIND_PORT
diff --git a/charts/metallb/values.schema.json b/charts/metallb/values.schema.json
index 5a92e56a..00fdc24e 100644
--- a/charts/metallb/values.schema.json
+++ b/charts/metallb/values.schema.json
@@ -317,6 +317,9 @@
                 "mlBindPort": {
                   "type": "integer"
                 },
+                "mlBindAddrOverride": {
+                  "type": "string"
+                },
                 "mlSecretKeyPath": {
                   "type": "string"
                 }
@@ -342,6 +345,9 @@
             "runtimeClassName": {
               "type": "string"
             },
+            "securityContext": {
+              "type": "object"
+            },
             "secretName": {
               "type": "string"
             },
diff --git a/charts/metallb/values.yaml b/charts/metallb/values.yaml
index be8cf112..6481ff68 100644
--- a/charts/metallb/values.yaml
+++ b/charts/metallb/values.yaml
@@ -260,6 +260,7 @@ speaker:
   memberlist:
     enabled: true
     mlBindPort: 7946
+    mlBindAddrOverride: ""
     mlSecretKeyPath: "/etc/ml_secret_key"
   excludeInterfaces:
     enabled: true
@@ -282,6 +283,7 @@ speaker:
     # true, a name is generated using the fullname template
     name: ""
     annotations: {}
+  securityContext: {}
   ## Defines a secret name for the controller to generate a memberlist encryption secret
   ## By default secretName: {{ "metallb.fullname" }}-memberlist
   ##
diff --git a/internal/ipfamily/ipfamily.go b/internal/ipfamily/ipfamily.go
index e9124888..15489c3f 100644
--- a/internal/ipfamily/ipfamily.go
+++ b/internal/ipfamily/ipfamily.go
@@ -28,6 +28,9 @@ func ForAddresses(ips []string) (Family, error) {
 	switch len(ips) {
 	case 1:
 		ip := net.ParseIP(ips[0])
+		if ip == nil {
+			return Unknown, fmt.Errorf("IPFamilyForAddresses: Invalid address %q", ips)
+		}
 		if ip.To4() != nil {
 			return IPv4, nil
 		}


Test patch:
diff --git a/internal/ipfamily/ipfamily_test.go b/internal/ipfamily/ipfamily_test.go
index b26b0902..8ee563a2 100644
--- a/internal/ipfamily/ipfamily_test.go
+++ b/internal/ipfamily/ipfamily_test.go
@@ -24,6 +24,12 @@ func TestIPFamilyForAddresses(t *testing.T) {
 			ips:    []string{"100::1"},
 			family: IPv6,
 		},
+		{
+			desc:    "one invalid address",
+			ips:     []string{"!.1.1.1"},
+			family:  Unknown,
+			wantErr: true,
+		},
 		{
 			desc:   "ipv4 and ipv6 addresse",
 			ips:    []string{"1.2.3.4", "100::1"},
@@ -41,6 +47,12 @@ func TestIPFamilyForAddresses(t *testing.T) {
 			family:  Unknown,
 			wantErr: true,
 		},
+		{
+			desc:    "dual stack with one invalid address",
+			ips:     []string{"!.1.1.1", "100::1"},
+			family:  Unknown,
+			wantErr: true,
+		},
 		{
 			desc:    "more than 2 addresses",
 			ips:     []string{"1.1.1.1", "100::1", "2.2.2.2"},