Files
my-rook-config/pkg/operator/ceph/nvmeof/spec_test.go
T
Oded Viner bc6e5fbc86 nvmeof: add default gateway pod spreading
ensure each gw pod runs on a different node when possible.
add default pod anti-affinity and topology spread constraints.
keep user placement overrides by merging defaults with spec placement.
add tests for default spread and user override behavior.

Signed-off-by: Oded Viner <oviner@redhat.com>
2026-02-18 19:59:34 +02:00

626 lines
20 KiB
Go

/*
Copyright 2025 The Rook Authors. All rights reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package nvmeof
import (
"fmt"
"strings"
"testing"
cephv1 "github.com/rook/rook/pkg/apis/ceph.rook.io/v1"
rookclient "github.com/rook/rook/pkg/client/clientset/versioned/fake"
"github.com/rook/rook/pkg/client/clientset/versioned/scheme"
"github.com/rook/rook/pkg/clusterd"
cephclient "github.com/rook/rook/pkg/daemon/ceph/client"
cephconfig "github.com/rook/rook/pkg/operator/ceph/config"
cephTest "github.com/rook/rook/pkg/operator/ceph/test"
cephver "github.com/rook/rook/pkg/operator/ceph/version"
optest "github.com/rook/rook/pkg/operator/test"
exectest "github.com/rook/rook/pkg/util/exec/test"
"github.com/stretchr/testify/assert"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/runtime"
"sigs.k8s.io/controller-runtime/pkg/client/fake"
)
func newDeploymentSpecTest(t *testing.T) (*ReconcileCephNVMeOFGateway, string) {
clientset := optest.New(t, 1)
c := &clusterd.Context{
Executor: &exectest.MockExecutor{},
RookClientset: rookclient.NewSimpleClientset(),
Clientset: clientset,
}
s := scheme.Scheme
object := []runtime.Object{
&cephv1.CephNVMeOFGateway{
ObjectMeta: metav1.ObjectMeta{
Name: name,
Namespace: namespace,
},
TypeMeta: controllerTypeMeta,
Spec: cephv1.NVMeOFGatewaySpec{
Image: "quay.io/ceph/nvmeof:1.5",
Pool: "nvmeof",
Group: "group-a",
Instances: 1,
},
},
}
cl := fake.NewClientBuilder().WithScheme(s).WithRuntimeObjects(object...).Build()
r := &ReconcileCephNVMeOFGateway{
client: cl,
scheme: scheme.Scheme,
context: c,
clusterInfo: &cephclient.ClusterInfo{
FSID: "myfsid",
CephVersion: cephver.Squid,
},
cephClusterSpec: &cephv1.ClusterSpec{
CephVersion: cephv1.CephVersionSpec{
Image: "quay.io/ceph/ceph:v19",
},
},
}
configHash := "dcb0d2f5f5e86ec4929d8243cd640b8154165f8ff9b89809964fc7993e9b0101"
return r, configHash
}
func TestDeploymentSpec(t *testing.T) {
t.Run("basic", func(t *testing.T) {
nvmeof := &cephv1.CephNVMeOFGateway{
ObjectMeta: metav1.ObjectMeta{
Name: "my-nvmeof",
Namespace: "rook-ceph-test-ns",
},
Spec: cephv1.NVMeOFGatewaySpec{
Image: "quay.io/ceph/nvmeof:1.5",
Pool: "nvmeof",
Group: "group-a",
Instances: 3,
Resources: v1.ResourceRequirements{
Limits: v1.ResourceList{
v1.ResourceCPU: *resource.NewQuantity(500.0, resource.BinarySI),
v1.ResourceMemory: *resource.NewQuantity(1024.0, resource.BinarySI),
},
Requests: v1.ResourceList{
v1.ResourceCPU: *resource.NewQuantity(200.0, resource.BinarySI),
v1.ResourceMemory: *resource.NewQuantity(512.0, resource.BinarySI),
},
},
PriorityClassName: "my-priority-class",
},
}
r, configHash := newDeploymentSpecTest(t)
configMapName := fmt.Sprintf("rook-ceph-nvmeof-%s-config", nvmeof.Name)
d, err := r.makeDeployment(nvmeof, "0", configMapName, configHash)
assert.NoError(t, err)
assert.NotEmpty(t, d.Spec.Template.Annotations)
assert.Equal(t, configHash, d.Spec.Template.Annotations["config-hash"])
// Verify deployment labels contain Ceph requirements
daemonID := nvmeof.Name + "-0"
cephTest.AssertLabelsContainCephRequirements(t, d.ObjectMeta.Labels,
"nvmeof", daemonID, AppName, nvmeof.Namespace, nvmeof.Name,
"cephnvmeofgateways.ceph.rook.io", "ceph-nvmeof")
podTemplate := optest.NewPodTemplateSpecTester(t, &d.Spec.Template)
podTemplate.RunFullSuite(
AppName,
optest.ResourceLimitExpectations{
CPUResourceLimit: "500",
MemoryResourceLimit: "1Ki",
CPUResourceRequest: "200",
MemoryResourceRequest: "512",
},
)
assert.Equal(t, "my-priority-class", d.Spec.Template.Spec.PriorityClassName)
assert.Equal(t, serviceAccountName, d.Spec.Template.Spec.ServiceAccountName)
})
t.Run("basic with default liveness-probe", func(t *testing.T) {
nvmeof := &cephv1.CephNVMeOFGateway{
ObjectMeta: metav1.ObjectMeta{
Name: "my-nvmeof",
Namespace: "rook-ceph-test-ns",
},
Spec: cephv1.NVMeOFGatewaySpec{
Image: "quay.io/ceph/nvmeof:1.5",
Pool: "nvmeof",
Group: "group-a",
Instances: 3,
Resources: v1.ResourceRequirements{
Limits: v1.ResourceList{
v1.ResourceCPU: *resource.NewQuantity(500.0, resource.BinarySI),
v1.ResourceMemory: *resource.NewQuantity(1024.0, resource.BinarySI),
},
Requests: v1.ResourceList{
v1.ResourceCPU: *resource.NewQuantity(200.0, resource.BinarySI),
v1.ResourceMemory: *resource.NewQuantity(512.0, resource.BinarySI),
},
},
PriorityClassName: "my-priority-class",
LivenessProbe: &cephv1.ProbeSpec{
Disabled: false,
},
},
}
r, configHash := newDeploymentSpecTest(t)
configMapName := fmt.Sprintf("rook-ceph-nvmeof-%s-config", nvmeof.Name)
d, err := r.makeDeployment(nvmeof, "0", configMapName, configHash)
assert.NoError(t, err)
assert.NotEmpty(t, d.Spec.Template.Annotations)
var nvmeofCont *v1.Container = nil
for i := range d.Spec.Template.Spec.Containers {
if d.Spec.Template.Spec.Containers[i].Name == "nvmeof-gateway" {
nvmeofCont = &d.Spec.Template.Spec.Containers[i]
break
}
}
assert.NotNil(t, nvmeofCont)
assert.NotNil(t, nvmeofCont.LivenessProbe)
assert.Equal(t, nvmeofCont.LivenessProbe.InitialDelaySeconds, int32(10))
assert.Equal(t, nvmeofCont.LivenessProbe.FailureThreshold, int32(10))
assert.GreaterOrEqual(t, nvmeofCont.LivenessProbe.TimeoutSeconds, int32(5))
})
t.Run("applies default placement when not specified", func(t *testing.T) {
nvmeof := &cephv1.CephNVMeOFGateway{
ObjectMeta: metav1.ObjectMeta{
Name: "my-nvmeof",
Namespace: "rook-ceph-test-ns",
},
Spec: cephv1.NVMeOFGatewaySpec{
Image: "quay.io/ceph/nvmeof:1.5",
Pool: "nvmeof",
Group: "group-a",
Instances: 3,
},
}
r, configHash := newDeploymentSpecTest(t)
configMapName := fmt.Sprintf("rook-ceph-nvmeof-%s-config", nvmeof.Name)
d, err := r.makeDeployment(nvmeof, "0", configMapName, configHash)
assert.NoError(t, err)
if assert.NotNil(t, d.Spec.Template.Spec.Affinity) {
assert.Nil(t, d.Spec.Template.Spec.Affinity.PodAntiAffinity)
}
assert.Len(t, d.Spec.Template.Spec.TopologySpreadConstraints, 1)
assert.Equal(t, int32(1), d.Spec.Template.Spec.TopologySpreadConstraints[0].MaxSkew)
assert.Equal(t, "kubernetes.io/hostname", d.Spec.Template.Spec.TopologySpreadConstraints[0].TopologyKey)
assert.Equal(t, v1.ScheduleAnyway, d.Spec.Template.Spec.TopologySpreadConstraints[0].WhenUnsatisfiable)
assert.Equal(t, map[string]string{"app": AppName}, d.Spec.Template.Spec.TopologySpreadConstraints[0].LabelSelector.MatchLabels)
})
t.Run("user placement overrides default placement", func(t *testing.T) {
nvmeof := &cephv1.CephNVMeOFGateway{
ObjectMeta: metav1.ObjectMeta{
Name: "my-nvmeof",
Namespace: "rook-ceph-test-ns",
},
Spec: cephv1.NVMeOFGatewaySpec{
Image: "quay.io/ceph/nvmeof:1.5",
Pool: "nvmeof",
Group: "group-a",
Instances: 3,
Placement: cephv1.Placement{
PodAntiAffinity: &v1.PodAntiAffinity{
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
{
TopologyKey: "topology.kubernetes.io/zone",
LabelSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"app": "custom-app",
},
},
},
},
},
TopologySpreadConstraints: []v1.TopologySpreadConstraint{
{
MaxSkew: 2,
TopologyKey: "topology.kubernetes.io/zone",
WhenUnsatisfiable: v1.DoNotSchedule,
LabelSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"app": "custom-app",
},
},
},
},
},
},
}
r, configHash := newDeploymentSpecTest(t)
configMapName := fmt.Sprintf("rook-ceph-nvmeof-%s-config", nvmeof.Name)
d, err := r.makeDeployment(nvmeof, "0", configMapName, configHash)
assert.NoError(t, err)
assert.NotNil(t, d.Spec.Template.Spec.Affinity)
assert.NotNil(t, d.Spec.Template.Spec.Affinity.PodAntiAffinity)
assert.Len(t, d.Spec.Template.Spec.Affinity.PodAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution, 1)
assert.Empty(t, d.Spec.Template.Spec.Affinity.PodAntiAffinity.PreferredDuringSchedulingIgnoredDuringExecution)
assert.Equal(t, "topology.kubernetes.io/zone", d.Spec.Template.Spec.Affinity.PodAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution[0].TopologyKey)
assert.Equal(t, map[string]string{"app": "custom-app"}, d.Spec.Template.Spec.Affinity.PodAntiAffinity.RequiredDuringSchedulingIgnoredDuringExecution[0].LabelSelector.MatchLabels)
assert.Len(t, d.Spec.Template.Spec.TopologySpreadConstraints, 1)
assert.Equal(t, int32(2), d.Spec.Template.Spec.TopologySpreadConstraints[0].MaxSkew)
assert.Equal(t, "topology.kubernetes.io/zone", d.Spec.Template.Spec.TopologySpreadConstraints[0].TopologyKey)
assert.Equal(t, v1.DoNotSchedule, d.Spec.Template.Spec.TopologySpreadConstraints[0].WhenUnsatisfiable)
assert.Equal(t, map[string]string{"app": "custom-app"}, d.Spec.Template.Spec.TopologySpreadConstraints[0].LabelSelector.MatchLabels)
})
t.Run("with host network", func(t *testing.T) {
nvmeof := &cephv1.CephNVMeOFGateway{
ObjectMeta: metav1.ObjectMeta{
Name: "my-nvmeof",
Namespace: "rook-ceph-test-ns",
},
Spec: cephv1.NVMeOFGatewaySpec{
Image: "quay.io/ceph/nvmeof:1.5",
Pool: "nvmeof",
Group: "group-a",
Instances: 1,
},
}
r, configHash := newDeploymentSpecTest(t)
r.cephClusterSpec.Network = cephv1.NetworkSpec{
HostNetwork: true,
}
configMapName := fmt.Sprintf("rook-ceph-nvmeof-%s-config", nvmeof.Name)
d, err := r.makeDeployment(nvmeof, "0", configMapName, configHash)
assert.NoError(t, err)
assert.True(t, d.Spec.Template.Spec.HostNetwork)
assert.Equal(t, v1.DNSClusterFirstWithHostNet, d.Spec.Template.Spec.DNSPolicy)
svc := r.generateCephNVMeOFService(nvmeof, "0")
assert.Equal(t, v1.ClusterIPNone, svc.Spec.ClusterIP)
})
t.Run("with custom configmap ref", func(t *testing.T) {
nvmeof := &cephv1.CephNVMeOFGateway{
ObjectMeta: metav1.ObjectMeta{
Name: "my-nvmeof",
Namespace: "rook-ceph-test-ns",
},
Spec: cephv1.NVMeOFGatewaySpec{
Image: "quay.io/ceph/nvmeof:1.5",
Pool: "nvmeof",
Group: "group-a",
Instances: 1,
ConfigMapRef: "custom-configmap",
},
}
r, configHash := newDeploymentSpecTest(t)
configMapName := "custom-configmap"
d, err := r.makeDeployment(nvmeof, "0", configMapName, configHash)
assert.NoError(t, err)
assert.NotEmpty(t, d.Spec.Template.Annotations)
var gatewayConfigVol *v1.Volume = nil
for i := range d.Spec.Template.Spec.Volumes {
if d.Spec.Template.Spec.Volumes[i].Name == "gateway-config" {
gatewayConfigVol = &d.Spec.Template.Spec.Volumes[i]
break
}
}
assert.NotNil(t, gatewayConfigVol)
assert.NotNil(t, gatewayConfigVol.ConfigMap)
assert.Equal(t, "custom-configmap", gatewayConfigVol.ConfigMap.Name)
})
t.Run("init container configuration", func(t *testing.T) {
nvmeof := &cephv1.CephNVMeOFGateway{
ObjectMeta: metav1.ObjectMeta{
Name: "my-nvmeof",
Namespace: "rook-ceph-test-ns",
},
Spec: cephv1.NVMeOFGatewaySpec{
Image: "quay.io/ceph/nvmeof:1.5",
Pool: "nvmeof",
Group: "group-a",
Instances: 1,
},
}
r, configHash := newDeploymentSpecTest(t)
configMapName := fmt.Sprintf("rook-ceph-nvmeof-%s-config", nvmeof.Name)
d, err := r.makeDeployment(nvmeof, "0", configMapName, configHash)
assert.NoError(t, err)
assert.Len(t, d.Spec.Template.Spec.InitContainers, 1)
initCont := d.Spec.Template.Spec.InitContainers[0]
assert.Equal(t, "generate-ceph-conf", initCont.Name)
assert.Equal(t, r.cephClusterSpec.CephVersion.Image, initCont.Image)
assert.Equal(t, []string{"/bin/bash", "-c", connectionConfigScript}, initCont.Command)
assert.Contains(t, initCont.Args, "--keyring=/etc/ceph/keyring")
assertEnvVar(t, initCont.Env, "GATEWAY_NAME", instanceName(nvmeof, "0"))
assertEnvVar(t, initCont.Env, "POOL_NAME", nvmeof.Spec.Pool)
assertEnvVar(t, initCont.Env, "ANA_GROUP", nvmeof.Spec.Group)
assertEnvVarPresent(t, initCont.Env, "POD_IP")
volumeMountNames := []string{}
for _, vm := range initCont.VolumeMounts {
volumeMountNames = append(volumeMountNames, vm.Name)
}
assert.Contains(t, volumeMountNames, "ceph-admin-keyring")
assert.Contains(t, volumeMountNames, "gateway-config")
assert.Contains(t, volumeMountNames, "ceph-conf-emptydir")
})
t.Run("daemon container configuration", func(t *testing.T) {
nvmeof := &cephv1.CephNVMeOFGateway{
ObjectMeta: metav1.ObjectMeta{
Name: "my-nvmeof",
Namespace: "rook-ceph-test-ns",
},
Spec: cephv1.NVMeOFGatewaySpec{
Image: "quay.io/ceph/nvmeof:1.5",
Pool: "nvmeof",
Group: "group-a",
Instances: 1,
},
}
r, configHash := newDeploymentSpecTest(t)
configMapName := fmt.Sprintf("rook-ceph-nvmeof-%s-config", nvmeof.Name)
d, err := r.makeDeployment(nvmeof, "0", configMapName, configHash)
assert.NoError(t, err)
assert.Len(t, d.Spec.Template.Spec.Containers, 1)
daemonCont := d.Spec.Template.Spec.Containers[0]
assert.Equal(t, "nvmeof-gateway", daemonCont.Name)
assert.Equal(t, nvmeof.Spec.Image, daemonCont.Image)
expectedCephArgs := strings.Join(cephconfig.DefaultFlags(r.clusterInfo.FSID, "/etc/ceph/keyring"), " ")
assertEnvVar(t, daemonCont.Env, "CEPH_ARGS", expectedCephArgs)
portNames := []string{}
for _, p := range daemonCont.Ports {
portNames = append(portNames, p.Name)
}
assert.Contains(t, portNames, "io")
assert.Contains(t, portNames, "gateway")
assert.Contains(t, portNames, "monitor")
assert.Contains(t, portNames, "discovery")
assert.NotNil(t, daemonCont.SecurityContext)
// SecurityContext should be set with privileged=true for NVMeOF gateway
assert.NotNil(t, daemonCont.SecurityContext.Privileged)
assert.True(t, *daemonCont.SecurityContext.Privileged)
})
t.Run("daemon container uses default image when not specified", func(t *testing.T) {
nvmeof := &cephv1.CephNVMeOFGateway{
ObjectMeta: metav1.ObjectMeta{
Name: "my-nvmeof",
Namespace: "rook-ceph-test-ns",
},
Spec: cephv1.NVMeOFGatewaySpec{
// Image not specified - should use default
Pool: "nvmeof",
Group: "group-a",
Instances: 1,
},
}
r, configHash := newDeploymentSpecTest(t)
configMapName := fmt.Sprintf("rook-ceph-nvmeof-%s-config", nvmeof.Name)
d, err := r.makeDeployment(nvmeof, "0", configMapName, configHash)
assert.NoError(t, err)
assert.Len(t, d.Spec.Template.Spec.Containers, 1)
daemonCont := d.Spec.Template.Spec.Containers[0]
assert.Equal(t, "nvmeof-gateway", daemonCont.Name)
assert.Equal(t, "quay.io/ceph/nvmeof:1.5", daemonCont.Image)
})
t.Run("hostname set when instance name is valid", func(t *testing.T) {
nvmeof := &cephv1.CephNVMeOFGateway{
ObjectMeta: metav1.ObjectMeta{
Name: "my-nvmeof",
Namespace: "rook-ceph-test-ns",
},
Spec: cephv1.NVMeOFGatewaySpec{
Image: "quay.io/ceph/nvmeof:1.5",
Pool: "nvmeof",
Group: "group-a",
Instances: 1,
},
}
r, configHash := newDeploymentSpecTest(t)
configMapName := fmt.Sprintf("rook-ceph-nvmeof-%s-config", nvmeof.Name)
d, err := r.makeDeployment(nvmeof, "0", configMapName, configHash)
assert.NoError(t, err)
assert.Equal(t, instanceName(nvmeof, "0"), d.Spec.Template.Spec.Hostname)
})
t.Run("hostname not set when instance name is invalid", func(t *testing.T) {
nvmeof := &cephv1.CephNVMeOFGateway{
ObjectMeta: metav1.ObjectMeta{
Name: "my_nvmeof",
Namespace: "rook-ceph-test-ns",
},
Spec: cephv1.NVMeOFGatewaySpec{
Image: "quay.io/ceph/nvmeof:1.5",
Pool: "nvmeof",
Group: "group-a",
Instances: 1,
},
}
r, configHash := newDeploymentSpecTest(t)
configMapName := fmt.Sprintf("rook-ceph-nvmeof-%s-config", nvmeof.Name)
d, err := r.makeDeployment(nvmeof, "0", configMapName, configHash)
assert.NoError(t, err)
assert.Empty(t, d.Spec.Template.Spec.Hostname)
})
t.Run("service generation", func(t *testing.T) {
nvmeof := &cephv1.CephNVMeOFGateway{
ObjectMeta: metav1.ObjectMeta{
Name: "my-nvmeof",
Namespace: "rook-ceph-test-ns",
},
Spec: cephv1.NVMeOFGatewaySpec{
Image: "quay.io/ceph/nvmeof:1.5",
Pool: "nvmeof",
Group: "group-a",
Instances: 1,
},
}
r, _ := newDeploymentSpecTest(t)
svc := r.generateCephNVMeOFService(nvmeof, "0")
assert.Equal(t, "rook-ceph-nvmeof-my-nvmeof-0", svc.Name)
assert.Equal(t, "rook-ceph-test-ns", svc.Namespace)
// Verify service labels contain Ceph requirements
daemonID := nvmeof.Name + "-0"
cephTest.AssertLabelsContainCephRequirements(t, svc.Labels,
"nvmeof", daemonID, AppName, nvmeof.Namespace, nvmeof.Name,
"cephnvmeofgateways.ceph.rook.io", "ceph-nvmeof")
portNames := []string{}
for _, p := range svc.Spec.Ports {
portNames = append(portNames, p.Name)
}
assert.Contains(t, portNames, "io")
assert.Contains(t, portNames, "gateway")
assert.Contains(t, portNames, "monitor")
assert.Contains(t, portNames, "discovery")
for _, p := range svc.Spec.Ports {
switch p.Name {
case "io":
assert.Equal(t, int32(nvmeofIOPort), p.Port)
case "gateway":
assert.Equal(t, int32(nvmeofGatewayPort), p.Port)
case "monitor":
assert.Equal(t, int32(nvmeofMonitorPort), p.Port)
case "discovery":
assert.Equal(t, int32(nvmeofDiscoveryPort), p.Port)
}
}
})
t.Run("custom ports", func(t *testing.T) {
nvmeof := &cephv1.CephNVMeOFGateway{
ObjectMeta: metav1.ObjectMeta{
Name: "my-nvmeof",
Namespace: "rook-ceph-test-ns",
},
Spec: cephv1.NVMeOFGatewaySpec{
Image: "quay.io/ceph/nvmeof:1.5",
Pool: "nvmeof",
Group: "group-a",
Instances: 1,
Ports: &cephv1.NVMeOFGatewayPorts{
IOPort: 14420,
GatewayPort: 15500,
MonitorPort: 15499,
DiscoveryPort: 18009,
},
},
}
r, configHash := newDeploymentSpecTest(t)
configMapName := fmt.Sprintf("rook-ceph-nvmeof-%s-config", nvmeof.Name)
d, err := r.makeDeployment(nvmeof, "0", configMapName, configHash)
assert.NoError(t, err)
daemonCont := d.Spec.Template.Spec.Containers[0]
assertContainerPort(t, daemonCont.Ports, "io", 14420)
assertContainerPort(t, daemonCont.Ports, "gateway", 15500)
assertContainerPort(t, daemonCont.Ports, "monitor", 15499)
assertContainerPort(t, daemonCont.Ports, "discovery", 18009)
svc := r.generateCephNVMeOFService(nvmeof, "0")
assertServicePort(t, svc.Spec.Ports, "io", 14420)
assertServicePort(t, svc.Spec.Ports, "gateway", 15500)
assertServicePort(t, svc.Spec.Ports, "monitor", 15499)
assertServicePort(t, svc.Spec.Ports, "discovery", 18009)
})
}
func assertEnvVar(t *testing.T, envVars []v1.EnvVar, name, value string) {
t.Helper()
for _, env := range envVars {
if env.Name == name {
assert.Equal(t, value, env.Value)
return
}
}
assert.Failf(t, "missing env var", "expected %s", name)
}
func assertEnvVarPresent(t *testing.T, envVars []v1.EnvVar, name string) {
t.Helper()
for _, env := range envVars {
if env.Name == name {
assert.NotNil(t, env.ValueFrom)
return
}
}
assert.Failf(t, "missing env var", "expected %s", name)
}
func assertServicePort(t *testing.T, ports []v1.ServicePort, name string, value int32) {
t.Helper()
for _, port := range ports {
if port.Name == name {
assert.Equal(t, value, port.Port)
return
}
}
assert.Failf(t, "missing port", "expected %s", name)
}
func assertContainerPort(t *testing.T, ports []v1.ContainerPort, name string, value int32) {
t.Helper()
for _, port := range ports {
if port.Name == name {
assert.Equal(t, value, port.ContainerPort)
return
}
}
assert.Failf(t, "missing port", "expected %s", name)
}