mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-09-21 01:50:55 +00:00
Field status.hostIPs
added for Pod (#101566)
* Add FeatureGate PodHostIPs * Add HostIPs field and update PodIPs field * Types conversion * Add dropDisabledStatusFields * Add HostIPs for kubelet * Add fuzzer for PodStatus * Add status.hostIPs in ConvertDownwardAPIFieldLabel * Add status.hostIPs in validEnvDownwardAPIFieldPathExpressions * Downward API support for status.hostIPs * Add DownwardAPI validation for status.hostIPs * Add e2e to check that hostIPs works * Add e2e to check that Downward API works * Regenerate
This commit is contained in:
@@ -434,6 +434,8 @@ func GetValidationOptionsFromPodSpecAndMeta(podSpec, oldPodSpec *api.PodSpec, po
|
||||
AllowExpandedDNSConfig: utilfeature.DefaultFeatureGate.Enabled(features.ExpandedDNSConfig) || haveSameExpandedDNSConfig(podSpec, oldPodSpec),
|
||||
// Allow pod spec to use OS field
|
||||
AllowOSField: utilfeature.DefaultFeatureGate.Enabled(features.IdentifyPodOS),
|
||||
// Allow pod spec to use status.hostIPs in downward API if feature is enabled
|
||||
AllowHostIPsField: utilfeature.DefaultFeatureGate.Enabled(features.PodHostIPs),
|
||||
// The default sysctl value does not contain a forward slash, and in 1.24 we intend to relax this to be true by default
|
||||
AllowSysctlRegexContainSlash: false,
|
||||
}
|
||||
@@ -454,6 +456,9 @@ func GetValidationOptionsFromPodSpecAndMeta(podSpec, oldPodSpec *api.PodSpec, po
|
||||
// if old spec has OS field set, we must allow it
|
||||
opts.AllowOSField = opts.AllowOSField || oldPodSpec.OS != nil
|
||||
|
||||
// if old spec has status.hostIPs downwardAPI set, we must allow it
|
||||
opts.AllowHostIPsField = opts.AllowHostIPsField || hasUsedDownwardAPIFieldPathWithPodSpec(oldPodSpec, "status.hostIPs")
|
||||
|
||||
// if old spec used non-integer multiple of huge page unit size, we must allow it
|
||||
opts.AllowIndivisibleHugePagesValues = usesIndivisibleHugePagesValues(oldPodSpec)
|
||||
|
||||
@@ -470,6 +475,57 @@ func GetValidationOptionsFromPodSpecAndMeta(podSpec, oldPodSpec *api.PodSpec, po
|
||||
return opts
|
||||
}
|
||||
|
||||
func hasUsedDownwardAPIFieldPathWithPodSpec(podSpec *api.PodSpec, fieldPath string) bool {
|
||||
if podSpec == nil {
|
||||
return false
|
||||
}
|
||||
for _, vol := range podSpec.Volumes {
|
||||
if hasUsedDownwardAPIFieldPathWithVolume(&vol, fieldPath) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
for _, c := range podSpec.InitContainers {
|
||||
if hasUsedDownwardAPIFieldPathWithContainer(&c, fieldPath) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
for _, c := range podSpec.Containers {
|
||||
if hasUsedDownwardAPIFieldPathWithContainer(&c, fieldPath) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func hasUsedDownwardAPIFieldPathWithVolume(volume *api.Volume, fieldPath string) bool {
|
||||
if volume == nil {
|
||||
return false
|
||||
}
|
||||
if volume.DownwardAPI != nil {
|
||||
for _, file := range volume.DownwardAPI.Items {
|
||||
if file.FieldRef != nil &&
|
||||
file.FieldRef.FieldPath == fieldPath {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func hasUsedDownwardAPIFieldPathWithContainer(container *api.Container, fieldPath string) bool {
|
||||
if container == nil {
|
||||
return false
|
||||
}
|
||||
for _, env := range container.Env {
|
||||
if env.ValueFrom != nil &&
|
||||
env.ValueFrom.FieldRef != nil &&
|
||||
env.ValueFrom.FieldRef.FieldPath == fieldPath {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// GetValidationOptionsFromPodTemplate will return pod validation options for specified template.
|
||||
func GetValidationOptionsFromPodTemplate(podTemplate, oldPodTemplate *api.PodTemplateSpec) apivalidation.PodValidationOptions {
|
||||
var newPodSpec, oldPodSpec *api.PodSpec
|
||||
@@ -512,19 +568,39 @@ func DropDisabledTemplateFields(podTemplate, oldPodTemplate *api.PodTemplateSpec
|
||||
func DropDisabledPodFields(pod, oldPod *api.Pod) {
|
||||
var (
|
||||
podSpec *api.PodSpec
|
||||
podStatus *api.PodStatus
|
||||
podAnnotations map[string]string
|
||||
oldPodSpec *api.PodSpec
|
||||
oldPodStatus *api.PodStatus
|
||||
oldPodAnnotations map[string]string
|
||||
)
|
||||
if pod != nil {
|
||||
podSpec = &pod.Spec
|
||||
podAnnotations = pod.Annotations
|
||||
podStatus = &pod.Status
|
||||
}
|
||||
if oldPod != nil {
|
||||
oldPodSpec = &oldPod.Spec
|
||||
oldPodAnnotations = oldPod.Annotations
|
||||
oldPodStatus = &oldPod.Status
|
||||
}
|
||||
dropDisabledFields(podSpec, podAnnotations, oldPodSpec, oldPodAnnotations)
|
||||
dropDisabledStatusFields(podStatus, oldPodStatus)
|
||||
}
|
||||
|
||||
// dropDisabledStatusFields removes disabled fields from the pod status
|
||||
func dropDisabledStatusFields(podStatus *api.PodStatus, oldPodStatus *api.PodStatus) {
|
||||
// drop HostIPs to empty (disable PodHostIPs).
|
||||
if !utilfeature.DefaultFeatureGate.Enabled(features.PodHostIPs) && !hostIPsInUse(oldPodStatus) {
|
||||
podStatus.HostIPs = nil
|
||||
}
|
||||
}
|
||||
|
||||
func hostIPsInUse(podStatus *api.PodStatus) bool {
|
||||
if podStatus == nil {
|
||||
return false
|
||||
}
|
||||
return len(podStatus.HostIPs) > 0
|
||||
}
|
||||
|
||||
// dropDisabledFields removes disabled fields from the pod metadata and spec.
|
||||
|
@@ -1768,3 +1768,73 @@ func TestDropOSField(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDropDisabledStatusFields(t *testing.T) {
|
||||
podWithHostIP := func() *api.PodStatus {
|
||||
return &api.PodStatus{
|
||||
HostIPs: makeHostIPs("10.0.0.1", "fd00:10::1"),
|
||||
}
|
||||
}
|
||||
|
||||
podWithoutHostIPs := func() *api.PodStatus {
|
||||
return &api.PodStatus{
|
||||
HostIPs: nil,
|
||||
}
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
podStatus *api.PodStatus
|
||||
oldPodStatus *api.PodStatus
|
||||
wantPodStatus *api.PodStatus
|
||||
featureEnabled bool
|
||||
}{
|
||||
{
|
||||
podStatus: podWithHostIP(),
|
||||
oldPodStatus: podWithHostIP(),
|
||||
featureEnabled: false,
|
||||
|
||||
wantPodStatus: podWithHostIP(),
|
||||
},
|
||||
{
|
||||
podStatus: podWithoutHostIPs(),
|
||||
oldPodStatus: podWithHostIP(),
|
||||
featureEnabled: true,
|
||||
|
||||
wantPodStatus: podWithoutHostIPs(),
|
||||
},
|
||||
{
|
||||
podStatus: podWithoutHostIPs(),
|
||||
oldPodStatus: podWithoutHostIPs(),
|
||||
featureEnabled: false,
|
||||
|
||||
wantPodStatus: podWithoutHostIPs(),
|
||||
},
|
||||
{
|
||||
podStatus: podWithHostIP(),
|
||||
oldPodStatus: podWithoutHostIPs(),
|
||||
featureEnabled: true,
|
||||
|
||||
wantPodStatus: podWithHostIP(),
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.PodHostIPs, tt.featureEnabled)()
|
||||
|
||||
dropDisabledStatusFields(tt.podStatus, tt.oldPodStatus)
|
||||
|
||||
if !reflect.DeepEqual(tt.podStatus, tt.wantPodStatus) {
|
||||
t.Errorf("dropDisabledStatusFields() = %v, want %v", tt.podStatus, tt.wantPodStatus)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func makeHostIPs(ips ...string) []api.HostIP {
|
||||
ret := []api.HostIP{}
|
||||
for _, ip := range ips {
|
||||
ret = append(ret, api.HostIP{IP: ip})
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
Reference in New Issue
Block a user