2019-06-06 17:43:13 -04:00
|
|
|
/*
|
|
|
|
|
Copyright 2019 The Kubernetes Authors.
|
|
|
|
|
|
|
|
|
|
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 network
|
|
|
|
|
|
|
|
|
|
import (
|
2020-02-07 21:16:47 -05:00
|
|
|
"context"
|
2019-06-06 17:43:13 -04:00
|
|
|
"fmt"
|
|
|
|
|
"net"
|
2020-11-11 17:04:33 -05:00
|
|
|
"strings"
|
2020-01-14 13:10:32 -05:00
|
|
|
"time"
|
2019-06-06 17:43:13 -04:00
|
|
|
|
2022-03-29 02:12:12 -04:00
|
|
|
"github.com/onsi/ginkgo/v2"
|
2019-06-06 17:43:13 -04:00
|
|
|
"github.com/onsi/gomega"
|
|
|
|
|
|
2019-08-26 08:56:38 -04:00
|
|
|
appsv1 "k8s.io/api/apps/v1"
|
2019-06-06 17:43:13 -04:00
|
|
|
v1 "k8s.io/api/core/v1"
|
2024-11-20 15:54:32 -05:00
|
|
|
discoveryv1 "k8s.io/api/discovery/v1"
|
2019-06-06 17:43:13 -04:00
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
|
clientset "k8s.io/client-go/kubernetes"
|
2023-06-20 04:27:14 -04:00
|
|
|
"k8s.io/kubernetes/test/e2e/feature"
|
2019-06-06 17:43:13 -04:00
|
|
|
"k8s.io/kubernetes/test/e2e/framework"
|
2020-03-24 21:57:32 -04:00
|
|
|
e2edeployment "k8s.io/kubernetes/test/e2e/framework/deployment"
|
2025-06-10 09:51:15 -04:00
|
|
|
e2eendpointslice "k8s.io/kubernetes/test/e2e/framework/endpointslice"
|
2020-11-11 17:04:33 -05:00
|
|
|
e2enetwork "k8s.io/kubernetes/test/e2e/framework/network"
|
2019-06-06 17:43:13 -04:00
|
|
|
e2enode "k8s.io/kubernetes/test/e2e/framework/node"
|
e2e: adapt to moved code
This is the result of automatically editing source files like this:
go install golang.org/x/tools/cmd/goimports@latest
find ./test/e2e* -name "*.go" | xargs env PATH=$GOPATH/bin:$PATH ./e2e-framework-sed.sh
with e2e-framework-sed.sh containing this:
sed -i \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecCommandInContainer(/e2epod.ExecCommandInContainer(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecCommandInContainerWithFullOutput(/e2epod.ExecCommandInContainerWithFullOutput(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecShellInContainer(/e2epod.ExecShellInContainer(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecShellInPod(/e2epod.ExecShellInPod(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecShellInPodWithFullOutput(/e2epod.ExecShellInPodWithFullOutput(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecWithOptions(/e2epod.ExecWithOptions(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.MatchContainerOutput(/e2eoutput.MatchContainerOutput(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.PodClient(/e2epod.NewPodClient(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.PodClientNS(/e2epod.PodClientNS(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.TestContainerOutput(/e2eoutput.TestContainerOutput(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.TestContainerOutputRegexp(/e2eoutput.TestContainerOutputRegexp(\1, /" \
-e "s/framework.AddOrUpdateLabelOnNode\b/e2enode.AddOrUpdateLabelOnNode/" \
-e "s/framework.AllNodes\b/e2edebug.AllNodes/" \
-e "s/framework.AllNodesReady\b/e2enode.AllNodesReady/" \
-e "s/framework.ContainerResourceGatherer\b/e2edebug.ContainerResourceGatherer/" \
-e "s/framework.ContainerResourceUsage\b/e2edebug.ContainerResourceUsage/" \
-e "s/framework.CreateEmptyFileOnPod\b/e2eoutput.CreateEmptyFileOnPod/" \
-e "s/framework.DefaultPodDeletionTimeout\b/e2epod.DefaultPodDeletionTimeout/" \
-e "s/framework.DumpAllNamespaceInfo\b/e2edebug.DumpAllNamespaceInfo/" \
-e "s/framework.DumpDebugInfo\b/e2eoutput.DumpDebugInfo/" \
-e "s/framework.DumpNodeDebugInfo\b/e2edebug.DumpNodeDebugInfo/" \
-e "s/framework.EtcdUpgrade\b/e2eproviders.EtcdUpgrade/" \
-e "s/framework.EventsLister\b/e2edebug.EventsLister/" \
-e "s/framework.ExecOptions\b/e2epod.ExecOptions/" \
-e "s/framework.ExpectNodeHasLabel\b/e2enode.ExpectNodeHasLabel/" \
-e "s/framework.ExpectNodeHasTaint\b/e2enode.ExpectNodeHasTaint/" \
-e "s/framework.GCEUpgradeScript\b/e2eproviders.GCEUpgradeScript/" \
-e "s/framework.ImagePrePullList\b/e2epod.ImagePrePullList/" \
-e "s/framework.KubectlBuilder\b/e2ekubectl.KubectlBuilder/" \
-e "s/framework.LocationParamGKE\b/e2eproviders.LocationParamGKE/" \
-e "s/framework.LogSizeDataTimeseries\b/e2edebug.LogSizeDataTimeseries/" \
-e "s/framework.LogSizeGatherer\b/e2edebug.LogSizeGatherer/" \
-e "s/framework.LogsSizeData\b/e2edebug.LogsSizeData/" \
-e "s/framework.LogsSizeDataSummary\b/e2edebug.LogsSizeDataSummary/" \
-e "s/framework.LogsSizeVerifier\b/e2edebug.LogsSizeVerifier/" \
-e "s/framework.LookForStringInLog\b/e2eoutput.LookForStringInLog/" \
-e "s/framework.LookForStringInPodExec\b/e2eoutput.LookForStringInPodExec/" \
-e "s/framework.LookForStringInPodExecToContainer\b/e2eoutput.LookForStringInPodExecToContainer/" \
-e "s/framework.MasterAndDNSNodes\b/e2edebug.MasterAndDNSNodes/" \
-e "s/framework.MasterNodes\b/e2edebug.MasterNodes/" \
-e "s/framework.MasterUpgradeGKE\b/e2eproviders.MasterUpgradeGKE/" \
-e "s/framework.NewKubectlCommand\b/e2ekubectl.NewKubectlCommand/" \
-e "s/framework.NewLogsVerifier\b/e2edebug.NewLogsVerifier/" \
-e "s/framework.NewNodeKiller\b/e2enode.NewNodeKiller/" \
-e "s/framework.NewResourceUsageGatherer\b/e2edebug.NewResourceUsageGatherer/" \
-e "s/framework.NodeHasTaint\b/e2enode.NodeHasTaint/" \
-e "s/framework.NodeKiller\b/e2enode.NodeKiller/" \
-e "s/framework.NodesSet\b/e2edebug.NodesSet/" \
-e "s/framework.PodClient\b/e2epod.PodClient/" \
-e "s/framework.RemoveLabelOffNode\b/e2enode.RemoveLabelOffNode/" \
-e "s/framework.ResourceConstraint\b/e2edebug.ResourceConstraint/" \
-e "s/framework.ResourceGathererOptions\b/e2edebug.ResourceGathererOptions/" \
-e "s/framework.ResourceUsagePerContainer\b/e2edebug.ResourceUsagePerContainer/" \
-e "s/framework.ResourceUsageSummary\b/e2edebug.ResourceUsageSummary/" \
-e "s/framework.RunHostCmd\b/e2eoutput.RunHostCmd/" \
-e "s/framework.RunHostCmdOrDie\b/e2eoutput.RunHostCmdOrDie/" \
-e "s/framework.RunHostCmdWithFullOutput\b/e2eoutput.RunHostCmdWithFullOutput/" \
-e "s/framework.RunHostCmdWithRetries\b/e2eoutput.RunHostCmdWithRetries/" \
-e "s/framework.RunKubectl\b/e2ekubectl.RunKubectl/" \
-e "s/framework.RunKubectlInput\b/e2ekubectl.RunKubectlInput/" \
-e "s/framework.RunKubectlOrDie\b/e2ekubectl.RunKubectlOrDie/" \
-e "s/framework.RunKubectlOrDieInput\b/e2ekubectl.RunKubectlOrDieInput/" \
-e "s/framework.RunKubectlWithFullOutput\b/e2ekubectl.RunKubectlWithFullOutput/" \
-e "s/framework.RunKubemciCmd\b/e2ekubectl.RunKubemciCmd/" \
-e "s/framework.RunKubemciWithKubeconfig\b/e2ekubectl.RunKubemciWithKubeconfig/" \
-e "s/framework.SingleContainerSummary\b/e2edebug.SingleContainerSummary/" \
-e "s/framework.SingleLogSummary\b/e2edebug.SingleLogSummary/" \
-e "s/framework.TimestampedSize\b/e2edebug.TimestampedSize/" \
-e "s/framework.WaitForAllNodesSchedulable\b/e2enode.WaitForAllNodesSchedulable/" \
-e "s/framework.WaitForSSHTunnels\b/e2enode.WaitForSSHTunnels/" \
-e "s/framework.WorkItem\b/e2edebug.WorkItem/" \
"$@"
for i in "$@"; do
# Import all sub packages and let goimports figure out which of those
# are redundant (= already imported) or not needed.
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2edebug "k8s.io/kubernetes/test/e2e/framework/debug"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2ekubectl "k8s.io/kubernetes/test/e2e/framework/kubectl"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2enode "k8s.io/kubernetes/test/e2e/framework/node"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2eoutput "k8s.io/kubernetes/test/e2e/framework/pod/output"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2epod "k8s.io/kubernetes/test/e2e/framework/pod"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2eproviders "k8s.io/kubernetes/test/e2e/framework/providers"' "$i"
goimports -w "$i"
done
2022-09-08 10:04:17 -04:00
|
|
|
e2epod "k8s.io/kubernetes/test/e2e/framework/pod"
|
2019-07-29 17:00:35 -04:00
|
|
|
e2eservice "k8s.io/kubernetes/test/e2e/framework/service"
|
2021-02-26 15:21:30 -05:00
|
|
|
"k8s.io/kubernetes/test/e2e/network/common"
|
2019-06-06 17:43:13 -04:00
|
|
|
imageutils "k8s.io/kubernetes/test/utils/image"
|
2022-04-04 08:00:06 -04:00
|
|
|
admissionapi "k8s.io/pod-security-admission/api"
|
2019-07-29 17:00:35 -04:00
|
|
|
netutils "k8s.io/utils/net"
|
2019-06-06 17:43:13 -04:00
|
|
|
)
|
|
|
|
|
|
2021-03-12 12:44:35 -05:00
|
|
|
// Tests for ipv4-ipv6 dual-stack feature
|
2023-06-20 04:27:14 -04:00
|
|
|
var _ = common.SIGDescribe(feature.IPv6DualStack, func() {
|
2019-06-06 17:43:13 -04:00
|
|
|
f := framework.NewDefaultFramework("dualstack")
|
2023-05-10 09:38:10 -04:00
|
|
|
f.NamespacePodSecurityLevel = admissionapi.LevelPrivileged
|
2019-06-06 17:43:13 -04:00
|
|
|
|
|
|
|
|
var cs clientset.Interface
|
e2e: adapt to moved code
This is the result of automatically editing source files like this:
go install golang.org/x/tools/cmd/goimports@latest
find ./test/e2e* -name "*.go" | xargs env PATH=$GOPATH/bin:$PATH ./e2e-framework-sed.sh
with e2e-framework-sed.sh containing this:
sed -i \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecCommandInContainer(/e2epod.ExecCommandInContainer(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecCommandInContainerWithFullOutput(/e2epod.ExecCommandInContainerWithFullOutput(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecShellInContainer(/e2epod.ExecShellInContainer(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecShellInPod(/e2epod.ExecShellInPod(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecShellInPodWithFullOutput(/e2epod.ExecShellInPodWithFullOutput(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecWithOptions(/e2epod.ExecWithOptions(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.MatchContainerOutput(/e2eoutput.MatchContainerOutput(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.PodClient(/e2epod.NewPodClient(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.PodClientNS(/e2epod.PodClientNS(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.TestContainerOutput(/e2eoutput.TestContainerOutput(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.TestContainerOutputRegexp(/e2eoutput.TestContainerOutputRegexp(\1, /" \
-e "s/framework.AddOrUpdateLabelOnNode\b/e2enode.AddOrUpdateLabelOnNode/" \
-e "s/framework.AllNodes\b/e2edebug.AllNodes/" \
-e "s/framework.AllNodesReady\b/e2enode.AllNodesReady/" \
-e "s/framework.ContainerResourceGatherer\b/e2edebug.ContainerResourceGatherer/" \
-e "s/framework.ContainerResourceUsage\b/e2edebug.ContainerResourceUsage/" \
-e "s/framework.CreateEmptyFileOnPod\b/e2eoutput.CreateEmptyFileOnPod/" \
-e "s/framework.DefaultPodDeletionTimeout\b/e2epod.DefaultPodDeletionTimeout/" \
-e "s/framework.DumpAllNamespaceInfo\b/e2edebug.DumpAllNamespaceInfo/" \
-e "s/framework.DumpDebugInfo\b/e2eoutput.DumpDebugInfo/" \
-e "s/framework.DumpNodeDebugInfo\b/e2edebug.DumpNodeDebugInfo/" \
-e "s/framework.EtcdUpgrade\b/e2eproviders.EtcdUpgrade/" \
-e "s/framework.EventsLister\b/e2edebug.EventsLister/" \
-e "s/framework.ExecOptions\b/e2epod.ExecOptions/" \
-e "s/framework.ExpectNodeHasLabel\b/e2enode.ExpectNodeHasLabel/" \
-e "s/framework.ExpectNodeHasTaint\b/e2enode.ExpectNodeHasTaint/" \
-e "s/framework.GCEUpgradeScript\b/e2eproviders.GCEUpgradeScript/" \
-e "s/framework.ImagePrePullList\b/e2epod.ImagePrePullList/" \
-e "s/framework.KubectlBuilder\b/e2ekubectl.KubectlBuilder/" \
-e "s/framework.LocationParamGKE\b/e2eproviders.LocationParamGKE/" \
-e "s/framework.LogSizeDataTimeseries\b/e2edebug.LogSizeDataTimeseries/" \
-e "s/framework.LogSizeGatherer\b/e2edebug.LogSizeGatherer/" \
-e "s/framework.LogsSizeData\b/e2edebug.LogsSizeData/" \
-e "s/framework.LogsSizeDataSummary\b/e2edebug.LogsSizeDataSummary/" \
-e "s/framework.LogsSizeVerifier\b/e2edebug.LogsSizeVerifier/" \
-e "s/framework.LookForStringInLog\b/e2eoutput.LookForStringInLog/" \
-e "s/framework.LookForStringInPodExec\b/e2eoutput.LookForStringInPodExec/" \
-e "s/framework.LookForStringInPodExecToContainer\b/e2eoutput.LookForStringInPodExecToContainer/" \
-e "s/framework.MasterAndDNSNodes\b/e2edebug.MasterAndDNSNodes/" \
-e "s/framework.MasterNodes\b/e2edebug.MasterNodes/" \
-e "s/framework.MasterUpgradeGKE\b/e2eproviders.MasterUpgradeGKE/" \
-e "s/framework.NewKubectlCommand\b/e2ekubectl.NewKubectlCommand/" \
-e "s/framework.NewLogsVerifier\b/e2edebug.NewLogsVerifier/" \
-e "s/framework.NewNodeKiller\b/e2enode.NewNodeKiller/" \
-e "s/framework.NewResourceUsageGatherer\b/e2edebug.NewResourceUsageGatherer/" \
-e "s/framework.NodeHasTaint\b/e2enode.NodeHasTaint/" \
-e "s/framework.NodeKiller\b/e2enode.NodeKiller/" \
-e "s/framework.NodesSet\b/e2edebug.NodesSet/" \
-e "s/framework.PodClient\b/e2epod.PodClient/" \
-e "s/framework.RemoveLabelOffNode\b/e2enode.RemoveLabelOffNode/" \
-e "s/framework.ResourceConstraint\b/e2edebug.ResourceConstraint/" \
-e "s/framework.ResourceGathererOptions\b/e2edebug.ResourceGathererOptions/" \
-e "s/framework.ResourceUsagePerContainer\b/e2edebug.ResourceUsagePerContainer/" \
-e "s/framework.ResourceUsageSummary\b/e2edebug.ResourceUsageSummary/" \
-e "s/framework.RunHostCmd\b/e2eoutput.RunHostCmd/" \
-e "s/framework.RunHostCmdOrDie\b/e2eoutput.RunHostCmdOrDie/" \
-e "s/framework.RunHostCmdWithFullOutput\b/e2eoutput.RunHostCmdWithFullOutput/" \
-e "s/framework.RunHostCmdWithRetries\b/e2eoutput.RunHostCmdWithRetries/" \
-e "s/framework.RunKubectl\b/e2ekubectl.RunKubectl/" \
-e "s/framework.RunKubectlInput\b/e2ekubectl.RunKubectlInput/" \
-e "s/framework.RunKubectlOrDie\b/e2ekubectl.RunKubectlOrDie/" \
-e "s/framework.RunKubectlOrDieInput\b/e2ekubectl.RunKubectlOrDieInput/" \
-e "s/framework.RunKubectlWithFullOutput\b/e2ekubectl.RunKubectlWithFullOutput/" \
-e "s/framework.RunKubemciCmd\b/e2ekubectl.RunKubemciCmd/" \
-e "s/framework.RunKubemciWithKubeconfig\b/e2ekubectl.RunKubemciWithKubeconfig/" \
-e "s/framework.SingleContainerSummary\b/e2edebug.SingleContainerSummary/" \
-e "s/framework.SingleLogSummary\b/e2edebug.SingleLogSummary/" \
-e "s/framework.TimestampedSize\b/e2edebug.TimestampedSize/" \
-e "s/framework.WaitForAllNodesSchedulable\b/e2enode.WaitForAllNodesSchedulable/" \
-e "s/framework.WaitForSSHTunnels\b/e2enode.WaitForSSHTunnels/" \
-e "s/framework.WorkItem\b/e2edebug.WorkItem/" \
"$@"
for i in "$@"; do
# Import all sub packages and let goimports figure out which of those
# are redundant (= already imported) or not needed.
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2edebug "k8s.io/kubernetes/test/e2e/framework/debug"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2ekubectl "k8s.io/kubernetes/test/e2e/framework/kubectl"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2enode "k8s.io/kubernetes/test/e2e/framework/node"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2eoutput "k8s.io/kubernetes/test/e2e/framework/pod/output"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2epod "k8s.io/kubernetes/test/e2e/framework/pod"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2eproviders "k8s.io/kubernetes/test/e2e/framework/providers"' "$i"
goimports -w "$i"
done
2022-09-08 10:04:17 -04:00
|
|
|
var podClient *e2epod.PodClient
|
2019-06-06 17:43:13 -04:00
|
|
|
|
|
|
|
|
ginkgo.BeforeEach(func() {
|
|
|
|
|
cs = f.ClientSet
|
e2e: adapt to moved code
This is the result of automatically editing source files like this:
go install golang.org/x/tools/cmd/goimports@latest
find ./test/e2e* -name "*.go" | xargs env PATH=$GOPATH/bin:$PATH ./e2e-framework-sed.sh
with e2e-framework-sed.sh containing this:
sed -i \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecCommandInContainer(/e2epod.ExecCommandInContainer(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecCommandInContainerWithFullOutput(/e2epod.ExecCommandInContainerWithFullOutput(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecShellInContainer(/e2epod.ExecShellInContainer(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecShellInPod(/e2epod.ExecShellInPod(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecShellInPodWithFullOutput(/e2epod.ExecShellInPodWithFullOutput(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecWithOptions(/e2epod.ExecWithOptions(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.MatchContainerOutput(/e2eoutput.MatchContainerOutput(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.PodClient(/e2epod.NewPodClient(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.PodClientNS(/e2epod.PodClientNS(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.TestContainerOutput(/e2eoutput.TestContainerOutput(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.TestContainerOutputRegexp(/e2eoutput.TestContainerOutputRegexp(\1, /" \
-e "s/framework.AddOrUpdateLabelOnNode\b/e2enode.AddOrUpdateLabelOnNode/" \
-e "s/framework.AllNodes\b/e2edebug.AllNodes/" \
-e "s/framework.AllNodesReady\b/e2enode.AllNodesReady/" \
-e "s/framework.ContainerResourceGatherer\b/e2edebug.ContainerResourceGatherer/" \
-e "s/framework.ContainerResourceUsage\b/e2edebug.ContainerResourceUsage/" \
-e "s/framework.CreateEmptyFileOnPod\b/e2eoutput.CreateEmptyFileOnPod/" \
-e "s/framework.DefaultPodDeletionTimeout\b/e2epod.DefaultPodDeletionTimeout/" \
-e "s/framework.DumpAllNamespaceInfo\b/e2edebug.DumpAllNamespaceInfo/" \
-e "s/framework.DumpDebugInfo\b/e2eoutput.DumpDebugInfo/" \
-e "s/framework.DumpNodeDebugInfo\b/e2edebug.DumpNodeDebugInfo/" \
-e "s/framework.EtcdUpgrade\b/e2eproviders.EtcdUpgrade/" \
-e "s/framework.EventsLister\b/e2edebug.EventsLister/" \
-e "s/framework.ExecOptions\b/e2epod.ExecOptions/" \
-e "s/framework.ExpectNodeHasLabel\b/e2enode.ExpectNodeHasLabel/" \
-e "s/framework.ExpectNodeHasTaint\b/e2enode.ExpectNodeHasTaint/" \
-e "s/framework.GCEUpgradeScript\b/e2eproviders.GCEUpgradeScript/" \
-e "s/framework.ImagePrePullList\b/e2epod.ImagePrePullList/" \
-e "s/framework.KubectlBuilder\b/e2ekubectl.KubectlBuilder/" \
-e "s/framework.LocationParamGKE\b/e2eproviders.LocationParamGKE/" \
-e "s/framework.LogSizeDataTimeseries\b/e2edebug.LogSizeDataTimeseries/" \
-e "s/framework.LogSizeGatherer\b/e2edebug.LogSizeGatherer/" \
-e "s/framework.LogsSizeData\b/e2edebug.LogsSizeData/" \
-e "s/framework.LogsSizeDataSummary\b/e2edebug.LogsSizeDataSummary/" \
-e "s/framework.LogsSizeVerifier\b/e2edebug.LogsSizeVerifier/" \
-e "s/framework.LookForStringInLog\b/e2eoutput.LookForStringInLog/" \
-e "s/framework.LookForStringInPodExec\b/e2eoutput.LookForStringInPodExec/" \
-e "s/framework.LookForStringInPodExecToContainer\b/e2eoutput.LookForStringInPodExecToContainer/" \
-e "s/framework.MasterAndDNSNodes\b/e2edebug.MasterAndDNSNodes/" \
-e "s/framework.MasterNodes\b/e2edebug.MasterNodes/" \
-e "s/framework.MasterUpgradeGKE\b/e2eproviders.MasterUpgradeGKE/" \
-e "s/framework.NewKubectlCommand\b/e2ekubectl.NewKubectlCommand/" \
-e "s/framework.NewLogsVerifier\b/e2edebug.NewLogsVerifier/" \
-e "s/framework.NewNodeKiller\b/e2enode.NewNodeKiller/" \
-e "s/framework.NewResourceUsageGatherer\b/e2edebug.NewResourceUsageGatherer/" \
-e "s/framework.NodeHasTaint\b/e2enode.NodeHasTaint/" \
-e "s/framework.NodeKiller\b/e2enode.NodeKiller/" \
-e "s/framework.NodesSet\b/e2edebug.NodesSet/" \
-e "s/framework.PodClient\b/e2epod.PodClient/" \
-e "s/framework.RemoveLabelOffNode\b/e2enode.RemoveLabelOffNode/" \
-e "s/framework.ResourceConstraint\b/e2edebug.ResourceConstraint/" \
-e "s/framework.ResourceGathererOptions\b/e2edebug.ResourceGathererOptions/" \
-e "s/framework.ResourceUsagePerContainer\b/e2edebug.ResourceUsagePerContainer/" \
-e "s/framework.ResourceUsageSummary\b/e2edebug.ResourceUsageSummary/" \
-e "s/framework.RunHostCmd\b/e2eoutput.RunHostCmd/" \
-e "s/framework.RunHostCmdOrDie\b/e2eoutput.RunHostCmdOrDie/" \
-e "s/framework.RunHostCmdWithFullOutput\b/e2eoutput.RunHostCmdWithFullOutput/" \
-e "s/framework.RunHostCmdWithRetries\b/e2eoutput.RunHostCmdWithRetries/" \
-e "s/framework.RunKubectl\b/e2ekubectl.RunKubectl/" \
-e "s/framework.RunKubectlInput\b/e2ekubectl.RunKubectlInput/" \
-e "s/framework.RunKubectlOrDie\b/e2ekubectl.RunKubectlOrDie/" \
-e "s/framework.RunKubectlOrDieInput\b/e2ekubectl.RunKubectlOrDieInput/" \
-e "s/framework.RunKubectlWithFullOutput\b/e2ekubectl.RunKubectlWithFullOutput/" \
-e "s/framework.RunKubemciCmd\b/e2ekubectl.RunKubemciCmd/" \
-e "s/framework.RunKubemciWithKubeconfig\b/e2ekubectl.RunKubemciWithKubeconfig/" \
-e "s/framework.SingleContainerSummary\b/e2edebug.SingleContainerSummary/" \
-e "s/framework.SingleLogSummary\b/e2edebug.SingleLogSummary/" \
-e "s/framework.TimestampedSize\b/e2edebug.TimestampedSize/" \
-e "s/framework.WaitForAllNodesSchedulable\b/e2enode.WaitForAllNodesSchedulable/" \
-e "s/framework.WaitForSSHTunnels\b/e2enode.WaitForSSHTunnels/" \
-e "s/framework.WorkItem\b/e2edebug.WorkItem/" \
"$@"
for i in "$@"; do
# Import all sub packages and let goimports figure out which of those
# are redundant (= already imported) or not needed.
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2edebug "k8s.io/kubernetes/test/e2e/framework/debug"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2ekubectl "k8s.io/kubernetes/test/e2e/framework/kubectl"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2enode "k8s.io/kubernetes/test/e2e/framework/node"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2eoutput "k8s.io/kubernetes/test/e2e/framework/pod/output"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2epod "k8s.io/kubernetes/test/e2e/framework/pod"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2eproviders "k8s.io/kubernetes/test/e2e/framework/providers"' "$i"
goimports -w "$i"
done
2022-09-08 10:04:17 -04:00
|
|
|
podClient = e2epod.NewPodClient(f)
|
2019-06-06 17:43:13 -04:00
|
|
|
})
|
|
|
|
|
|
2026-02-18 12:37:27 -05:00
|
|
|
// A dual-stack cluster should have at least one dual-stack node (though it may
|
|
|
|
|
// also have some single-stack IPv4 or single-stack IPv6 nodes for some use
|
|
|
|
|
// cases).
|
|
|
|
|
ginkgo.It("should have at least one dual-stack node", func(ctx context.Context) {
|
2022-12-12 04:11:10 -05:00
|
|
|
nodeList, err := e2enode.GetReadySchedulableNodes(ctx, cs)
|
2019-09-03 15:00:00 -04:00
|
|
|
framework.ExpectNoError(err)
|
2019-06-06 17:43:13 -04:00
|
|
|
|
2026-02-18 12:37:27 -05:00
|
|
|
var found bool
|
2019-06-06 17:43:13 -04:00
|
|
|
for _, node := range nodeList.Items {
|
2026-02-18 12:37:27 -05:00
|
|
|
ginkgo.By(fmt.Sprintf("examining %s", node.Name))
|
|
|
|
|
var hasIPv4, hasIPv6 bool
|
|
|
|
|
for _, addr := range node.Status.Addresses {
|
|
|
|
|
if addr.Type != v1.NodeInternalIP && addr.Type != v1.NodeExternalIP {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if netutils.IsIPv4String(addr.Address) {
|
|
|
|
|
hasIPv4 = true
|
|
|
|
|
} else if netutils.IsIPv6String(addr.Address) {
|
|
|
|
|
hasIPv6 = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if hasIPv4 && hasIPv6 {
|
|
|
|
|
found = true
|
|
|
|
|
break
|
2021-12-08 01:07:56 -05:00
|
|
|
}
|
2019-06-06 17:43:13 -04:00
|
|
|
}
|
2026-02-18 12:37:27 -05:00
|
|
|
|
|
|
|
|
if !found {
|
|
|
|
|
framework.Failf("Could not find any schedulable node with both an IPv4 IP and an IPv6 IP")
|
|
|
|
|
}
|
2019-06-06 17:43:13 -04:00
|
|
|
})
|
|
|
|
|
|
2022-10-17 08:47:15 -04:00
|
|
|
ginkgo.It("should create pod, add ipv6 and ipv4 ip to pod ips", func(ctx context.Context) {
|
2019-06-06 17:43:13 -04:00
|
|
|
podName := "pod-dualstack-ips"
|
|
|
|
|
|
|
|
|
|
pod := &v1.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: podName,
|
|
|
|
|
Labels: map[string]string{"test": "dualstack-pod-ips"},
|
|
|
|
|
},
|
|
|
|
|
Spec: v1.PodSpec{
|
|
|
|
|
Containers: []v1.Container{
|
|
|
|
|
{
|
|
|
|
|
Name: "dualstack-pod-ips",
|
2020-11-10 16:44:06 -05:00
|
|
|
Image: imageutils.GetE2EImage(imageutils.Agnhost),
|
2019-06-06 17:43:13 -04:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ginkgo.By("submitting the pod to kubernetes")
|
2022-12-12 04:11:10 -05:00
|
|
|
p := podClient.CreateSync(ctx, pod)
|
2019-06-06 17:43:13 -04:00
|
|
|
|
|
|
|
|
gomega.Expect(p.Status.PodIP).ShouldNot(gomega.BeEquivalentTo(""))
|
|
|
|
|
gomega.Expect(p.Status.PodIPs).ShouldNot(gomega.BeNil())
|
|
|
|
|
|
|
|
|
|
// validate there are 2 ips in podIPs
|
2023-07-21 04:22:31 -04:00
|
|
|
gomega.Expect(p.Status.PodIPs).To(gomega.HaveLen(2))
|
2019-06-06 17:43:13 -04:00
|
|
|
// validate first ip in PodIPs is same as PodIP
|
2023-07-21 04:22:31 -04:00
|
|
|
gomega.Expect(p.Status.PodIP).To(gomega.Equal(p.Status.PodIPs[0].IP))
|
2019-06-06 17:43:13 -04:00
|
|
|
// assert 2 pod ips belong to different families
|
2021-12-08 01:07:56 -05:00
|
|
|
if netutils.IsIPv4String(p.Status.PodIPs[0].IP) == netutils.IsIPv4String(p.Status.PodIPs[1].IP) {
|
|
|
|
|
framework.Failf("both internalIPs %s and %s belong to the same families", p.Status.PodIPs[0].IP, p.Status.PodIPs[1].IP)
|
|
|
|
|
}
|
2019-06-06 17:43:13 -04:00
|
|
|
|
|
|
|
|
ginkgo.By("deleting the pod")
|
2022-12-12 04:11:10 -05:00
|
|
|
err := podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(30))
|
2019-06-06 17:43:13 -04:00
|
|
|
framework.ExpectNoError(err, "failed to delete pod")
|
|
|
|
|
})
|
|
|
|
|
|
2024-01-19 06:32:04 -05:00
|
|
|
f.It("should create pod, add ipv6 and ipv4 ip to host ips", func(ctx context.Context) {
|
2023-10-24 10:01:21 -04:00
|
|
|
podName := "pod-dualstack-ips"
|
|
|
|
|
|
|
|
|
|
pod := &v1.Pod{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: podName,
|
|
|
|
|
Labels: map[string]string{"test": "dualstack-host-ips"},
|
|
|
|
|
},
|
|
|
|
|
Spec: v1.PodSpec{
|
|
|
|
|
Containers: []v1.Container{
|
|
|
|
|
{
|
|
|
|
|
Name: "dualstack-host-ips",
|
|
|
|
|
Image: imageutils.GetE2EImage(imageutils.Agnhost),
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ginkgo.By("submitting the pod to kubernetes")
|
|
|
|
|
p := podClient.CreateSync(ctx, pod)
|
|
|
|
|
|
|
|
|
|
gomega.Expect(p.Status.HostIP).ShouldNot(gomega.BeEquivalentTo(""))
|
|
|
|
|
gomega.Expect(p.Status.HostIPs).ShouldNot(gomega.BeNil())
|
|
|
|
|
|
|
|
|
|
// validate there are 2 ips in hostIPs
|
|
|
|
|
gomega.Expect(p.Status.HostIPs).To(gomega.HaveLen(2))
|
|
|
|
|
// validate first ip in hostIPs is same as HostIP
|
|
|
|
|
gomega.Expect(p.Status.HostIP).To(gomega.Equal(p.Status.HostIPs[0].IP))
|
|
|
|
|
// assert 2 host ips belong to different families
|
|
|
|
|
if netutils.IsIPv4String(p.Status.HostIPs[0].IP) == netutils.IsIPv4String(p.Status.HostIPs[1].IP) {
|
|
|
|
|
framework.Failf("both internalIPs %s and %s belong to the same families", p.Status.HostIPs[0], p.Status.HostIPs[1])
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ginkgo.By("deleting the pod")
|
|
|
|
|
err := podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(30))
|
|
|
|
|
framework.ExpectNoError(err, "failed to delete pod")
|
|
|
|
|
})
|
|
|
|
|
|
2019-06-06 17:43:13 -04:00
|
|
|
// takes close to 140s to complete, so doesn't need to be marked [SLOW]
|
2022-10-17 08:47:15 -04:00
|
|
|
ginkgo.It("should be able to reach pod on ipv4 and ipv6 ip", func(ctx context.Context) {
|
2019-06-06 17:43:13 -04:00
|
|
|
serverDeploymentName := "dualstack-server"
|
|
|
|
|
clientDeploymentName := "dualstack-client"
|
|
|
|
|
|
|
|
|
|
// get all schedulable nodes to determine the number of replicas for pods
|
|
|
|
|
// this is to ensure connectivity from all nodes on cluster
|
2023-08-18 08:39:33 -04:00
|
|
|
nodeList, err := e2enode.GetBoundedReadySchedulableNodes(ctx, cs, 3)
|
2019-09-03 15:00:00 -04:00
|
|
|
framework.ExpectNoError(err)
|
2019-06-06 17:43:13 -04:00
|
|
|
|
|
|
|
|
replicas := int32(len(nodeList.Items))
|
|
|
|
|
|
2020-03-24 21:57:32 -04:00
|
|
|
serverDeploymentSpec := e2edeployment.NewDeployment(serverDeploymentName,
|
2019-07-10 18:14:39 -04:00
|
|
|
replicas,
|
|
|
|
|
map[string]string{"test": "dual-stack-server"},
|
|
|
|
|
"dualstack-test-server",
|
2019-05-14 00:04:14 -04:00
|
|
|
imageutils.GetE2EImage(imageutils.Agnhost),
|
2019-08-26 08:56:38 -04:00
|
|
|
appsv1.RollingUpdateDeploymentStrategyType)
|
2019-05-14 00:04:14 -04:00
|
|
|
serverDeploymentSpec.Spec.Template.Spec.Containers[0].Args = []string{"test-webserver"}
|
2019-07-10 18:14:39 -04:00
|
|
|
|
2019-06-06 17:43:13 -04:00
|
|
|
// to ensure all the pods land on different nodes and we can thereby
|
|
|
|
|
// validate connectivity across all nodes.
|
2019-07-10 18:14:39 -04:00
|
|
|
serverDeploymentSpec.Spec.Template.Spec.Affinity = &v1.Affinity{
|
|
|
|
|
PodAntiAffinity: &v1.PodAntiAffinity{
|
|
|
|
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
|
|
|
|
{
|
|
|
|
|
LabelSelector: &metav1.LabelSelector{
|
|
|
|
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
|
|
|
|
{
|
|
|
|
|
Key: "test",
|
|
|
|
|
Operator: metav1.LabelSelectorOpIn,
|
|
|
|
|
Values: []string{"dualstack-test-server"},
|
2019-06-06 17:43:13 -04:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
2019-07-10 18:14:39 -04:00
|
|
|
TopologyKey: "kubernetes.io/hostname",
|
2019-06-06 17:43:13 -04:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
2020-03-24 21:57:32 -04:00
|
|
|
clientDeploymentSpec := e2edeployment.NewDeployment(clientDeploymentName,
|
2019-07-10 18:14:39 -04:00
|
|
|
replicas,
|
|
|
|
|
map[string]string{"test": "dual-stack-client"},
|
|
|
|
|
"dualstack-test-client",
|
|
|
|
|
imageutils.GetE2EImage(imageutils.Agnhost),
|
2019-08-26 08:56:38 -04:00
|
|
|
appsv1.RollingUpdateDeploymentStrategyType)
|
2019-07-10 18:14:39 -04:00
|
|
|
|
|
|
|
|
clientDeploymentSpec.Spec.Template.Spec.Containers[0].Command = []string{"sleep", "3600"}
|
|
|
|
|
clientDeploymentSpec.Spec.Template.Spec.Affinity = &v1.Affinity{
|
|
|
|
|
PodAntiAffinity: &v1.PodAntiAffinity{
|
|
|
|
|
RequiredDuringSchedulingIgnoredDuringExecution: []v1.PodAffinityTerm{
|
|
|
|
|
{
|
|
|
|
|
LabelSelector: &metav1.LabelSelector{
|
|
|
|
|
MatchExpressions: []metav1.LabelSelectorRequirement{
|
|
|
|
|
{
|
|
|
|
|
Key: "test",
|
|
|
|
|
Operator: metav1.LabelSelectorOpIn,
|
|
|
|
|
Values: []string{"dualstack-test-client"},
|
2019-06-06 17:43:13 -04:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
2019-07-10 18:14:39 -04:00
|
|
|
TopologyKey: "kubernetes.io/hostname",
|
2019-06-06 17:43:13 -04:00
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-12 04:11:10 -05:00
|
|
|
serverDeployment, err := cs.AppsV1().Deployments(f.Namespace.Name).Create(ctx, serverDeploymentSpec, metav1.CreateOptions{})
|
2019-06-06 17:43:13 -04:00
|
|
|
framework.ExpectNoError(err)
|
|
|
|
|
|
2022-12-12 04:11:10 -05:00
|
|
|
clientDeployment, err := cs.AppsV1().Deployments(f.Namespace.Name).Create(ctx, clientDeploymentSpec, metav1.CreateOptions{})
|
2019-06-06 17:43:13 -04:00
|
|
|
framework.ExpectNoError(err)
|
|
|
|
|
|
2020-03-24 21:57:32 -04:00
|
|
|
err = e2edeployment.WaitForDeploymentComplete(cs, serverDeployment)
|
2019-06-06 17:43:13 -04:00
|
|
|
framework.ExpectNoError(err)
|
2020-03-24 21:57:32 -04:00
|
|
|
err = e2edeployment.WaitForDeploymentComplete(cs, clientDeployment)
|
2019-06-06 17:43:13 -04:00
|
|
|
framework.ExpectNoError(err)
|
|
|
|
|
|
2022-12-12 04:11:10 -05:00
|
|
|
serverPods, err := e2edeployment.GetPodsForDeployment(ctx, cs, serverDeployment)
|
2019-06-06 17:43:13 -04:00
|
|
|
framework.ExpectNoError(err)
|
|
|
|
|
|
2022-12-12 04:11:10 -05:00
|
|
|
clientPods, err := e2edeployment.GetPodsForDeployment(ctx, cs, clientDeployment)
|
2019-06-06 17:43:13 -04:00
|
|
|
framework.ExpectNoError(err)
|
|
|
|
|
|
2022-12-12 04:11:10 -05:00
|
|
|
assertNetworkConnectivity(ctx, f, *serverPods, *clientPods, "dualstack-test-client", "80")
|
2019-06-06 17:43:13 -04:00
|
|
|
})
|
2019-07-29 17:00:35 -04:00
|
|
|
|
2022-10-17 08:47:15 -04:00
|
|
|
ginkgo.It("should create a single stack service with cluster ip from primary service range", func(ctx context.Context) {
|
2019-07-29 17:00:35 -04:00
|
|
|
serviceName := "defaultclusterip"
|
|
|
|
|
ns := f.Namespace.Name
|
2019-07-31 17:40:00 -04:00
|
|
|
jig := e2eservice.NewTestJig(cs, ns, serviceName)
|
2019-07-29 17:00:35 -04:00
|
|
|
|
2019-12-11 07:13:34 -05:00
|
|
|
t := NewServerTest(cs, ns, serviceName)
|
2019-07-29 17:00:35 -04:00
|
|
|
defer func() {
|
|
|
|
|
defer ginkgo.GinkgoRecover()
|
|
|
|
|
if errs := t.Cleanup(); len(errs) != 0 {
|
|
|
|
|
framework.Failf("errors in cleanup: %v", errs)
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
|
|
|
ginkgo.By("creating service " + ns + "/" + serviceName + " with Service.Spec.IPFamilies not set nil policy")
|
|
|
|
|
service := createService(t.ServiceName, t.Namespace, t.Labels, nil, nil)
|
2019-07-29 17:00:35 -04:00
|
|
|
|
|
|
|
|
jig.Labels = t.Labels
|
2022-12-12 04:11:10 -05:00
|
|
|
err := jig.CreateServicePods(ctx, 2)
|
2019-07-31 17:40:00 -04:00
|
|
|
framework.ExpectNoError(err)
|
2019-07-29 17:00:35 -04:00
|
|
|
svc, err := t.CreateService(service)
|
|
|
|
|
framework.ExpectNoError(err, "failed to create service: %s in namespace: %s", serviceName, ns)
|
|
|
|
|
|
|
|
|
|
validateNumOfServicePorts(svc, 2)
|
|
|
|
|
|
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
|
|
|
expectedPolicy := v1.IPFamilyPolicySingleStack
|
|
|
|
|
expectedFamilies := []v1.IPFamily{v1.IPv4Protocol}
|
|
|
|
|
if framework.TestContext.ClusterIsIPv6() {
|
|
|
|
|
expectedFamilies = []v1.IPFamily{v1.IPv6Protocol}
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-29 17:00:35 -04:00
|
|
|
// check the spec has been set to default ip family
|
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
|
|
|
validateServiceAndClusterIPFamily(svc, expectedFamilies, &expectedPolicy)
|
2019-07-29 17:00:35 -04:00
|
|
|
|
|
|
|
|
// ensure endpoint belong to same ipfamily as service
|
2025-06-10 09:51:15 -04:00
|
|
|
validateEndpointSlices(ctx, f, svc, expectedFamilies)
|
2019-07-29 17:00:35 -04:00
|
|
|
})
|
|
|
|
|
|
2022-10-17 08:47:15 -04:00
|
|
|
ginkgo.It("should create service with ipv4 cluster ip", func(ctx context.Context) {
|
2019-07-29 17:00:35 -04:00
|
|
|
serviceName := "ipv4clusterip"
|
|
|
|
|
ns := f.Namespace.Name
|
|
|
|
|
|
2019-07-31 17:40:00 -04:00
|
|
|
jig := e2eservice.NewTestJig(cs, ns, serviceName)
|
2019-07-29 17:00:35 -04:00
|
|
|
|
2019-12-11 07:13:34 -05:00
|
|
|
t := NewServerTest(cs, ns, serviceName)
|
2019-07-29 17:00:35 -04:00
|
|
|
defer func() {
|
|
|
|
|
defer ginkgo.GinkgoRecover()
|
|
|
|
|
if errs := t.Cleanup(); len(errs) != 0 {
|
|
|
|
|
framework.Failf("errors in cleanup: %v", errs)
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
ginkgo.By("creating service " + ns + "/" + serviceName + " with Service.Spec.IPFamily IPv4" + ns)
|
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
|
|
|
|
|
|
|
|
expectedPolicy := v1.IPFamilyPolicySingleStack
|
|
|
|
|
expectedFamilies := []v1.IPFamily{v1.IPv4Protocol}
|
|
|
|
|
|
|
|
|
|
service := createService(t.ServiceName, t.Namespace, t.Labels, nil, expectedFamilies)
|
2019-07-29 17:00:35 -04:00
|
|
|
|
|
|
|
|
jig.Labels = t.Labels
|
2022-12-12 04:11:10 -05:00
|
|
|
err := jig.CreateServicePods(ctx, 2)
|
2019-07-31 17:40:00 -04:00
|
|
|
framework.ExpectNoError(err)
|
2019-07-29 17:00:35 -04:00
|
|
|
svc, err := t.CreateService(service)
|
|
|
|
|
framework.ExpectNoError(err, "failed to create service: %s in namespace: %s", serviceName, ns)
|
|
|
|
|
|
|
|
|
|
validateNumOfServicePorts(svc, 2)
|
|
|
|
|
|
|
|
|
|
// check the spec has been set to IPv4 and cluster ip belong to IPv4 family
|
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
|
|
|
validateServiceAndClusterIPFamily(svc, expectedFamilies, &expectedPolicy)
|
2019-07-29 17:00:35 -04:00
|
|
|
|
|
|
|
|
// ensure endpoints belong to same ipfamily as service
|
2025-06-10 09:51:15 -04:00
|
|
|
validateEndpointSlices(ctx, f, svc, expectedFamilies)
|
2019-07-29 17:00:35 -04:00
|
|
|
})
|
|
|
|
|
|
2022-10-17 08:47:15 -04:00
|
|
|
ginkgo.It("should create service with ipv6 cluster ip", func(ctx context.Context) {
|
2019-07-29 17:00:35 -04:00
|
|
|
serviceName := "ipv6clusterip"
|
|
|
|
|
ns := f.Namespace.Name
|
|
|
|
|
|
2019-07-31 17:40:00 -04:00
|
|
|
jig := e2eservice.NewTestJig(cs, ns, serviceName)
|
2019-07-29 17:00:35 -04:00
|
|
|
|
2019-12-11 07:13:34 -05:00
|
|
|
t := NewServerTest(cs, ns, serviceName)
|
2019-07-29 17:00:35 -04:00
|
|
|
defer func() {
|
|
|
|
|
defer ginkgo.GinkgoRecover()
|
|
|
|
|
if errs := t.Cleanup(); len(errs) != 0 {
|
|
|
|
|
framework.Failf("errors in cleanup: %v", errs)
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
ginkgo.By("creating service " + ns + "/" + serviceName + " with Service.Spec.IPFamily IPv6" + ns)
|
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
|
|
|
expectedPolicy := v1.IPFamilyPolicySingleStack
|
|
|
|
|
expectedFamilies := []v1.IPFamily{v1.IPv6Protocol}
|
|
|
|
|
|
|
|
|
|
service := createService(t.ServiceName, t.Namespace, t.Labels, nil, expectedFamilies)
|
2019-07-29 17:00:35 -04:00
|
|
|
|
|
|
|
|
jig.Labels = t.Labels
|
2022-12-12 04:11:10 -05:00
|
|
|
err := jig.CreateServicePods(ctx, 2)
|
2019-07-31 17:40:00 -04:00
|
|
|
framework.ExpectNoError(err)
|
2019-07-29 17:00:35 -04:00
|
|
|
svc, err := t.CreateService(service)
|
|
|
|
|
framework.ExpectNoError(err, "failed to create service: %s in namespace: %s", serviceName, ns)
|
|
|
|
|
|
|
|
|
|
validateNumOfServicePorts(svc, 2)
|
|
|
|
|
|
|
|
|
|
// check the spec has been set to IPv6 and cluster ip belongs to IPv6 family
|
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
|
|
|
validateServiceAndClusterIPFamily(svc, expectedFamilies, &expectedPolicy)
|
2019-07-29 17:00:35 -04:00
|
|
|
|
|
|
|
|
// ensure endpoints belong to same ipfamily as service
|
2025-06-10 09:51:15 -04:00
|
|
|
validateEndpointSlices(ctx, f, svc, expectedFamilies)
|
2019-07-29 17:00:35 -04:00
|
|
|
})
|
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
|
|
|
|
2022-10-17 08:47:15 -04:00
|
|
|
ginkgo.It("should create service with ipv4,v6 cluster ip", func(ctx context.Context) {
|
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
|
|
|
serviceName := "ipv4ipv6clusterip"
|
|
|
|
|
ns := f.Namespace.Name
|
|
|
|
|
|
|
|
|
|
jig := e2eservice.NewTestJig(cs, ns, serviceName)
|
|
|
|
|
|
|
|
|
|
t := NewServerTest(cs, ns, serviceName)
|
|
|
|
|
defer func() {
|
|
|
|
|
defer ginkgo.GinkgoRecover()
|
|
|
|
|
if errs := t.Cleanup(); len(errs) != 0 {
|
|
|
|
|
framework.Failf("errors in cleanup: %v", errs)
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
ginkgo.By("creating service " + ns + "/" + serviceName + " with Service.Spec.IPFamily IPv4, IPv6" + ns)
|
|
|
|
|
|
|
|
|
|
expectedPolicy := v1.IPFamilyPolicyRequireDualStack
|
|
|
|
|
expectedFamilies := []v1.IPFamily{v1.IPv4Protocol, v1.IPv6Protocol}
|
|
|
|
|
|
2021-08-18 20:05:07 -04:00
|
|
|
service := createService(t.ServiceName, t.Namespace, t.Labels, &expectedPolicy, expectedFamilies)
|
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
|
|
|
|
|
|
|
|
jig.Labels = t.Labels
|
2022-12-12 04:11:10 -05:00
|
|
|
err := jig.CreateServicePods(ctx, 2)
|
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
|
|
|
framework.ExpectNoError(err)
|
|
|
|
|
svc, err := t.CreateService(service)
|
|
|
|
|
framework.ExpectNoError(err, "failed to create service: %s in namespace: %s", serviceName, ns)
|
|
|
|
|
|
|
|
|
|
validateNumOfServicePorts(svc, 2)
|
|
|
|
|
|
|
|
|
|
// check the spec has been set to IPv4 and cluster ip belong to IPv4 family
|
|
|
|
|
validateServiceAndClusterIPFamily(svc, expectedFamilies, &expectedPolicy)
|
|
|
|
|
|
|
|
|
|
// ensure endpoints belong to same ipfamily as service
|
2025-06-10 09:51:15 -04:00
|
|
|
validateEndpointSlices(ctx, f, svc, expectedFamilies)
|
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
|
|
|
})
|
|
|
|
|
|
2022-10-17 08:47:15 -04:00
|
|
|
ginkgo.It("should create service with ipv6,v4 cluster ip", func(ctx context.Context) {
|
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
|
|
|
serviceName := "ipv6ipv4clusterip"
|
|
|
|
|
ns := f.Namespace.Name
|
|
|
|
|
|
|
|
|
|
jig := e2eservice.NewTestJig(cs, ns, serviceName)
|
|
|
|
|
|
|
|
|
|
t := NewServerTest(cs, ns, serviceName)
|
|
|
|
|
defer func() {
|
|
|
|
|
defer ginkgo.GinkgoRecover()
|
|
|
|
|
if errs := t.Cleanup(); len(errs) != 0 {
|
|
|
|
|
framework.Failf("errors in cleanup: %v", errs)
|
|
|
|
|
}
|
|
|
|
|
}()
|
|
|
|
|
|
|
|
|
|
ginkgo.By("creating service " + ns + "/" + serviceName + " with Service.Spec.IPFamily IPv4, IPv6" + ns)
|
|
|
|
|
|
|
|
|
|
expectedPolicy := v1.IPFamilyPolicyRequireDualStack
|
|
|
|
|
expectedFamilies := []v1.IPFamily{v1.IPv6Protocol, v1.IPv4Protocol}
|
|
|
|
|
|
2021-08-18 20:05:07 -04:00
|
|
|
service := createService(t.ServiceName, t.Namespace, t.Labels, &expectedPolicy, expectedFamilies)
|
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
|
|
|
|
|
|
|
|
jig.Labels = t.Labels
|
2022-12-12 04:11:10 -05:00
|
|
|
err := jig.CreateServicePods(ctx, 2)
|
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
|
|
|
framework.ExpectNoError(err)
|
|
|
|
|
svc, err := t.CreateService(service)
|
|
|
|
|
framework.ExpectNoError(err, "failed to create service: %s in namespace: %s", serviceName, ns)
|
|
|
|
|
|
|
|
|
|
validateNumOfServicePorts(svc, 2)
|
|
|
|
|
|
|
|
|
|
// check the spec has been set to IPv4 and cluster ip belong to IPv4 family
|
|
|
|
|
validateServiceAndClusterIPFamily(svc, expectedFamilies, &expectedPolicy)
|
|
|
|
|
|
|
|
|
|
// ensure endpoints belong to same ipfamily as service
|
2025-06-10 09:51:15 -04:00
|
|
|
validateEndpointSlices(ctx, f, svc, expectedFamilies)
|
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
|
|
|
})
|
2020-11-11 17:04:33 -05:00
|
|
|
|
|
|
|
|
// Service Granular Checks as in k8s.io/kubernetes/test/e2e/network/networking.go
|
|
|
|
|
// but using the secondary IP, so we run the same tests for each ClusterIP family
|
2021-05-19 17:54:06 -04:00
|
|
|
ginkgo.Describe("Granular Checks: Services Secondary IP Family [LinuxOnly]", func() {
|
2020-11-11 17:04:33 -05:00
|
|
|
|
2022-10-17 08:47:15 -04:00
|
|
|
ginkgo.It("should function for pod-Service: http", func(ctx context.Context) {
|
2022-12-12 04:11:10 -05:00
|
|
|
config := e2enetwork.NewNetworkingTestConfig(ctx, f, e2enetwork.EnableDualStack)
|
2020-11-11 17:04:33 -05:00
|
|
|
ginkgo.By(fmt.Sprintf("dialing(http) %v --> %v:%v (config.clusterIP)", config.TestContainerPod.Name, config.SecondaryClusterIP, e2enetwork.ClusterHTTPPort))
|
2022-12-12 04:11:10 -05:00
|
|
|
err := config.DialFromTestContainer(ctx, "http", config.SecondaryClusterIP, e2enetwork.ClusterHTTPPort, config.MaxTries, 0, config.EndpointHostnames())
|
2021-02-01 04:14:33 -05:00
|
|
|
if err != nil {
|
|
|
|
|
framework.Failf("failed dialing endpoint, %v", err)
|
|
|
|
|
}
|
2020-11-11 17:04:33 -05:00
|
|
|
ginkgo.By(fmt.Sprintf("dialing(http) %v --> %v:%v (nodeIP)", config.TestContainerPod.Name, config.SecondaryNodeIP, config.NodeHTTPPort))
|
2022-12-12 04:11:10 -05:00
|
|
|
err = config.DialFromTestContainer(ctx, "http", config.SecondaryNodeIP, config.NodeHTTPPort, config.MaxTries, 0, config.EndpointHostnames())
|
2021-02-01 04:14:33 -05:00
|
|
|
if err != nil {
|
|
|
|
|
framework.Failf("failed dialing endpoint, %v", err)
|
|
|
|
|
}
|
2020-11-11 17:04:33 -05:00
|
|
|
})
|
|
|
|
|
|
2022-10-17 08:47:15 -04:00
|
|
|
ginkgo.It("should function for pod-Service: udp", func(ctx context.Context) {
|
2022-12-12 04:11:10 -05:00
|
|
|
config := e2enetwork.NewNetworkingTestConfig(ctx, f, e2enetwork.EnableDualStack)
|
2020-11-11 17:04:33 -05:00
|
|
|
ginkgo.By(fmt.Sprintf("dialing(udp) %v --> %v:%v (config.clusterIP)", config.TestContainerPod.Name, config.SecondaryClusterIP, e2enetwork.ClusterUDPPort))
|
2022-12-12 04:11:10 -05:00
|
|
|
err := config.DialFromTestContainer(ctx, "udp", config.SecondaryClusterIP, e2enetwork.ClusterUDPPort, config.MaxTries, 0, config.EndpointHostnames())
|
2021-02-01 04:14:33 -05:00
|
|
|
if err != nil {
|
|
|
|
|
framework.Failf("failed dialing endpoint, %v", err)
|
|
|
|
|
}
|
2020-11-11 17:04:33 -05:00
|
|
|
ginkgo.By(fmt.Sprintf("dialing(udp) %v --> %v:%v (nodeIP)", config.TestContainerPod.Name, config.SecondaryNodeIP, config.NodeUDPPort))
|
2022-12-12 04:11:10 -05:00
|
|
|
err = config.DialFromTestContainer(ctx, "udp", config.SecondaryNodeIP, config.NodeUDPPort, config.MaxTries, 0, config.EndpointHostnames())
|
2021-02-01 04:14:33 -05:00
|
|
|
if err != nil {
|
|
|
|
|
framework.Failf("failed dialing endpoint, %v", err)
|
|
|
|
|
}
|
2020-11-11 17:04:33 -05:00
|
|
|
})
|
|
|
|
|
|
2023-06-20 04:27:14 -04:00
|
|
|
f.It("should function for pod-Service: sctp", feature.SCTPConnectivity, func(ctx context.Context) {
|
2022-12-12 04:11:10 -05:00
|
|
|
config := e2enetwork.NewNetworkingTestConfig(ctx, f, e2enetwork.EnableDualStack, e2enetwork.EnableSCTP)
|
2020-11-11 17:04:33 -05:00
|
|
|
ginkgo.By(fmt.Sprintf("dialing(sctp) %v --> %v:%v (config.clusterIP)", config.TestContainerPod.Name, config.SecondaryClusterIP, e2enetwork.ClusterSCTPPort))
|
2022-12-12 04:11:10 -05:00
|
|
|
err := config.DialFromTestContainer(ctx, "sctp", config.SecondaryClusterIP, e2enetwork.ClusterSCTPPort, config.MaxTries, 0, config.EndpointHostnames())
|
2021-02-01 04:14:33 -05:00
|
|
|
if err != nil {
|
|
|
|
|
framework.Failf("failed dialing endpoint, %v", err)
|
|
|
|
|
}
|
2020-11-11 17:04:33 -05:00
|
|
|
|
|
|
|
|
ginkgo.By(fmt.Sprintf("dialing(sctp) %v --> %v:%v (nodeIP)", config.TestContainerPod.Name, config.SecondaryNodeIP, config.NodeSCTPPort))
|
2022-12-12 04:11:10 -05:00
|
|
|
err = config.DialFromTestContainer(ctx, "sctp", config.SecondaryNodeIP, config.NodeSCTPPort, config.MaxTries, 0, config.EndpointHostnames())
|
2021-02-01 04:14:33 -05:00
|
|
|
if err != nil {
|
|
|
|
|
framework.Failf("failed dialing endpoint, %v", err)
|
|
|
|
|
}
|
2020-11-11 17:04:33 -05:00
|
|
|
})
|
|
|
|
|
|
2022-10-17 08:47:15 -04:00
|
|
|
ginkgo.It("should function for node-Service: http", func(ctx context.Context) {
|
2022-12-12 04:11:10 -05:00
|
|
|
config := e2enetwork.NewNetworkingTestConfig(ctx, f, e2enetwork.EnableDualStack, e2enetwork.UseHostNetwork)
|
2020-11-11 17:04:33 -05:00
|
|
|
ginkgo.By(fmt.Sprintf("dialing(http) %v (node) --> %v:%v (config.clusterIP)", config.SecondaryNodeIP, config.SecondaryClusterIP, e2enetwork.ClusterHTTPPort))
|
2022-12-12 04:11:10 -05:00
|
|
|
err := config.DialFromNode(ctx, "http", config.SecondaryClusterIP, e2enetwork.ClusterHTTPPort, config.MaxTries, 0, config.EndpointHostnames())
|
2021-02-01 04:14:33 -05:00
|
|
|
if err != nil {
|
|
|
|
|
framework.Failf("failed dialing endpoint, %v", err)
|
|
|
|
|
}
|
2020-11-11 17:04:33 -05:00
|
|
|
|
|
|
|
|
ginkgo.By(fmt.Sprintf("dialing(http) %v (node) --> %v:%v (nodeIP)", config.SecondaryNodeIP, config.SecondaryNodeIP, config.NodeHTTPPort))
|
2022-12-12 04:11:10 -05:00
|
|
|
err = config.DialFromNode(ctx, "http", config.SecondaryNodeIP, config.NodeHTTPPort, config.MaxTries, 0, config.EndpointHostnames())
|
2021-02-01 04:14:33 -05:00
|
|
|
if err != nil {
|
|
|
|
|
framework.Failf("failed dialing endpoint, %v", err)
|
|
|
|
|
}
|
2020-11-11 17:04:33 -05:00
|
|
|
})
|
|
|
|
|
|
2022-10-17 08:47:15 -04:00
|
|
|
ginkgo.It("should function for node-Service: udp", func(ctx context.Context) {
|
2022-12-12 04:11:10 -05:00
|
|
|
config := e2enetwork.NewNetworkingTestConfig(ctx, f, e2enetwork.EnableDualStack, e2enetwork.UseHostNetwork)
|
2020-11-11 17:04:33 -05:00
|
|
|
ginkgo.By(fmt.Sprintf("dialing(udp) %v (node) --> %v:%v (config.clusterIP)", config.SecondaryNodeIP, config.SecondaryClusterIP, e2enetwork.ClusterUDPPort))
|
2022-12-12 04:11:10 -05:00
|
|
|
err := config.DialFromNode(ctx, "udp", config.SecondaryClusterIP, e2enetwork.ClusterUDPPort, config.MaxTries, 0, config.EndpointHostnames())
|
2021-02-01 04:14:33 -05:00
|
|
|
if err != nil {
|
|
|
|
|
framework.Failf("failed dialing endpoint, %v", err)
|
|
|
|
|
}
|
2020-11-11 17:04:33 -05:00
|
|
|
|
|
|
|
|
ginkgo.By(fmt.Sprintf("dialing(udp) %v (node) --> %v:%v (nodeIP)", config.SecondaryNodeIP, config.SecondaryNodeIP, config.NodeUDPPort))
|
2022-12-12 04:11:10 -05:00
|
|
|
err = config.DialFromNode(ctx, "udp", config.SecondaryNodeIP, config.NodeUDPPort, config.MaxTries, 0, config.EndpointHostnames())
|
2021-02-01 04:14:33 -05:00
|
|
|
if err != nil {
|
|
|
|
|
framework.Failf("failed dialing endpoint, %v", err)
|
|
|
|
|
}
|
2020-11-11 17:04:33 -05:00
|
|
|
})
|
|
|
|
|
|
2022-10-17 08:47:15 -04:00
|
|
|
ginkgo.It("should function for endpoint-Service: http", func(ctx context.Context) {
|
2022-12-12 04:11:10 -05:00
|
|
|
config := e2enetwork.NewNetworkingTestConfig(ctx, f, e2enetwork.EnableDualStack)
|
2020-11-11 17:04:33 -05:00
|
|
|
ginkgo.By(fmt.Sprintf("dialing(http) %v (endpoint) --> %v:%v (config.clusterIP)", config.EndpointPods[0].Name, config.SecondaryClusterIP, e2enetwork.ClusterHTTPPort))
|
2022-12-12 04:11:10 -05:00
|
|
|
err := config.DialFromEndpointContainer(ctx, "http", config.SecondaryClusterIP, e2enetwork.ClusterHTTPPort, config.MaxTries, 0, config.EndpointHostnames())
|
2021-02-01 04:14:33 -05:00
|
|
|
if err != nil {
|
|
|
|
|
framework.Failf("failed dialing endpoint, %v", err)
|
|
|
|
|
}
|
2020-11-11 17:04:33 -05:00
|
|
|
ginkgo.By(fmt.Sprintf("dialing(http) %v (endpoint) --> %v:%v (nodeIP)", config.EndpointPods[0].Name, config.SecondaryNodeIP, config.NodeHTTPPort))
|
2022-12-12 04:11:10 -05:00
|
|
|
err = config.DialFromEndpointContainer(ctx, "http", config.SecondaryNodeIP, config.NodeHTTPPort, config.MaxTries, 0, config.EndpointHostnames())
|
2021-02-01 04:14:33 -05:00
|
|
|
if err != nil {
|
|
|
|
|
framework.Failf("failed dialing endpoint, %v", err)
|
|
|
|
|
}
|
2020-11-11 17:04:33 -05:00
|
|
|
})
|
|
|
|
|
|
2022-10-17 08:47:15 -04:00
|
|
|
ginkgo.It("should function for endpoint-Service: udp", func(ctx context.Context) {
|
2022-12-12 04:11:10 -05:00
|
|
|
config := e2enetwork.NewNetworkingTestConfig(ctx, f, e2enetwork.EnableDualStack)
|
2020-11-11 17:04:33 -05:00
|
|
|
ginkgo.By(fmt.Sprintf("dialing(udp) %v (endpoint) --> %v:%v (config.clusterIP)", config.EndpointPods[0].Name, config.SecondaryClusterIP, e2enetwork.ClusterUDPPort))
|
2022-12-12 04:11:10 -05:00
|
|
|
err := config.DialFromEndpointContainer(ctx, "udp", config.SecondaryClusterIP, e2enetwork.ClusterUDPPort, config.MaxTries, 0, config.EndpointHostnames())
|
2021-02-01 04:14:33 -05:00
|
|
|
if err != nil {
|
|
|
|
|
framework.Failf("failed dialing endpoint, %v", err)
|
|
|
|
|
}
|
2020-11-11 17:04:33 -05:00
|
|
|
ginkgo.By(fmt.Sprintf("dialing(udp) %v (endpoint) --> %v:%v (nodeIP)", config.EndpointPods[0].Name, config.SecondaryNodeIP, config.NodeUDPPort))
|
2022-12-12 04:11:10 -05:00
|
|
|
err = config.DialFromEndpointContainer(ctx, "udp", config.SecondaryNodeIP, config.NodeUDPPort, config.MaxTries, 0, config.EndpointHostnames())
|
2021-02-01 04:14:33 -05:00
|
|
|
if err != nil {
|
|
|
|
|
framework.Failf("failed dialing endpoint, %v", err)
|
|
|
|
|
}
|
2020-11-11 17:04:33 -05:00
|
|
|
})
|
|
|
|
|
|
2022-10-17 08:47:15 -04:00
|
|
|
ginkgo.It("should update endpoints: http", func(ctx context.Context) {
|
2022-12-12 04:11:10 -05:00
|
|
|
config := e2enetwork.NewNetworkingTestConfig(ctx, f, e2enetwork.EnableDualStack)
|
2020-11-11 17:04:33 -05:00
|
|
|
ginkgo.By(fmt.Sprintf("dialing(http) %v --> %v:%v (config.clusterIP)", config.TestContainerPod.Name, config.SecondaryClusterIP, e2enetwork.ClusterHTTPPort))
|
2022-12-12 04:11:10 -05:00
|
|
|
err := config.DialFromTestContainer(ctx, "http", config.SecondaryClusterIP, e2enetwork.ClusterHTTPPort, config.MaxTries, 0, config.EndpointHostnames())
|
2021-02-01 04:14:33 -05:00
|
|
|
if err != nil {
|
|
|
|
|
framework.Failf("failed dialing endpoint, %v", err)
|
|
|
|
|
}
|
2022-12-12 04:11:10 -05:00
|
|
|
config.DeleteNetProxyPod(ctx)
|
2020-11-11 17:04:33 -05:00
|
|
|
|
|
|
|
|
ginkgo.By(fmt.Sprintf("dialing(http) %v --> %v:%v (config.clusterIP)", config.TestContainerPod.Name, config.SecondaryClusterIP, e2enetwork.ClusterHTTPPort))
|
2022-12-12 04:11:10 -05:00
|
|
|
err = config.DialFromTestContainer(ctx, "http", config.SecondaryClusterIP, e2enetwork.ClusterHTTPPort, config.MaxTries, config.MaxTries, config.EndpointHostnames())
|
2021-02-01 04:14:33 -05:00
|
|
|
if err != nil {
|
|
|
|
|
framework.Failf("failed dialing endpoint, %v", err)
|
|
|
|
|
}
|
2020-11-11 17:04:33 -05:00
|
|
|
})
|
|
|
|
|
|
2022-10-17 08:47:15 -04:00
|
|
|
ginkgo.It("should update endpoints: udp", func(ctx context.Context) {
|
2022-12-12 04:11:10 -05:00
|
|
|
config := e2enetwork.NewNetworkingTestConfig(ctx, f, e2enetwork.EnableDualStack)
|
2020-11-11 17:04:33 -05:00
|
|
|
ginkgo.By(fmt.Sprintf("dialing(udp) %v --> %v:%v (config.clusterIP)", config.TestContainerPod.Name, config.SecondaryClusterIP, e2enetwork.ClusterUDPPort))
|
2022-12-12 04:11:10 -05:00
|
|
|
err := config.DialFromTestContainer(ctx, "udp", config.SecondaryClusterIP, e2enetwork.ClusterUDPPort, config.MaxTries, 0, config.EndpointHostnames())
|
2021-02-01 04:14:33 -05:00
|
|
|
if err != nil {
|
|
|
|
|
framework.Failf("failed dialing endpoint, %v", err)
|
|
|
|
|
}
|
2020-11-11 17:04:33 -05:00
|
|
|
|
2022-12-12 04:11:10 -05:00
|
|
|
config.DeleteNetProxyPod(ctx)
|
2020-11-11 17:04:33 -05:00
|
|
|
|
|
|
|
|
ginkgo.By(fmt.Sprintf("dialing(udp) %v --> %v:%v (config.clusterIP)", config.TestContainerPod.Name, config.SecondaryClusterIP, e2enetwork.ClusterUDPPort))
|
2022-12-12 04:11:10 -05:00
|
|
|
err = config.DialFromTestContainer(ctx, "udp", config.SecondaryClusterIP, e2enetwork.ClusterUDPPort, config.MaxTries, config.MaxTries, config.EndpointHostnames())
|
2021-02-01 04:14:33 -05:00
|
|
|
if err != nil {
|
|
|
|
|
framework.Failf("failed dialing endpoint, %v", err)
|
|
|
|
|
}
|
2020-11-11 17:04:33 -05:00
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// [LinuxOnly]: Windows does not support session affinity.
|
2022-10-17 08:47:15 -04:00
|
|
|
ginkgo.It("should function for client IP based session affinity: http [LinuxOnly]", func(ctx context.Context) {
|
2022-12-12 04:11:10 -05:00
|
|
|
config := e2enetwork.NewNetworkingTestConfig(ctx, f, e2enetwork.EnableDualStack)
|
2020-11-11 17:04:33 -05:00
|
|
|
ginkgo.By(fmt.Sprintf("dialing(http) %v --> %v:%v", config.TestContainerPod.Name, config.SessionAffinityService.Spec.ClusterIPs[1], e2enetwork.ClusterHTTPPort))
|
|
|
|
|
|
|
|
|
|
// Check if number of endpoints returned are exactly one.
|
2022-12-12 04:11:10 -05:00
|
|
|
eps, err := config.GetEndpointsFromTestContainer(ctx, "http", config.SessionAffinityService.Spec.ClusterIPs[1], e2enetwork.ClusterHTTPPort, e2enetwork.SessionAffinityChecks)
|
2020-11-11 17:04:33 -05:00
|
|
|
if err != nil {
|
|
|
|
|
framework.Failf("ginkgo.Failed to get endpoints from test container, error: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if len(eps) == 0 {
|
|
|
|
|
framework.Failf("Unexpected no endpoints return")
|
|
|
|
|
}
|
|
|
|
|
if len(eps) > 1 {
|
|
|
|
|
framework.Failf("Unexpected endpoints return: %v, expect 1 endpoints", eps)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
// [LinuxOnly]: Windows does not support session affinity.
|
2022-10-17 08:47:15 -04:00
|
|
|
ginkgo.It("should function for client IP based session affinity: udp [LinuxOnly]", func(ctx context.Context) {
|
2022-12-12 04:11:10 -05:00
|
|
|
config := e2enetwork.NewNetworkingTestConfig(ctx, f, e2enetwork.EnableDualStack)
|
2020-11-11 17:04:33 -05:00
|
|
|
ginkgo.By(fmt.Sprintf("dialing(udp) %v --> %v:%v", config.TestContainerPod.Name, config.SessionAffinityService.Spec.ClusterIPs[1], e2enetwork.ClusterUDPPort))
|
|
|
|
|
|
|
|
|
|
// Check if number of endpoints returned are exactly one.
|
2022-12-12 04:11:10 -05:00
|
|
|
eps, err := config.GetEndpointsFromTestContainer(ctx, "udp", config.SessionAffinityService.Spec.ClusterIPs[1], e2enetwork.ClusterUDPPort, e2enetwork.SessionAffinityChecks)
|
2020-11-11 17:04:33 -05:00
|
|
|
if err != nil {
|
|
|
|
|
framework.Failf("ginkgo.Failed to get endpoints from test container, error: %v", err)
|
|
|
|
|
}
|
|
|
|
|
if len(eps) == 0 {
|
|
|
|
|
framework.Failf("Unexpected no endpoints return")
|
|
|
|
|
}
|
|
|
|
|
if len(eps) > 1 {
|
|
|
|
|
framework.Failf("Unexpected endpoints return: %v, expect 1 endpoints", eps)
|
|
|
|
|
}
|
|
|
|
|
})
|
|
|
|
|
|
2022-10-17 08:47:15 -04:00
|
|
|
ginkgo.It("should be able to handle large requests: http", func(ctx context.Context) {
|
2022-12-12 04:11:10 -05:00
|
|
|
config := e2enetwork.NewNetworkingTestConfig(ctx, f, e2enetwork.EnableDualStack)
|
2020-11-11 17:04:33 -05:00
|
|
|
ginkgo.By(fmt.Sprintf("dialing(http) %v --> %v:%v (config.clusterIP)", config.TestContainerPod.Name, config.SecondaryClusterIP, e2enetwork.ClusterHTTPPort))
|
|
|
|
|
message := strings.Repeat("42", 1000)
|
2022-12-12 04:11:10 -05:00
|
|
|
config.DialEchoFromTestContainer(ctx, "http", config.SecondaryClusterIP, e2enetwork.ClusterHTTPPort, config.MaxTries, 0, message)
|
2020-11-11 17:04:33 -05:00
|
|
|
})
|
|
|
|
|
|
2022-10-17 08:47:15 -04:00
|
|
|
ginkgo.It("should be able to handle large requests: udp", func(ctx context.Context) {
|
2022-12-12 04:11:10 -05:00
|
|
|
config := e2enetwork.NewNetworkingTestConfig(ctx, f, e2enetwork.EnableDualStack)
|
2020-11-11 17:04:33 -05:00
|
|
|
ginkgo.By(fmt.Sprintf("dialing(udp) %v --> %v:%v (config.clusterIP)", config.TestContainerPod.Name, config.SecondaryClusterIP, e2enetwork.ClusterUDPPort))
|
|
|
|
|
message := "n" + strings.Repeat("o", 1999)
|
2022-12-12 04:11:10 -05:00
|
|
|
config.DialEchoFromTestContainer(ctx, "udp", config.SecondaryClusterIP, e2enetwork.ClusterUDPPort, config.MaxTries, 0, message)
|
2020-11-11 17:04:33 -05:00
|
|
|
})
|
2021-02-01 04:10:14 -05:00
|
|
|
|
|
|
|
|
// if the endpoints pods use hostNetwork, several tests can't run in parallel
|
|
|
|
|
// because the pods will try to acquire the same port in the host.
|
|
|
|
|
// We run the test in serial, to avoid port conflicts.
|
2022-10-17 08:47:15 -04:00
|
|
|
ginkgo.It("should function for service endpoints using hostNetwork", func(ctx context.Context) {
|
2022-12-12 04:11:10 -05:00
|
|
|
config := e2enetwork.NewNetworkingTestConfig(ctx, f, e2enetwork.EnableDualStack, e2enetwork.UseHostNetwork, e2enetwork.EndpointsUseHostNetwork)
|
2021-02-01 04:10:14 -05:00
|
|
|
|
|
|
|
|
ginkgo.By("pod-Service(hostNetwork): http")
|
|
|
|
|
|
|
|
|
|
ginkgo.By(fmt.Sprintf("dialing(http) %v --> %v:%v (config.clusterIP)", config.TestContainerPod.Name, config.SecondaryClusterIP, e2enetwork.ClusterHTTPPort))
|
2022-12-12 04:11:10 -05:00
|
|
|
err := config.DialFromTestContainer(ctx, "http", config.SecondaryClusterIP, e2enetwork.ClusterHTTPPort, config.MaxTries, 0, config.EndpointHostnames())
|
2021-02-01 04:10:14 -05:00
|
|
|
if err != nil {
|
|
|
|
|
framework.Failf("failed dialing endpoint, %v", err)
|
|
|
|
|
}
|
|
|
|
|
ginkgo.By(fmt.Sprintf("dialing(http) %v --> %v:%v (nodeIP)", config.TestContainerPod.Name, config.SecondaryNodeIP, config.NodeHTTPPort))
|
2022-12-12 04:11:10 -05:00
|
|
|
err = config.DialFromTestContainer(ctx, "http", config.SecondaryNodeIP, config.NodeHTTPPort, config.MaxTries, 0, config.EndpointHostnames())
|
2021-02-01 04:10:14 -05:00
|
|
|
if err != nil {
|
|
|
|
|
framework.Failf("failed dialing endpoint, %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ginkgo.By("node-Service(hostNetwork): http")
|
|
|
|
|
|
|
|
|
|
ginkgo.By(fmt.Sprintf("dialing(http) %v (node) --> %v:%v (config.clusterIP)", config.SecondaryNodeIP, config.SecondaryClusterIP, e2enetwork.ClusterHTTPPort))
|
2022-12-12 04:11:10 -05:00
|
|
|
err = config.DialFromNode(ctx, "http", config.SecondaryClusterIP, e2enetwork.ClusterHTTPPort, config.MaxTries, 0, config.EndpointHostnames())
|
2021-02-01 04:10:14 -05:00
|
|
|
if err != nil {
|
|
|
|
|
framework.Failf("failed dialing endpoint, %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ginkgo.By(fmt.Sprintf("dialing(http) %v (node) --> %v:%v (nodeIP)", config.SecondaryNodeIP, config.SecondaryNodeIP, config.NodeHTTPPort))
|
2022-12-12 04:11:10 -05:00
|
|
|
err = config.DialFromNode(ctx, "http", config.SecondaryNodeIP, config.NodeHTTPPort, config.MaxTries, 0, config.EndpointHostnames())
|
2021-02-01 04:10:14 -05:00
|
|
|
if err != nil {
|
|
|
|
|
framework.Failf("failed dialing endpoint, %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ginkgo.By("node-Service(hostNetwork): udp")
|
|
|
|
|
|
|
|
|
|
ginkgo.By(fmt.Sprintf("dialing(udp) %v (node) --> %v:%v (config.clusterIP)", config.SecondaryNodeIP, config.SecondaryClusterIP, e2enetwork.ClusterUDPPort))
|
|
|
|
|
|
2022-12-12 04:11:10 -05:00
|
|
|
err = config.DialFromNode(ctx, "udp", config.SecondaryClusterIP, e2enetwork.ClusterUDPPort, config.MaxTries, 0, config.EndpointHostnames())
|
2021-02-01 04:10:14 -05:00
|
|
|
if err != nil {
|
|
|
|
|
time.Sleep(10 * time.Hour)
|
|
|
|
|
framework.Failf("failed dialing endpoint, %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ginkgo.By(fmt.Sprintf("dialing(udp) %v (node) --> %v:%v (nodeIP)", config.SecondaryNodeIP, config.SecondaryNodeIP, config.NodeUDPPort))
|
2022-12-12 04:11:10 -05:00
|
|
|
err = config.DialFromNode(ctx, "udp", config.SecondaryNodeIP, config.NodeUDPPort, config.MaxTries, 0, config.EndpointHostnames())
|
2021-02-01 04:10:14 -05:00
|
|
|
if err != nil {
|
|
|
|
|
framework.Failf("failed dialing endpoint, %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ginkgo.By("handle large requests: http(hostNetwork)")
|
|
|
|
|
|
|
|
|
|
ginkgo.By(fmt.Sprintf("dialing(http) %v --> %v:%v (config.SecondaryClusterIP)", config.TestContainerPod.Name, config.SecondaryClusterIP, e2enetwork.ClusterHTTPPort))
|
|
|
|
|
message := strings.Repeat("42", 1000)
|
2022-12-12 04:11:10 -05:00
|
|
|
err = config.DialEchoFromTestContainer(ctx, "http", config.SecondaryClusterIP, e2enetwork.ClusterHTTPPort, config.MaxTries, 0, message)
|
2021-02-01 04:10:14 -05:00
|
|
|
if err != nil {
|
|
|
|
|
framework.Failf("failed dialing endpoint, %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ginkgo.By("handle large requests: udp(hostNetwork)")
|
|
|
|
|
|
|
|
|
|
ginkgo.By(fmt.Sprintf("dialing(udp) %v --> %v:%v (config.SecondaryClusterIP)", config.TestContainerPod.Name, config.SecondaryClusterIP, e2enetwork.ClusterUDPPort))
|
|
|
|
|
message = "n" + strings.Repeat("o", 1999)
|
2022-12-12 04:11:10 -05:00
|
|
|
err = config.DialEchoFromTestContainer(ctx, "udp", config.SecondaryClusterIP, e2enetwork.ClusterUDPPort, config.MaxTries, 0, message)
|
2021-02-01 04:10:14 -05:00
|
|
|
if err != nil {
|
|
|
|
|
framework.Failf("failed dialing endpoint, %v", err)
|
|
|
|
|
}
|
|
|
|
|
})
|
2020-11-11 17:04:33 -05:00
|
|
|
})
|
2019-06-06 17:43:13 -04:00
|
|
|
})
|
|
|
|
|
|
2019-07-29 17:00:35 -04:00
|
|
|
func validateNumOfServicePorts(svc *v1.Service, expectedNumOfPorts int) {
|
|
|
|
|
if len(svc.Spec.Ports) != expectedNumOfPorts {
|
|
|
|
|
framework.Failf("got unexpected len(Spec.Ports) for service: %v", svc)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2021-11-10 02:09:35 -05:00
|
|
|
func validateServiceAndClusterIPFamily(svc *v1.Service, expectedIPFamilies []v1.IPFamily, expectedPolicy *v1.IPFamilyPolicy) {
|
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
|
|
|
if len(svc.Spec.IPFamilies) != len(expectedIPFamilies) {
|
2019-07-29 17:00:35 -04:00
|
|
|
framework.Failf("service ip family nil for service %s/%s", svc.Namespace, svc.Name)
|
|
|
|
|
}
|
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
|
|
|
|
|
|
|
|
for idx, family := range expectedIPFamilies {
|
|
|
|
|
if svc.Spec.IPFamilies[idx] != family {
|
|
|
|
|
framework.Failf("service %s/%s expected family %v at index[%v] got %v", svc.Namespace, svc.Name, family, idx, svc.Spec.IPFamilies[idx])
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// validate ip assigned is from the family
|
|
|
|
|
if len(svc.Spec.ClusterIPs) != len(svc.Spec.IPFamilies) {
|
|
|
|
|
framework.Failf("service %s/%s assigned ips [%+v] does not match families [%+v]", svc.Namespace, svc.Name, svc.Spec.ClusterIPs, svc.Spec.IPFamilies)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for idx, family := range svc.Spec.IPFamilies {
|
|
|
|
|
if (family == v1.IPv6Protocol) != netutils.IsIPv6String(svc.Spec.ClusterIPs[idx]) {
|
|
|
|
|
framework.Failf("service %s/%s assigned ips at [%v]:%v does not match family:%v", svc.Namespace, svc.Name, idx, svc.Spec.ClusterIPs[idx], family)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// validate policy
|
|
|
|
|
if expectedPolicy == nil && svc.Spec.IPFamilyPolicy != nil {
|
|
|
|
|
framework.Failf("service %s/%s expected nil for IPFamilyPolicy", svc.Namespace, svc.Name)
|
|
|
|
|
}
|
|
|
|
|
if expectedPolicy != nil && svc.Spec.IPFamilyPolicy == nil {
|
|
|
|
|
framework.Failf("service %s/%s expected value %v for IPFamilyPolicy", svc.Namespace, svc.Name, expectedPolicy)
|
2019-07-29 17:00:35 -04:00
|
|
|
}
|
|
|
|
|
|
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
|
|
|
if expectedPolicy != nil && *(svc.Spec.IPFamilyPolicy) != *(expectedPolicy) {
|
|
|
|
|
framework.Failf("service %s/%s expected value %v for IPFamilyPolicy", svc.Namespace, svc.Name, expectedPolicy)
|
2019-07-29 17:00:35 -04:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-06-10 09:51:15 -04:00
|
|
|
func validateEndpointSlices(ctx context.Context, f *framework.Framework, svc *v1.Service, expectedIPFamilies []v1.IPFamily) {
|
|
|
|
|
var slices []discoveryv1.EndpointSlice
|
|
|
|
|
err := e2eendpointslice.WaitForEndpointSlices(ctx, f.ClientSet, svc.Namespace, svc.Name, 500*time.Millisecond, 10*time.Second, func(ctx context.Context, endpointSlices []discoveryv1.EndpointSlice) (bool, error) {
|
|
|
|
|
if len(endpointSlices) < len(expectedIPFamilies) {
|
2024-11-20 15:54:32 -05:00
|
|
|
return false, nil
|
|
|
|
|
}
|
2025-06-10 09:51:15 -04:00
|
|
|
slices = endpointSlices
|
2024-11-20 15:54:32 -05:00
|
|
|
return true, nil
|
2025-06-10 09:51:15 -04:00
|
|
|
})
|
|
|
|
|
framework.ExpectNoError(err, "could not validate EndpointSlices for service %s/%s", svc.Namespace, svc.Name)
|
2019-07-29 17:00:35 -04:00
|
|
|
|
2024-11-20 15:54:32 -05:00
|
|
|
var wantIPv4, wantIPv6 bool
|
|
|
|
|
for _, family := range expectedIPFamilies {
|
|
|
|
|
if family == v1.IPv4Protocol {
|
|
|
|
|
wantIPv4 = true
|
|
|
|
|
} else if family == v1.IPv6Protocol {
|
|
|
|
|
wantIPv6 = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, slice := range slices {
|
|
|
|
|
ip := "(none)"
|
|
|
|
|
if len(slice.Endpoints) > 0 && len(slice.Endpoints[0].Addresses) > 0 {
|
|
|
|
|
ip = slice.Endpoints[0].Addresses[0]
|
|
|
|
|
}
|
|
|
|
|
if slice.AddressType == discoveryv1.AddressTypeIPv4 {
|
|
|
|
|
if !wantIPv4 {
|
|
|
|
|
framework.Failf("did not want IPv4 slice but got slice %s with IP %s", slice.Name, ip)
|
|
|
|
|
}
|
|
|
|
|
wantIPv4 = false
|
|
|
|
|
} else if slice.AddressType == discoveryv1.AddressTypeIPv6 {
|
|
|
|
|
if !wantIPv6 {
|
|
|
|
|
framework.Failf("did not want IPv6 slice but got slice %s with IP %s", slice.Name, ip)
|
|
|
|
|
}
|
|
|
|
|
wantIPv6 = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if wantIPv4 {
|
|
|
|
|
framework.Failf("wanted an IPv4 slice but did not get one")
|
|
|
|
|
}
|
|
|
|
|
if wantIPv6 {
|
|
|
|
|
framework.Failf("wanted an IPv6 slice but did not get one")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-12 04:11:10 -05:00
|
|
|
func assertNetworkConnectivity(ctx context.Context, f *framework.Framework, serverPods v1.PodList, clientPods v1.PodList, containerName, port string) {
|
2019-06-06 17:43:13 -04:00
|
|
|
// curl from each client pod to all server pods to assert connectivity
|
2019-07-10 18:14:39 -04:00
|
|
|
duration := "10s"
|
|
|
|
|
pollInterval := "1s"
|
|
|
|
|
timeout := 10
|
|
|
|
|
|
2019-06-06 17:43:13 -04:00
|
|
|
var serverIPs []string
|
|
|
|
|
for _, pod := range serverPods.Items {
|
|
|
|
|
if pod.Status.PodIPs == nil || len(pod.Status.PodIPs) != 2 {
|
2019-09-13 00:44:29 -04:00
|
|
|
framework.Failf("PodIPs list not expected value, got %v", pod.Status.PodIPs)
|
2019-06-06 17:43:13 -04:00
|
|
|
}
|
2020-11-05 14:29:23 -05:00
|
|
|
if netutils.IsIPv4String(pod.Status.PodIPs[0].IP) == netutils.IsIPv4String(pod.Status.PodIPs[1].IP) {
|
2019-09-13 00:44:29 -04:00
|
|
|
framework.Failf("PodIPs should belong to different families, got %v", pod.Status.PodIPs)
|
2019-06-06 17:43:13 -04:00
|
|
|
}
|
|
|
|
|
serverIPs = append(serverIPs, pod.Status.PodIPs[0].IP, pod.Status.PodIPs[1].IP)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, clientPod := range clientPods.Items {
|
|
|
|
|
for _, ip := range serverIPs {
|
2022-12-12 04:11:10 -05:00
|
|
|
gomega.Consistently(ctx, func() error {
|
2019-07-10 18:14:39 -04:00
|
|
|
ginkgo.By(fmt.Sprintf("checking connectivity from pod %s to serverIP: %s, port: %s", clientPod.Name, ip, port))
|
|
|
|
|
cmd := checkNetworkConnectivity(ip, port, timeout)
|
e2e: adapt to moved code
This is the result of automatically editing source files like this:
go install golang.org/x/tools/cmd/goimports@latest
find ./test/e2e* -name "*.go" | xargs env PATH=$GOPATH/bin:$PATH ./e2e-framework-sed.sh
with e2e-framework-sed.sh containing this:
sed -i \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecCommandInContainer(/e2epod.ExecCommandInContainer(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecCommandInContainerWithFullOutput(/e2epod.ExecCommandInContainerWithFullOutput(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecShellInContainer(/e2epod.ExecShellInContainer(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecShellInPod(/e2epod.ExecShellInPod(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecShellInPodWithFullOutput(/e2epod.ExecShellInPodWithFullOutput(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.ExecWithOptions(/e2epod.ExecWithOptions(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.MatchContainerOutput(/e2eoutput.MatchContainerOutput(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.PodClient(/e2epod.NewPodClient(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.PodClientNS(/e2epod.PodClientNS(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.TestContainerOutput(/e2eoutput.TestContainerOutput(\1, /" \
-e "s/\(f\|fr\|\w\w*\.[fF]\w*\)\.TestContainerOutputRegexp(/e2eoutput.TestContainerOutputRegexp(\1, /" \
-e "s/framework.AddOrUpdateLabelOnNode\b/e2enode.AddOrUpdateLabelOnNode/" \
-e "s/framework.AllNodes\b/e2edebug.AllNodes/" \
-e "s/framework.AllNodesReady\b/e2enode.AllNodesReady/" \
-e "s/framework.ContainerResourceGatherer\b/e2edebug.ContainerResourceGatherer/" \
-e "s/framework.ContainerResourceUsage\b/e2edebug.ContainerResourceUsage/" \
-e "s/framework.CreateEmptyFileOnPod\b/e2eoutput.CreateEmptyFileOnPod/" \
-e "s/framework.DefaultPodDeletionTimeout\b/e2epod.DefaultPodDeletionTimeout/" \
-e "s/framework.DumpAllNamespaceInfo\b/e2edebug.DumpAllNamespaceInfo/" \
-e "s/framework.DumpDebugInfo\b/e2eoutput.DumpDebugInfo/" \
-e "s/framework.DumpNodeDebugInfo\b/e2edebug.DumpNodeDebugInfo/" \
-e "s/framework.EtcdUpgrade\b/e2eproviders.EtcdUpgrade/" \
-e "s/framework.EventsLister\b/e2edebug.EventsLister/" \
-e "s/framework.ExecOptions\b/e2epod.ExecOptions/" \
-e "s/framework.ExpectNodeHasLabel\b/e2enode.ExpectNodeHasLabel/" \
-e "s/framework.ExpectNodeHasTaint\b/e2enode.ExpectNodeHasTaint/" \
-e "s/framework.GCEUpgradeScript\b/e2eproviders.GCEUpgradeScript/" \
-e "s/framework.ImagePrePullList\b/e2epod.ImagePrePullList/" \
-e "s/framework.KubectlBuilder\b/e2ekubectl.KubectlBuilder/" \
-e "s/framework.LocationParamGKE\b/e2eproviders.LocationParamGKE/" \
-e "s/framework.LogSizeDataTimeseries\b/e2edebug.LogSizeDataTimeseries/" \
-e "s/framework.LogSizeGatherer\b/e2edebug.LogSizeGatherer/" \
-e "s/framework.LogsSizeData\b/e2edebug.LogsSizeData/" \
-e "s/framework.LogsSizeDataSummary\b/e2edebug.LogsSizeDataSummary/" \
-e "s/framework.LogsSizeVerifier\b/e2edebug.LogsSizeVerifier/" \
-e "s/framework.LookForStringInLog\b/e2eoutput.LookForStringInLog/" \
-e "s/framework.LookForStringInPodExec\b/e2eoutput.LookForStringInPodExec/" \
-e "s/framework.LookForStringInPodExecToContainer\b/e2eoutput.LookForStringInPodExecToContainer/" \
-e "s/framework.MasterAndDNSNodes\b/e2edebug.MasterAndDNSNodes/" \
-e "s/framework.MasterNodes\b/e2edebug.MasterNodes/" \
-e "s/framework.MasterUpgradeGKE\b/e2eproviders.MasterUpgradeGKE/" \
-e "s/framework.NewKubectlCommand\b/e2ekubectl.NewKubectlCommand/" \
-e "s/framework.NewLogsVerifier\b/e2edebug.NewLogsVerifier/" \
-e "s/framework.NewNodeKiller\b/e2enode.NewNodeKiller/" \
-e "s/framework.NewResourceUsageGatherer\b/e2edebug.NewResourceUsageGatherer/" \
-e "s/framework.NodeHasTaint\b/e2enode.NodeHasTaint/" \
-e "s/framework.NodeKiller\b/e2enode.NodeKiller/" \
-e "s/framework.NodesSet\b/e2edebug.NodesSet/" \
-e "s/framework.PodClient\b/e2epod.PodClient/" \
-e "s/framework.RemoveLabelOffNode\b/e2enode.RemoveLabelOffNode/" \
-e "s/framework.ResourceConstraint\b/e2edebug.ResourceConstraint/" \
-e "s/framework.ResourceGathererOptions\b/e2edebug.ResourceGathererOptions/" \
-e "s/framework.ResourceUsagePerContainer\b/e2edebug.ResourceUsagePerContainer/" \
-e "s/framework.ResourceUsageSummary\b/e2edebug.ResourceUsageSummary/" \
-e "s/framework.RunHostCmd\b/e2eoutput.RunHostCmd/" \
-e "s/framework.RunHostCmdOrDie\b/e2eoutput.RunHostCmdOrDie/" \
-e "s/framework.RunHostCmdWithFullOutput\b/e2eoutput.RunHostCmdWithFullOutput/" \
-e "s/framework.RunHostCmdWithRetries\b/e2eoutput.RunHostCmdWithRetries/" \
-e "s/framework.RunKubectl\b/e2ekubectl.RunKubectl/" \
-e "s/framework.RunKubectlInput\b/e2ekubectl.RunKubectlInput/" \
-e "s/framework.RunKubectlOrDie\b/e2ekubectl.RunKubectlOrDie/" \
-e "s/framework.RunKubectlOrDieInput\b/e2ekubectl.RunKubectlOrDieInput/" \
-e "s/framework.RunKubectlWithFullOutput\b/e2ekubectl.RunKubectlWithFullOutput/" \
-e "s/framework.RunKubemciCmd\b/e2ekubectl.RunKubemciCmd/" \
-e "s/framework.RunKubemciWithKubeconfig\b/e2ekubectl.RunKubemciWithKubeconfig/" \
-e "s/framework.SingleContainerSummary\b/e2edebug.SingleContainerSummary/" \
-e "s/framework.SingleLogSummary\b/e2edebug.SingleLogSummary/" \
-e "s/framework.TimestampedSize\b/e2edebug.TimestampedSize/" \
-e "s/framework.WaitForAllNodesSchedulable\b/e2enode.WaitForAllNodesSchedulable/" \
-e "s/framework.WaitForSSHTunnels\b/e2enode.WaitForSSHTunnels/" \
-e "s/framework.WorkItem\b/e2edebug.WorkItem/" \
"$@"
for i in "$@"; do
# Import all sub packages and let goimports figure out which of those
# are redundant (= already imported) or not needed.
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2edebug "k8s.io/kubernetes/test/e2e/framework/debug"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2ekubectl "k8s.io/kubernetes/test/e2e/framework/kubectl"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2enode "k8s.io/kubernetes/test/e2e/framework/node"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2eoutput "k8s.io/kubernetes/test/e2e/framework/pod/output"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2epod "k8s.io/kubernetes/test/e2e/framework/pod"' "$i"
sed -i -e '/"k8s.io.kubernetes.test.e2e.framework"/a e2eproviders "k8s.io/kubernetes/test/e2e/framework/providers"' "$i"
goimports -w "$i"
done
2022-09-08 10:04:17 -04:00
|
|
|
_, _, err := e2epod.ExecCommandInContainerWithFullOutput(f, clientPod.Name, containerName, cmd...)
|
2019-06-06 17:43:13 -04:00
|
|
|
return err
|
|
|
|
|
}, duration, pollInterval).ShouldNot(gomega.HaveOccurred())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-10 18:14:39 -04:00
|
|
|
func checkNetworkConnectivity(ip, port string, timeout int) []string {
|
|
|
|
|
curl := fmt.Sprintf("curl -g --connect-timeout %v http://%s", timeout, net.JoinHostPort(ip, port))
|
2019-06-06 17:43:13 -04:00
|
|
|
cmd := []string{"/bin/sh", "-c", curl}
|
|
|
|
|
return cmd
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-29 17:00:35 -04:00
|
|
|
// createService returns a service spec with defined arguments
|
2021-11-10 02:09:35 -05:00
|
|
|
func createService(name, ns string, labels map[string]string, ipFamilyPolicy *v1.IPFamilyPolicy, ipFamilies []v1.IPFamily) *v1.Service {
|
2019-07-29 17:00:35 -04:00
|
|
|
return &v1.Service{
|
|
|
|
|
ObjectMeta: metav1.ObjectMeta{
|
|
|
|
|
Name: name,
|
|
|
|
|
Namespace: ns,
|
|
|
|
|
},
|
|
|
|
|
Spec: v1.ServiceSpec{
|
dual stack services (#91824)
* api: structure change
* api: defaulting, conversion, and validation
* [FIX] validation: auto remove second ip/family when service changes to SingleStack
* [FIX] api: defaulting, conversion, and validation
* api-server: clusterIPs alloc, printers, storage and strategy
* [FIX] clusterIPs default on read
* alloc: auto remove second ip/family when service changes to SingleStack
* api-server: repair loop handling for clusterIPs
* api-server: force kubernetes default service into single stack
* api-server: tie dualstack feature flag with endpoint feature flag
* controller-manager: feature flag, endpoint, and endpointSlice controllers handling multi family service
* [FIX] controller-manager: feature flag, endpoint, and endpointSlicecontrollers handling multi family service
* kube-proxy: feature-flag, utils, proxier, and meta proxier
* [FIX] kubeproxy: call both proxier at the same time
* kubenet: remove forced pod IP sorting
* kubectl: modify describe to include ClusterIPs, IPFamilies, and IPFamilyPolicy
* e2e: fix tests that depends on IPFamily field AND add dual stack tests
* e2e: fix expected error message for ClusterIP immutability
* add integration tests for dualstack
the third phase of dual stack is a very complex change in the API,
basically it introduces Dual Stack services. Main changes are:
- It pluralizes the Service IPFamily field to IPFamilies,
and removes the singular field.
- It introduces a new field IPFamilyPolicyType that can take
3 values to express the "dual-stack(mad)ness" of the cluster:
SingleStack, PreferDualStack and RequireDualStack
- It pluralizes ClusterIP to ClusterIPs.
The goal is to add coverage to the services API operations,
taking into account the 6 different modes a cluster can have:
- single stack: IP4 or IPv6 (as of today)
- dual stack: IPv4 only, IPv6 only, IPv4 - IPv6, IPv6 - IPv4
* [FIX] add integration tests for dualstack
* generated data
* generated files
Co-authored-by: Antonio Ojea <aojea@redhat.com>
2020-10-26 16:15:59 -04:00
|
|
|
Selector: labels,
|
|
|
|
|
Type: v1.ServiceTypeNodePort,
|
|
|
|
|
IPFamilyPolicy: ipFamilyPolicy,
|
|
|
|
|
IPFamilies: ipFamilies,
|
2019-07-29 17:00:35 -04:00
|
|
|
Ports: []v1.ServicePort{
|
|
|
|
|
{
|
|
|
|
|
Name: "tcp-port",
|
|
|
|
|
Port: 53,
|
|
|
|
|
Protocol: v1.ProtocolTCP,
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
Name: "udp-port",
|
|
|
|
|
Port: 53,
|
|
|
|
|
Protocol: v1.ProtocolUDP,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
}
|