Skip to content

Commit 3dc3a25

Browse files
committed
Replace the custom pod IP patterns with a more explicit selector for IP families.
1 parent a29d083 commit 3dc3a25

File tree

10 files changed

+91
-52
lines changed

10 files changed

+91
-52
lines changed

.github/workflows/pull_request.yml

+1
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ jobs:
5454
- name: Run Python lint
5555
run: |
5656
pycodestyle --max-line-length=120 ./**/*.py
57+
black --check --diff ./
5758
build:
5859
name: Build
5960
runs-on: ubuntu-latest

api/v1beta1/foundationdbcluster_types.go

+3-4
Original file line numberDiff line numberDiff line change
@@ -2421,12 +2421,11 @@ type RoutingConfig struct {
24212421
// This supports the values `pod` and `service`.
24222422
PublicIPSource *PublicIPSource `json:"publicIPSource,omitempty"`
24232423

2424-
// PodIPIndex tells the pod to use a specific entry from the podIPs list
2425-
// instead of the default podIP. The entry be the first one that matches the
2426-
// pattern that is provided in this field.
2424+
// PodIPFamily tells the pod which family of IP addresses to use.
2425+
// You can use 4 to represent IPv4, and 6 to represent IPv6.
24272426
// This feature is only supported in FDB 7.0 or later, and requires
24282427
// dual-stack support in your Kubernetes environment.
2429-
PodIPPattern *string `json:"podIPPattern,omitempty"`
2428+
PodIPFamily *int `json:"podIPFamily,omitempty"`
24302429
}
24312430

24322431
// RequiredAddressSet provides settings for which addresses we need to listen

api/v1beta1/zz_generated.deepcopy.go

+3-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

config/crd/bases/apps.foundationdb.org_foundationdbclusters.yaml

+2-2
Original file line numberDiff line numberDiff line change
@@ -7570,8 +7570,8 @@ spec:
75707570
properties:
75717571
headlessService:
75727572
type: boolean
7573-
podIPPattern:
7574-
type: string
7573+
podIPFamily:
7574+
type: integer
75757575
publicIPSource:
75767576
type: string
75777577
type: object

controllers/cluster_controller.go

+25-10
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"errors"
2929
"fmt"
3030
"math"
31+
"net"
3132
"regexp"
3233
"sort"
3334
"strconv"
@@ -891,7 +892,7 @@ func (instance FdbInstance) GetPublicIPs() []string {
891892
}
892893

893894
func getPublicIpsForPod(pod *corev1.Pod) []string {
894-
var podIPPattern *regexp.Regexp
895+
var podIPFamily *int
895896

896897
if pod == nil {
897898
return []string{}
@@ -900,27 +901,41 @@ func getPublicIpsForPod(pod *corev1.Pod) []string {
900901
for _, container := range pod.Spec.Containers {
901902
if container.Name == "foundationdb-kubernetes-sidecar" {
902903
for indexOfArgument, argument := range container.Args {
903-
if argument == "--public-ip-pattern" && indexOfArgument < len(container.Args)-1 {
904-
patternString := container.Args[indexOfArgument+1]
905-
pattern, err := regexp.Compile(patternString)
904+
if argument == "--public-ip-family" && indexOfArgument < len(container.Args)-1 {
905+
familyString := container.Args[indexOfArgument+1]
906+
family, err := strconv.Atoi(familyString)
906907
if err != nil {
907-
log.Error(err, "Error parsing public IP pattern", "pattern", pattern)
908+
log.Error(err, "Error parsing public IP family", "family", familyString)
908909
return nil
909910
}
910-
podIPPattern = pattern
911+
podIPFamily = &family
911912
break
912913
}
913914
}
914915
}
915916
}
916917

917-
if podIPPattern != nil {
918+
if podIPFamily != nil {
918919
podIPs := pod.Status.PodIPs
919920
matchingIPs := make([]string, 0, len(podIPs))
920921

921-
for _, ip := range podIPs {
922-
if podIPPattern.Match([]byte(ip.IP)) {
923-
matchingIPs = append(matchingIPs, ip.IP)
922+
for _, podIP := range podIPs {
923+
ip := net.ParseIP(podIP.IP)
924+
if ip == nil {
925+
log.Error(nil, "Failed to parse IP from pod", "ip", podIP)
926+
continue
927+
}
928+
matches := false
929+
switch *podIPFamily {
930+
case 4:
931+
matches = ip.To4() != nil
932+
case 6:
933+
matches = ip.To4() == nil
934+
default:
935+
log.Error(nil, "Could not match IP address against IP family", "family", *podIPFamily)
936+
}
937+
if matches {
938+
matchingIPs = append(matchingIPs, podIP.IP)
924939
}
925940
}
926941
return matchingIPs

controllers/cluster_controller_test.go

+24-3
Original file line numberDiff line numberDiff line change
@@ -3903,10 +3903,10 @@ var _ = Describe(string(fdbtypes.ProcessClassClusterController), func() {
39033903
})
39043904
})
39053905

3906-
Context("with a pod IP pattern configured", func() {
3906+
Context("with a v6 pod IP family configured", func() {
39073907
BeforeEach(func() {
3908-
pattern := ":"
3909-
cluster.Spec.Routing.PodIPPattern = &pattern
3908+
family := 6
3909+
cluster.Spec.Routing.PodIPFamily = &family
39103910
pod, err := GetPod(cluster, "storage", 1)
39113911
Expect(err).NotTo(HaveOccurred())
39123912
pod.Status.PodIP = "1.1.1.1"
@@ -3937,6 +3937,27 @@ var _ = Describe(string(fdbtypes.ProcessClassClusterController), func() {
39373937
})
39383938
})
39393939

3940+
Context("with a v4 pod IP family configured", func() {
3941+
BeforeEach(func() {
3942+
family := 4
3943+
cluster.Spec.Routing.PodIPFamily = &family
3944+
pod, err := GetPod(cluster, "storage", 1)
3945+
Expect(err).NotTo(HaveOccurred())
3946+
pod.Status.PodIP = "1.1.1.1"
3947+
pod.Status.PodIPs = []corev1.PodIP{
3948+
{IP: "1.1.1.2"},
3949+
{IP: "2001:db8::ff00:42:8329"},
3950+
}
3951+
instance.Pod = pod
3952+
instance.Metadata = &pod.ObjectMeta
3953+
})
3954+
3955+
It("should select the address based on the spec", func() {
3956+
result := instance.GetPublicIPs()
3957+
Expect(result).To(Equal([]string{"1.1.1.2"}))
3958+
})
3959+
})
3960+
39403961
Context("with no pod", func() {
39413962
BeforeEach(func() {
39423963
pod, err := GetPod(cluster, "storage", 1)

controllers/pod_models.go

+4-4
Original file line numberDiff line numberDiff line change
@@ -461,13 +461,13 @@ func configureSidecarContainer(container *corev1.Container, initMode bool, insta
461461
if usePublicIPFromService {
462462
publicIPKey = fmt.Sprintf("metadata.annotations['%s']", fdbtypes.PublicIPAnnotation)
463463
} else {
464-
pattern := cluster.Spec.Routing.PodIPPattern
465-
if pattern == nil {
464+
family := cluster.Spec.Routing.PodIPFamily
465+
if family == nil {
466466
publicIPKey = "status.podIP"
467467
} else {
468468
publicIPKey = "status.podIPs"
469-
sidecarArgs = append(sidecarArgs, "--public-ip-pattern")
470-
sidecarArgs = append(sidecarArgs, fmt.Sprint(*pattern))
469+
sidecarArgs = append(sidecarArgs, "--public-ip-family")
470+
sidecarArgs = append(sidecarArgs, fmt.Sprint(*family))
471471
}
472472
}
473473
sidecarEnv = append(sidecarEnv, corev1.EnvVar{Name: "FDB_PUBLIC_IP", ValueFrom: &corev1.EnvVarSource{

controllers/pod_models_test.go

+6-6
Original file line numberDiff line numberDiff line change
@@ -383,8 +383,8 @@ var _ = Describe("pod_models", func() {
383383

384384
Context("with a pod IP pattern defined", func() {
385385
BeforeEach(func() {
386-
pattern := ":"
387-
cluster.Spec.Routing.PodIPPattern = &pattern
386+
family := 6
387+
cluster.Spec.Routing.PodIPFamily = &family
388388
spec, err = GetPodSpec(cluster, fdbtypes.ProcessClassStorage, 1)
389389
})
390390

@@ -403,8 +403,8 @@ var _ = Describe("pod_models", func() {
403403
"fdbcli",
404404
"--main-container-version",
405405
"6.2.20",
406-
"--public-ip-pattern",
407-
":",
406+
"--public-ip-family",
407+
"6",
408408
"--init-mode",
409409
}))
410410
Expect(initContainer.Env).To(Equal([]corev1.EnvVar{
@@ -435,8 +435,8 @@ var _ = Describe("pod_models", func() {
435435
"fdbcli",
436436
"--main-container-version",
437437
"6.2.20",
438-
"--public-ip-pattern",
439-
":",
438+
"--public-ip-family",
439+
"6",
440440
}))
441441
Expect(sidecarContainer.Env).To(Equal([]corev1.EnvVar{
442442
{Name: "FDB_PUBLIC_IP", ValueFrom: &corev1.EnvVarSource{

docs/cluster_spec.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -462,7 +462,7 @@ RoutingConfig allows configuring routing to our pods, and services that sit in f
462462
| ----- | ----------- | ------ | -------- |
463463
| headlessService | Headless determines whether we want to run a headless service for the cluster. | *bool | false |
464464
| publicIPSource | PublicIPSource specifies what source a process should use to get its public IPs. This supports the values `pod` and `service`. | *PublicIPSource | false |
465-
| podIPPattern | PodIPIndex tells the pod to use a specific entry from the podIPs list instead of the default podIP. The entry be the first one that matches the pattern that is provided in this field. This feature is only supported in FDB 7.0 or later, and requires dual-stack support in your Kubernetes environment. | *string | false |
465+
| podIPFamily | PodIPFamily tells the pod which family of IP addresses to use. You can use 4 to represent IPv4, and 6 to represent IPv6. This feature is only supported in FDB 7.0 or later, and requires dual-stack support in your Kubernetes environment. | *int | false |
466466

467467
[Back to TOC](#table-of-contents)
468468

foundationdb-kubernetes-sidecar/sidecar.py

+22-19
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121

2222
import argparse
2323
import hashlib
24+
import ipaddress
2425
import logging
2526
import json
2627
import os
@@ -56,9 +57,7 @@ def __init__(self):
5657
),
5758
action="store_true",
5859
)
59-
parser.add_argument(
60-
"--bind-address", help="IP and port to bind on"
61-
)
60+
parser.add_argument("--bind-address", help="IP and port to bind on")
6261
parser.add_argument(
6362
"--tls",
6463
help=("This flag enables TLS for incoming connections"),
@@ -150,10 +149,10 @@ def __init__(self):
150149
help=("The version of the main foundationdb container in the pod"),
151150
)
152151
parser.add_argument(
153-
"--public-ip-pattern",
152+
"--public-ip-family",
154153
help=(
155154
"Tells the sidecar to treat the public IP as a comma-separated "
156-
"list, and use the first entry matching this pattern"
155+
"list, and use the first entry in the specified IP family"
157156
),
158157
)
159158
parser.add_argument(
@@ -224,7 +223,7 @@ def __init__(self):
224223
"FDB_MACHINE_ID",
225224
"FDB_ZONE_ID",
226225
"FDB_INSTANCE_ID",
227-
"FDB_POD_IP"
226+
"FDB_POD_IP",
228227
]:
229228
self.substitutions[key] = os.getenv(key, "")
230229

@@ -298,11 +297,14 @@ def __init__(self):
298297
if os.getenv("COPY_ONCE", "0") == "1":
299298
self.init_mode = True
300299

301-
if args.public_ip_pattern:
302-
regex = re.compile(args.public_ip_pattern)
303-
304-
self.substitutions["FDB_PUBLIC_IP"] = Config.extract_desired_ip(regex, self.substitutions["FDB_PUBLIC_IP"])
305-
self.substitutions["FDB_POD_IP"] = Config.extract_desired_ip(regex, self.substitutions["FDB_POD_IP"])
300+
if args.public_ip_family:
301+
version = int(args.public_ip_family)
302+
self.substitutions["FDB_PUBLIC_IP"] = Config.extract_desired_ip(
303+
version, self.substitutions["FDB_PUBLIC_IP"]
304+
)
305+
self.substitutions["FDB_POD_IP"] = Config.extract_desired_ip(
306+
version, self.substitutions["FDB_POD_IP"]
307+
)
306308

307309
if not self.bind_address:
308310
if self.substitutions["FDB_POD_IP"] != "":
@@ -326,16 +328,16 @@ def is_at_least(self, target_version):
326328
)
327329

328330
@classmethod
329-
def extract_desired_ip(cls, pattern, string):
331+
def extract_desired_ip(cls, version, string):
330332
if string == "":
331333
return string
332334

333335
ips = string.split(",")
334-
matching_ips = [ip for ip in ips if pattern.search(ip)]
336+
matching_ips = [ip for ip in ips if ipaddress.ip_address(ip).version == version]
335337
if len(matching_ips) == 0:
336-
raise Exception("Failed to find IP matching %s in %s" % (pattern, ips))
338+
raise Exception(f"Failed to find IPv{version} entry in {ips}")
337339
ip = matching_ips[0]
338-
if ":" in ip:
340+
if version == 6:
339341
ip = "[%s]" % ip
340342
return ip
341343

@@ -353,12 +355,13 @@ def start(cls):
353355
This method starts the server.
354356
"""
355357
config = Config.shared()
356-
port_index = config.bind_address.rindex(":")
357-
address = config.bind_address[:port_index]
358-
port = config.bind_address[port_index+1:]
358+
colon_index = config.bind_address.rindex(":")
359+
port_index = colon_index + 1
360+
address = config.bind_address[:colon_index]
361+
port = config.bind_address[port_index:]
359362
log.info(f"Listening on {address}:{port}")
360363

361-
if ":" in address:
364+
if address.startswith("[") and address.endswith("]"):
362365
server = ThreadingHTTPServerV6((address[1:-1], int(port)), cls)
363366
else:
364367
server = ThreadingHTTPServer((address, int(port)), cls)

0 commit comments

Comments
 (0)