Skip to content
16 changes: 16 additions & 0 deletions apis/druid/v1alpha1/druid_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,14 @@ type DruidSpec struct {

// +optional
Auth druidapi.Auth `json:"auth,omitempty"`

// See v1.DNSPolicy for more details.
// +optional
DNSPolicy v1.DNSPolicy `json:"dnsPolicy,omitempty" protobuf:"bytes,6,opt,name=dnsPolicy,casttype=DNSPolicy"`

// See v1.PodDNSConfig for more details.
// +optional
DNSConfig *v1.PodDNSConfig `json:"dnsConfig,omitempty" protobuf:"bytes,26,opt,name=dnsConfig"`
}

// DruidNodeSpec Specification of `Druid` Node type and its configurations.
Expand Down Expand Up @@ -494,6 +502,14 @@ type DruidNodeSpec struct {
// Dynamic Configurations for Druid. Applied through the dynamic configuration API.
// +optional
DynamicConfig runtime.RawExtension `json:"dynamicConfig,omitempty"`

// See v1.DNSPolicy for more details.
// +optional
DNSPolicy v1.DNSPolicy `json:"dnsPolicy,omitempty" protobuf:"bytes,6,opt,name=dnsPolicy,casttype=DNSPolicy"`

// See v1.PodDNSConfig for more details.
// +optional
DNSConfig *v1.PodDNSConfig `json:"dnsConfig,omitempty" protobuf:"bytes,26,opt,name=dnsConfig"`
}

// ZookeeperSpec IGNORED (Future API): In order to make Druid dependency setup extensible from within Druid operator.
Expand Down
10 changes: 10 additions & 0 deletions apis/druid/v1alpha1/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

80 changes: 80 additions & 0 deletions chart/crds/druid.apache.org_druids.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1501,6 +1501,46 @@ spec:
description: DisablePVCDeletionFinalizer Whether PVCs shall be deleted
on the deletion of the Druid cluster.
type: boolean
dnsConfig:
description: See v1.PodDNSConfig for more details.
properties:
nameservers:
description: |-
A list of DNS name server IP addresses.
This will be appended to the base nameservers generated from DNSPolicy.
Duplicated nameservers will be removed.
items:
type: string
type: array
options:
description: |-
A list of DNS resolver options.
This will be merged with the base options generated from DNSPolicy.
Duplicated entries will be removed. Resolution options given in Options
will override those that appear in the base DNSPolicy.
items:
description: PodDNSConfigOption defines DNS resolver options
of a pod.
properties:
name:
description: Required.
type: string
value:
type: string
type: object
type: array
searches:
description: |-
A list of DNS search domains for host-name lookup.
This will be appended to the base search paths generated from DNSPolicy.
Duplicated search paths will be removed.
items:
type: string
type: array
type: object
dnsPolicy:
description: See v1.DNSPolicy for more details.
type: string
dynamicConfig:
description: Dynamic Configurations for Druid. Applied through the
dynamic configuration API.
Expand Down Expand Up @@ -3367,6 +3407,46 @@ spec:
type: string
type: object
type: object
dnsConfig:
description: See v1.PodDNSConfig for more details.
properties:
nameservers:
description: |-
A list of DNS name server IP addresses.
This will be appended to the base nameservers generated from DNSPolicy.
Duplicated nameservers will be removed.
items:
type: string
type: array
options:
description: |-
A list of DNS resolver options.
This will be merged with the base options generated from DNSPolicy.
Duplicated entries will be removed. Resolution options given in Options
will override those that appear in the base DNSPolicy.
items:
description: PodDNSConfigOption defines DNS resolver options
of a pod.
properties:
name:
description: Required.
type: string
value:
type: string
type: object
type: array
searches:
description: |-
A list of DNS search domains for host-name lookup.
This will be appended to the base search paths generated from DNSPolicy.
Duplicated search paths will be removed.
items:
type: string
type: array
type: object
dnsPolicy:
description: See v1.DNSPolicy for more details.
type: string
druid.port:
description: DruidPort Used by the `Druid` process.
format: int32
Expand Down
80 changes: 80 additions & 0 deletions config/crd/bases/druid.apache.org_druids.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1501,6 +1501,46 @@ spec:
description: DisablePVCDeletionFinalizer Whether PVCs shall be deleted
on the deletion of the Druid cluster.
type: boolean
dnsConfig:
description: See v1.PodDNSConfig for more details.
properties:
nameservers:
description: |-
A list of DNS name server IP addresses.
This will be appended to the base nameservers generated from DNSPolicy.
Duplicated nameservers will be removed.
items:
type: string
type: array
options:
description: |-
A list of DNS resolver options.
This will be merged with the base options generated from DNSPolicy.
Duplicated entries will be removed. Resolution options given in Options
will override those that appear in the base DNSPolicy.
items:
description: PodDNSConfigOption defines DNS resolver options
of a pod.
properties:
name:
description: Required.
type: string
value:
type: string
type: object
type: array
searches:
description: |-
A list of DNS search domains for host-name lookup.
This will be appended to the base search paths generated from DNSPolicy.
Duplicated search paths will be removed.
items:
type: string
type: array
type: object
dnsPolicy:
description: See v1.DNSPolicy for more details.
type: string
dynamicConfig:
description: Dynamic Configurations for Druid. Applied through the
dynamic configuration API.
Expand Down Expand Up @@ -3367,6 +3407,46 @@ spec:
type: string
type: object
type: object
dnsConfig:
description: See v1.PodDNSConfig for more details.
properties:
nameservers:
description: |-
A list of DNS name server IP addresses.
This will be appended to the base nameservers generated from DNSPolicy.
Duplicated nameservers will be removed.
items:
type: string
type: array
options:
description: |-
A list of DNS resolver options.
This will be merged with the base options generated from DNSPolicy.
Duplicated entries will be removed. Resolution options given in Options
will override those that appear in the base DNSPolicy.
items:
description: PodDNSConfigOption defines DNS resolver options
of a pod.
properties:
name:
description: Required.
type: string
value:
type: string
type: object
type: array
searches:
description: |-
A list of DNS search domains for host-name lookup.
This will be appended to the base search paths generated from DNSPolicy.
Duplicated search paths will be removed.
items:
type: string
type: array
type: object
dnsPolicy:
description: See v1.DNSPolicy for more details.
type: string
druid.port:
description: DruidPort Used by the `Druid` process.
format: int32
Expand Down
2 changes: 2 additions & 0 deletions controllers/druid/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -1122,6 +1122,8 @@ func makePodSpec(nodeSpec *v1alpha1.DruidNodeSpec, m *v1alpha1.Druid, nodeSpecUn
SecurityContext: firstNonNilValue(nodeSpec.PodSecurityContext, m.Spec.PodSecurityContext).(*v1.PodSecurityContext),
ServiceAccountName: firstNonEmptyStr(nodeSpec.ServiceAccountName, m.Spec.ServiceAccount),
PriorityClassName: firstNonEmptyStr(nodeSpec.PriorityClassName, m.Spec.PriorityClassName),
DNSPolicy: v1.DNSPolicy(firstNonEmptyStr(string(nodeSpec.DNSPolicy), string(m.Spec.DNSPolicy))),
DNSConfig: firstNonNilValue(nodeSpec.DNSConfig, m.Spec.DNSConfig).(*v1.PodDNSConfig),
}

addAdditionalContainers(m, nodeSpec, &spec)
Expand Down
138 changes: 138 additions & 0 deletions controllers/druid/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package druid

import (
"io/ioutil"
"reflect"
"testing"

"github.com/ghodss/yaml"
. "github.com/onsi/ginkgo/v2"
Expand Down Expand Up @@ -213,3 +215,139 @@ func readAndUnmarshallResource(file string, res interface{}) error {
}
return nil
}

func TestPodSpecDNSConfig(t *testing.T) {
tests := []struct {
name string
nodeDNSConfig *corev1.PodDNSConfig
specDNSConfig *corev1.PodDNSConfig
expected *corev1.PodDNSConfig
}{
{
name: "Both nil",
nodeDNSConfig: nil,
specDNSConfig: nil,
expected: nil,
},
{
name: "Only spec provided",
nodeDNSConfig: nil,
specDNSConfig: &corev1.PodDNSConfig{
Nameservers: []string{"8.8.8.8"},
Searches: []string{"example.com"},
},
expected: &corev1.PodDNSConfig{
Nameservers: []string{"8.8.8.8"},
Searches: []string{"example.com"},
},
},
{
name: "Only node provided",
nodeDNSConfig: &corev1.PodDNSConfig{
Nameservers: []string{"1.1.1.1"},
Searches: []string{"node.local"},
},
specDNSConfig: nil,
expected: &corev1.PodDNSConfig{
Nameservers: []string{"1.1.1.1"},
Searches: []string{"node.local"},
},
},
{
name: "Both provided, node wins",
nodeDNSConfig: &corev1.PodDNSConfig{
Nameservers: []string{"1.1.1.1"},
Searches: []string{"node.local"},
},
specDNSConfig: &corev1.PodDNSConfig{
Nameservers: []string{"8.8.8.8"},
Searches: []string{"example.com"},
},
expected: &corev1.PodDNSConfig{
Nameservers: []string{"1.1.1.1"},
Searches: []string{"node.local"},
},
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
m := &druidv1alpha1.Druid{
Spec: druidv1alpha1.DruidSpec{
DNSConfig: tc.specDNSConfig,
},
}
nodeSpec := &druidv1alpha1.DruidNodeSpec{
DNSConfig: tc.nodeDNSConfig,
}
podSpec := makePodSpec(nodeSpec, m, "unique", "dummySHA")
if !reflect.DeepEqual(podSpec.DNSConfig, tc.expected) {
t.Errorf("expected DNSConfig %v, got %v", tc.expected, podSpec.DNSConfig)
}
})
}
}

func TestPodSpecDNSConfigYAML(t *testing.T) {
m, err := readDruidClusterSpecFromFile("testdata/druid-test-cr.yaml")
if err != nil {
t.Fatalf("failed to read cluster spec: %v", err)
}
nodeSpec := m.Spec.Nodes["middlemanagers"]
podSpec := makePodSpec(&nodeSpec, m, "unique", "dummySHA")
expectedDNSConfig := &corev1.PodDNSConfig{
Nameservers: []string{"10.0.0.53"},
Searches: []string{"example.local"},
}
if !reflect.DeepEqual(podSpec.DNSConfig, expectedDNSConfig) {
t.Errorf("expected DNSConfig %v, got %v", expectedDNSConfig, podSpec.DNSConfig)
}
}

// TestPodSpecDNSPolicy verifies DNSPolicy resolution in makePodSpec.
func TestPodSpecDNSPolicy(t *testing.T) {
tests := []struct {
name string
nodeDNS string
specDNS string
expected corev1.DNSPolicy
}{
{"Both empty", "", "", corev1.DNSPolicy("")},
{"Only spec provided", "", "ClusterFirst", corev1.DNSPolicy("ClusterFirst")},
{"Only node provided", "Default", "", corev1.DNSPolicy("Default")},
{"Both provided, node wins", "Default", "ClusterFirst", corev1.DNSPolicy("Default")},
}

for _, tc := range tests {
tc := tc // capture current test case
t.Run(tc.name, func(t *testing.T) {
m := &druidv1alpha1.Druid{
Spec: druidv1alpha1.DruidSpec{
DNSPolicy: corev1.DNSPolicy(tc.specDNS),
},
}
nodeSpec := &druidv1alpha1.DruidNodeSpec{
DNSPolicy: corev1.DNSPolicy(tc.nodeDNS),
}
podSpec := makePodSpec(nodeSpec, m, "unique", "dummySHA")
if podSpec.DNSPolicy != tc.expected {
t.Errorf("expected DNSPolicy %q, got %q", tc.expected, podSpec.DNSPolicy)
}
})
}
}

// TestPodSpecDNSPolicyYAML validates that the generated PodSpec DNSPolicy matches the expected value,
// using the druid-test-cr.yaml as the single input file.
func TestPodSpecDNSPolicyYAML(t *testing.T) {
m, err := readDruidClusterSpecFromFile("testdata/druid-test-cr.yaml")
if err != nil {
t.Fatalf("failed to read cluster spec: %v", err)
}
nodeSpec := m.Spec.Nodes["middlemanagers"]
podSpec := makePodSpec(&nodeSpec, m, "unique", "dummySHA")
expectedDNSPolicy := corev1.DNSPolicy("ClusterFirst")
if podSpec.DNSPolicy != expectedDNSPolicy {
t.Errorf("expected DNSPolicy %q, got %q", expectedDNSPolicy, podSpec.DNSPolicy)
}
}
Loading