Skip to content

Commit

Permalink
Promote KEP-2681 to beta in 1.29
Browse files Browse the repository at this point in the history
  • Loading branch information
wzshiming committed Sep 22, 2023
1 parent 14ed7e8 commit 91ed9cd
Show file tree
Hide file tree
Showing 2 changed files with 127 additions and 74 deletions.
3 changes: 2 additions & 1 deletion pkg/features/kube_features.go
Original file line number Diff line number Diff line change
Expand Up @@ -684,6 +684,7 @@ const (
// owner: @wzshiming
// kep: http://kep.k8s.io/2681
// alpha: v1.28
// beta: v1.29
//
// Adds pod.status.hostIPs and downward API
PodHostIPs featuregate.Feature = "PodHostIPs"
Expand Down Expand Up @@ -1134,7 +1135,7 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS

PodReadyToStartContainersCondition: {Default: false, PreRelease: featuregate.Alpha},

PodHostIPs: {Default: false, PreRelease: featuregate.Alpha},
PodHostIPs: {Default: true, PreRelease: featuregate.Beta},

PodSchedulingReadiness: {Default: true, PreRelease: featuregate.Beta},

Expand Down
198 changes: 125 additions & 73 deletions test/e2e_node/pod_host_ips.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,8 @@ import (
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/sets"
"k8s.io/apimachinery/pkg/util/uuid"
netutils "k8s.io/utils/net"

kubefeatures "k8s.io/kubernetes/pkg/features"
kubeletconfig "k8s.io/kubernetes/pkg/kubelet/apis/config"
"k8s.io/kubernetes/test/e2e/framework"
Expand All @@ -38,9 +37,11 @@ import (
e2epodoutput "k8s.io/kubernetes/test/e2e/framework/pod/output"
"k8s.io/kubernetes/test/e2e/network/common"
imageutils "k8s.io/kubernetes/test/utils/image"
netutils "k8s.io/utils/net"
"k8s.io/utils/ptr"
)

var _ = common.SIGDescribe("Dual Stack Host IP [Feature:PodHostIPs]", func() {
var _ = common.SIGDescribe("DualStack Host IP [NodeFeature:PodHostIPs] [Feature:PodHostIPs]", func() {
f := framework.NewDefaultFramework("dualstack")

ginkgo.Context("when creating a Pod, it has no PodHostIPs feature", func() {
Expand All @@ -53,21 +54,7 @@ var _ = common.SIGDescribe("Dual Stack Host IP [Feature:PodHostIPs]", func() {

podName := "pod-dualstack-host-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),
},
},
},
}

pod := genPodHostIPs(podName+string(uuid.NewUUID()), false)
ginkgo.By("submitting the pod to kubernetes")
podClient := e2epod.NewPodClient(f)
p := podClient.CreateSync(ctx, pod)
Expand All @@ -76,30 +63,15 @@ var _ = common.SIGDescribe("Dual Stack Host IP [Feature:PodHostIPs]", func() {
gomega.Expect(p.Status.HostIPs).Should(gomega.BeNil())

ginkgo.By("deleting the pod")
err := podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(30))
err := podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(1))
framework.ExpectNoError(err, "failed to delete pod")
})

ginkgo.It("should create pod with hostNetwork, add host ips is empty", func(ctx context.Context) {

podName := "pod-dualstack-host-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),
},
},
HostNetwork: true,
},
}

pod := genPodHostIPs(podName+string(uuid.NewUUID()), true)
ginkgo.By("submitting the pod to kubernetes")
podClient := e2epod.NewPodClient(f)
p := podClient.CreateSync(ctx, pod)
Expand All @@ -108,7 +80,7 @@ var _ = common.SIGDescribe("Dual Stack Host IP [Feature:PodHostIPs]", func() {
gomega.Expect(p.Status.HostIPs).Should(gomega.BeNil())

ginkgo.By("deleting the pod")
err := podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(30))
err := podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(1))
framework.ExpectNoError(err, "failed to delete pod")
})
})
Expand All @@ -123,20 +95,7 @@ var _ = common.SIGDescribe("Dual Stack Host IP [Feature:PodHostIPs]", func() {

podName := "pod-dualstack-host-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),
},
},
},
}
pod := genPodHostIPs(podName+string(uuid.NewUUID()), false)

ginkgo.By("submitting the pod to kubernetes")
podClient := e2epod.NewPodClient(f)
Expand All @@ -158,41 +117,34 @@ var _ = common.SIGDescribe("Dual Stack Host IP [Feature:PodHostIPs]", func() {
framework.ExpectNoError(err)
for _, node := range nodeList.Items {
if node.Name == p.Spec.NodeName {
nodeIPs := []string{}
got := sets.New[string]()
for _, hostIP := range p.Status.HostIPs {
got.Insert(hostIP.IP)
}

want := sets.New[string]()
for _, address := range node.Status.Addresses {
if address.Type == v1.NodeInternalIP {
nodeIPs = append(nodeIPs, address.Address)
want.Insert(address.Address)
}
}
gomega.Expect(p.Status.HostIPs).Should(gomega.Equal(nodeIPs))
if !got.Equal(want) {
framework.Failf("got %v, want %v", got, want)
}
break
}
}

ginkgo.By("deleting the pod")
err = podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(30))
err = podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(1))
framework.ExpectNoError(err, "failed to delete pod")
})

ginkgo.It("should create pod with hostNetwork, add ipv6 and ipv4 ip to host ips", func(ctx context.Context) {

podName := "pod-dualstack-host-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),
},
},
HostNetwork: true,
},
}
pod := genPodHostIPs(podName+string(uuid.NewUUID()), true)

ginkgo.By("submitting the pod to kubernetes")
podClient := e2epod.NewPodClient(f)
Expand All @@ -214,19 +166,26 @@ var _ = common.SIGDescribe("Dual Stack Host IP [Feature:PodHostIPs]", func() {
framework.ExpectNoError(err)
for _, node := range nodeList.Items {
if node.Name == p.Spec.NodeName {
nodeIPs := []string{}
got := sets.New[string]()
for _, hostIP := range p.Status.HostIPs {
got.Insert(hostIP.IP)
}

want := sets.New[string]()
for _, address := range node.Status.Addresses {
if address.Type == v1.NodeInternalIP {
nodeIPs = append(nodeIPs, address.Address)
want.Insert(address.Address)
}
}
gomega.Expect(p.Status.HostIPs).Should(gomega.Equal(nodeIPs))
if !got.Equal(want) {
framework.Failf("got %v, want %v", got, want)
}
break
}
}

ginkgo.By("deleting the pod")
err = podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(30))
err = podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(1))
framework.ExpectNoError(err, "failed to delete pod")
})

Expand All @@ -250,9 +209,91 @@ var _ = common.SIGDescribe("Dual Stack Host IP [Feature:PodHostIPs]", func() {

testDownwardAPI(ctx, f, podName, env, expectations)
})

ginkgo.It("rollback", func(ctx context.Context) {

podName := "pod-dualstack-host-ips"

pod := genPodHostIPs(podName+string(uuid.NewUUID()), false)

ginkgo.By("submitting the pod to kubernetes")
podClient := e2epod.NewPodClient(f)
p := podClient.CreateSync(ctx, pod)

gomega.Expect(p.Status.HostIPs).ShouldNot(gomega.BeNil())

ginkgo.By("Disable PodHostIPs feature")
cfg, err := getCurrentKubeletConfig(ctx)
framework.ExpectNoError(err)

newCfg := cfg.DeepCopy()
newCfg.FeatureGates = map[string]bool{
string(kubefeatures.PodHostIPs): false,
}

updateKubeletConfig(ctx, f, newCfg, true)

gomega.Expect(p.Status.HostIPs).ShouldNot(gomega.BeNil())

ginkgo.By("deleting the pod")
err = podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(1))
framework.ExpectNoError(err, "failed to delete pod")

ginkgo.By("recreate pod")
pod = genPodHostIPs(podName+string(uuid.NewUUID()), false)
p = podClient.CreateSync(ctx, pod)
// Feature PodHostIPs is disabled, HostIPs should be nil
gomega.Expect(p.Status.HostIPs).Should(gomega.BeNil())

newCfg.FeatureGates = map[string]bool{
string(kubefeatures.PodHostIPs): true,
}

updateKubeletConfig(ctx, f, newCfg, true)

p, err = podClient.Get(ctx, pod.Name, metav1.GetOptions{})
framework.ExpectNoError(err)
// Feature PodHostIPs is enabled, HostIPs should not be nil
gomega.Expect(p.Status.HostIPs).ShouldNot(gomega.BeNil())

ginkgo.By("deleting the pod")
err = podClient.Delete(ctx, pod.Name, *metav1.NewDeleteOptions(1))
framework.ExpectNoError(err, "failed to delete pod")
})

})
})

func genPodHostIPs(podName string, hostNetwork bool) *v1.Pod {
return &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: podName,
Labels: map[string]string{"test": "dualstack-host-ips"},
},
Spec: v1.PodSpec{
Containers: []v1.Container{
{
Name: "test-container",
Image: imageutils.GetE2EImage(imageutils.Agnhost),
SecurityContext: &v1.SecurityContext{
AllowPrivilegeEscalation: ptr.To(false),
Capabilities: &v1.Capabilities{
Drop: []v1.Capability{"ALL"},
},
RunAsNonRoot: ptr.To(true),
RunAsUser: ptr.To[int64](1000),
SeccompProfile: &v1.SeccompProfile{
Type: v1.SeccompProfileTypeRuntimeDefault,
},
},
},
},
RestartPolicy: v1.RestartPolicyNever,
HostNetwork: hostNetwork,
},
}
}

func testDownwardAPI(ctx context.Context, f *framework.Framework, podName string, env []v1.EnvVar, expectations []string) {
pod := &v1.Pod{
ObjectMeta: metav1.ObjectMeta{
Expand All @@ -276,6 +317,17 @@ func testDownwardAPI(ctx context.Context, f *framework.Framework, podName string
},
},
Env: env,
SecurityContext: &v1.SecurityContext{
AllowPrivilegeEscalation: ptr.To(false),
Capabilities: &v1.Capabilities{
Drop: []v1.Capability{"ALL"},
},
RunAsNonRoot: ptr.To(true),
RunAsUser: ptr.To[int64](1000),
SeccompProfile: &v1.SeccompProfile{
Type: v1.SeccompProfileTypeRuntimeDefault,
},
},
},
},
RestartPolicy: v1.RestartPolicyNever,
Expand Down

0 comments on commit 91ed9cd

Please sign in to comment.