mirror of
https://github.com/k3s-io/kubernetes.git
synced 2025-07-29 06:27:05 +00:00
Merge pull request #105090 from saad-ali/removeSubpathFeaturegate
Remove VolumeSubpath feature gate
This commit is contained in:
commit
0d20f47c7a
@ -544,29 +544,10 @@ func dropDisabledFields(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !utilfeature.DefaultFeatureGate.Enabled(features.VolumeSubpath) && !subpathInUse(oldPodSpec) {
|
|
||||||
// drop subpath from the pod if the feature is disabled and the old spec did not specify subpaths
|
|
||||||
VisitContainers(podSpec, AllContainers, func(c *api.Container, containerType ContainerType) bool {
|
|
||||||
for i := range c.VolumeMounts {
|
|
||||||
c.VolumeMounts[i].SubPath = ""
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
if !utilfeature.DefaultFeatureGate.Enabled(features.EphemeralContainers) && !ephemeralContainersInUse(oldPodSpec) {
|
if !utilfeature.DefaultFeatureGate.Enabled(features.EphemeralContainers) && !ephemeralContainersInUse(oldPodSpec) {
|
||||||
podSpec.EphemeralContainers = nil
|
podSpec.EphemeralContainers = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if !utilfeature.DefaultFeatureGate.Enabled(features.VolumeSubpath) && !subpathExprInUse(oldPodSpec) {
|
|
||||||
// drop subpath env expansion from the pod if subpath feature is disabled and the old spec did not specify subpath env expansion
|
|
||||||
VisitContainers(podSpec, AllContainers, func(c *api.Container, containerType ContainerType) bool {
|
|
||||||
for i := range c.VolumeMounts {
|
|
||||||
c.VolumeMounts[i].SubPathExpr = ""
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
if !utilfeature.DefaultFeatureGate.Enabled(features.ProbeTerminationGracePeriod) && !probeGracePeriodInUse(oldPodSpec) {
|
if !utilfeature.DefaultFeatureGate.Enabled(features.ProbeTerminationGracePeriod) && !probeGracePeriodInUse(oldPodSpec) {
|
||||||
// Set pod-level terminationGracePeriodSeconds to nil if the feature is disabled and it is not used
|
// Set pod-level terminationGracePeriodSeconds to nil if the feature is disabled and it is not used
|
||||||
VisitContainers(podSpec, AllContainers, func(c *api.Container, containerType ContainerType) bool {
|
VisitContainers(podSpec, AllContainers, func(c *api.Container, containerType ContainerType) bool {
|
||||||
@ -728,26 +709,6 @@ func fsGroupPolicyInUse(podSpec *api.PodSpec) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// subpathInUse returns true if the pod spec is non-nil and has a volume mount that makes use of the subPath feature
|
|
||||||
func subpathInUse(podSpec *api.PodSpec) bool {
|
|
||||||
if podSpec == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
var inUse bool
|
|
||||||
VisitContainers(podSpec, AllContainers, func(c *api.Container, containerType ContainerType) bool {
|
|
||||||
for i := range c.VolumeMounts {
|
|
||||||
if len(c.VolumeMounts[i].SubPath) > 0 {
|
|
||||||
inUse = true
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
|
|
||||||
return inUse
|
|
||||||
}
|
|
||||||
|
|
||||||
// overheadInUse returns true if the pod spec is non-nil and has Overhead set
|
// overheadInUse returns true if the pod spec is non-nil and has Overhead set
|
||||||
func overheadInUse(podSpec *api.PodSpec) bool {
|
func overheadInUse(podSpec *api.PodSpec) bool {
|
||||||
if podSpec == nil {
|
if podSpec == nil {
|
||||||
@ -816,26 +777,6 @@ func emptyDirSizeLimitInUse(podSpec *api.PodSpec) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// subpathExprInUse returns true if the pod spec is non-nil and has a volume mount that makes use of the subPathExpr feature
|
|
||||||
func subpathExprInUse(podSpec *api.PodSpec) bool {
|
|
||||||
if podSpec == nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
var inUse bool
|
|
||||||
VisitContainers(podSpec, AllContainers, func(c *api.Container, containerType ContainerType) bool {
|
|
||||||
for i := range c.VolumeMounts {
|
|
||||||
if len(c.VolumeMounts[i].SubPathExpr) > 0 {
|
|
||||||
inUse = true
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
})
|
|
||||||
|
|
||||||
return inUse
|
|
||||||
}
|
|
||||||
|
|
||||||
// probeGracePeriodInUse returns true if the pod spec is non-nil and has a probe that makes use
|
// probeGracePeriodInUse returns true if the pod spec is non-nil and has a probe that makes use
|
||||||
// of the probe-level terminationGracePeriodSeconds feature
|
// of the probe-level terminationGracePeriodSeconds feature
|
||||||
func probeGracePeriodInUse(podSpec *api.PodSpec) bool {
|
func probeGracePeriodInUse(podSpec *api.PodSpec) bool {
|
||||||
|
@ -652,100 +652,6 @@ func TestDropFSGroupFields(t *testing.T) {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDropSubPath(t *testing.T) {
|
|
||||||
podWithSubpaths := func() *api.Pod {
|
|
||||||
return &api.Pod{
|
|
||||||
Spec: api.PodSpec{
|
|
||||||
RestartPolicy: api.RestartPolicyNever,
|
|
||||||
Containers: []api.Container{{Name: "container1", Image: "testimage", VolumeMounts: []api.VolumeMount{{Name: "a", SubPath: "foo"}, {Name: "a", SubPath: "foo2"}, {Name: "a", SubPath: "foo3"}}}},
|
|
||||||
InitContainers: []api.Container{{Name: "container1", Image: "testimage", VolumeMounts: []api.VolumeMount{{Name: "a", SubPath: "foo"}, {Name: "a", SubPath: "foo2"}}}},
|
|
||||||
Volumes: []api.Volume{{Name: "a", VolumeSource: api.VolumeSource{HostPath: &api.HostPathVolumeSource{Path: "/dev/xvdc"}}}},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
podWithoutSubpaths := func() *api.Pod {
|
|
||||||
return &api.Pod{
|
|
||||||
Spec: api.PodSpec{
|
|
||||||
RestartPolicy: api.RestartPolicyNever,
|
|
||||||
Containers: []api.Container{{Name: "container1", Image: "testimage", VolumeMounts: []api.VolumeMount{{Name: "a", SubPath: ""}, {Name: "a", SubPath: ""}, {Name: "a", SubPath: ""}}}},
|
|
||||||
InitContainers: []api.Container{{Name: "container1", Image: "testimage", VolumeMounts: []api.VolumeMount{{Name: "a", SubPath: ""}, {Name: "a", SubPath: ""}}}},
|
|
||||||
Volumes: []api.Volume{{Name: "a", VolumeSource: api.VolumeSource{HostPath: &api.HostPathVolumeSource{Path: "/dev/xvdc"}}}},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
podInfo := []struct {
|
|
||||||
description string
|
|
||||||
hasSubpaths bool
|
|
||||||
pod func() *api.Pod
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
description: "has subpaths",
|
|
||||||
hasSubpaths: true,
|
|
||||||
pod: podWithSubpaths,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "does not have subpaths",
|
|
||||||
hasSubpaths: false,
|
|
||||||
pod: podWithoutSubpaths,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "is nil",
|
|
||||||
hasSubpaths: false,
|
|
||||||
pod: func() *api.Pod { return nil },
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, enabled := range []bool{true, false} {
|
|
||||||
for _, oldPodInfo := range podInfo {
|
|
||||||
for _, newPodInfo := range podInfo {
|
|
||||||
oldPodHasSubpaths, oldPod := oldPodInfo.hasSubpaths, oldPodInfo.pod()
|
|
||||||
newPodHasSubpaths, newPod := newPodInfo.hasSubpaths, newPodInfo.pod()
|
|
||||||
if newPod == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Run(fmt.Sprintf("feature enabled=%v, old pod %v, new pod %v", enabled, oldPodInfo.description, newPodInfo.description), func(t *testing.T) {
|
|
||||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeSubpath, enabled)()
|
|
||||||
|
|
||||||
var oldPodSpec *api.PodSpec
|
|
||||||
if oldPod != nil {
|
|
||||||
oldPodSpec = &oldPod.Spec
|
|
||||||
}
|
|
||||||
dropDisabledFields(&newPod.Spec, nil, oldPodSpec, nil)
|
|
||||||
|
|
||||||
// old pod should never be changed
|
|
||||||
if !reflect.DeepEqual(oldPod, oldPodInfo.pod()) {
|
|
||||||
t.Errorf("old pod changed: %v", cmp.Diff(oldPod, oldPodInfo.pod()))
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case enabled || oldPodHasSubpaths:
|
|
||||||
// new pod should not be changed if the feature is enabled, or if the old pod had subpaths
|
|
||||||
if !reflect.DeepEqual(newPod, newPodInfo.pod()) {
|
|
||||||
t.Errorf("new pod changed: %v", cmp.Diff(newPod, newPodInfo.pod()))
|
|
||||||
}
|
|
||||||
case newPodHasSubpaths:
|
|
||||||
// new pod should be changed
|
|
||||||
if reflect.DeepEqual(newPod, newPodInfo.pod()) {
|
|
||||||
t.Errorf("new pod was not changed")
|
|
||||||
}
|
|
||||||
// new pod should not have subpaths
|
|
||||||
if !reflect.DeepEqual(newPod, podWithoutSubpaths()) {
|
|
||||||
t.Errorf("new pod had subpaths: %v", cmp.Diff(newPod, podWithoutSubpaths()))
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
// new pod should not need to be changed
|
|
||||||
if !reflect.DeepEqual(newPod, newPodInfo.pod()) {
|
|
||||||
t.Errorf("new pod changed: %v", cmp.Diff(newPod, newPodInfo.pod()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDropProcMount(t *testing.T) {
|
func TestDropProcMount(t *testing.T) {
|
||||||
procMount := api.UnmaskedProcMount
|
procMount := api.UnmaskedProcMount
|
||||||
defaultProcMount := api.DefaultProcMount
|
defaultProcMount := api.DefaultProcMount
|
||||||
@ -1046,100 +952,6 @@ func TestDropAppArmor(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDropSubPathExpr(t *testing.T) {
|
|
||||||
podWithSubpaths := func() *api.Pod {
|
|
||||||
return &api.Pod{
|
|
||||||
Spec: api.PodSpec{
|
|
||||||
RestartPolicy: api.RestartPolicyNever,
|
|
||||||
Containers: []api.Container{{Name: "container1", Image: "testimage", VolumeMounts: []api.VolumeMount{{Name: "a", SubPathExpr: "foo"}, {Name: "a", SubPathExpr: "foo2"}, {Name: "a", SubPathExpr: "foo3"}}}},
|
|
||||||
InitContainers: []api.Container{{Name: "container1", Image: "testimage", VolumeMounts: []api.VolumeMount{{Name: "a", SubPathExpr: "foo"}, {Name: "a", SubPathExpr: "foo2"}}}},
|
|
||||||
Volumes: []api.Volume{{Name: "a", VolumeSource: api.VolumeSource{HostPath: &api.HostPathVolumeSource{Path: "/dev/xvdc"}}}},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
podWithoutSubpaths := func() *api.Pod {
|
|
||||||
return &api.Pod{
|
|
||||||
Spec: api.PodSpec{
|
|
||||||
RestartPolicy: api.RestartPolicyNever,
|
|
||||||
Containers: []api.Container{{Name: "container1", Image: "testimage", VolumeMounts: []api.VolumeMount{{Name: "a", SubPathExpr: ""}, {Name: "a", SubPathExpr: ""}, {Name: "a", SubPathExpr: ""}}}},
|
|
||||||
InitContainers: []api.Container{{Name: "container1", Image: "testimage", VolumeMounts: []api.VolumeMount{{Name: "a", SubPathExpr: ""}, {Name: "a", SubPathExpr: ""}}}},
|
|
||||||
Volumes: []api.Volume{{Name: "a", VolumeSource: api.VolumeSource{HostPath: &api.HostPathVolumeSource{Path: "/dev/xvdc"}}}},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
podInfo := []struct {
|
|
||||||
description string
|
|
||||||
hasSubpaths bool
|
|
||||||
pod func() *api.Pod
|
|
||||||
}{
|
|
||||||
{
|
|
||||||
description: "has subpaths",
|
|
||||||
hasSubpaths: true,
|
|
||||||
pod: podWithSubpaths,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "does not have subpaths",
|
|
||||||
hasSubpaths: false,
|
|
||||||
pod: podWithoutSubpaths,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
description: "is nil",
|
|
||||||
hasSubpaths: false,
|
|
||||||
pod: func() *api.Pod { return nil },
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, enabled := range []bool{true, false} {
|
|
||||||
for _, oldPodInfo := range podInfo {
|
|
||||||
for _, newPodInfo := range podInfo {
|
|
||||||
oldPodHasSubpaths, oldPod := oldPodInfo.hasSubpaths, oldPodInfo.pod()
|
|
||||||
newPodHasSubpaths, newPod := newPodInfo.hasSubpaths, newPodInfo.pod()
|
|
||||||
if newPod == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
t.Run(fmt.Sprintf("feature enabled=%v, old pod %v, new pod %v", enabled, oldPodInfo.description, newPodInfo.description), func(t *testing.T) {
|
|
||||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeSubpath, enabled)()
|
|
||||||
|
|
||||||
var oldPodSpec *api.PodSpec
|
|
||||||
if oldPod != nil {
|
|
||||||
oldPodSpec = &oldPod.Spec
|
|
||||||
}
|
|
||||||
dropDisabledFields(&newPod.Spec, nil, oldPodSpec, nil)
|
|
||||||
|
|
||||||
// old pod should never be changed
|
|
||||||
if !reflect.DeepEqual(oldPod, oldPodInfo.pod()) {
|
|
||||||
t.Errorf("old pod changed: %v", cmp.Diff(oldPod, oldPodInfo.pod()))
|
|
||||||
}
|
|
||||||
|
|
||||||
switch {
|
|
||||||
case enabled || oldPodHasSubpaths:
|
|
||||||
// new pod should not be changed if the feature is enabled, or if the old pod had subpaths
|
|
||||||
if !reflect.DeepEqual(newPod, newPodInfo.pod()) {
|
|
||||||
t.Errorf("new pod changed: %v", cmp.Diff(newPod, newPodInfo.pod()))
|
|
||||||
}
|
|
||||||
case newPodHasSubpaths:
|
|
||||||
// new pod should be changed
|
|
||||||
if reflect.DeepEqual(newPod, newPodInfo.pod()) {
|
|
||||||
t.Errorf("new pod was not changed")
|
|
||||||
}
|
|
||||||
// new pod should not have subpaths
|
|
||||||
if !reflect.DeepEqual(newPod, podWithoutSubpaths()) {
|
|
||||||
t.Errorf("new pod had subpaths: %v", cmp.Diff(newPod, podWithoutSubpaths()))
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
// new pod should not need to be changed
|
|
||||||
if !reflect.DeepEqual(newPod, newPodInfo.pod()) {
|
|
||||||
t.Errorf("new pod changed: %v", cmp.Diff(newPod, newPodInfo.pod()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDropProbeGracePeriod(t *testing.T) {
|
func TestDropProbeGracePeriod(t *testing.T) {
|
||||||
podWithProbeGracePeriod := func() *api.Pod {
|
podWithProbeGracePeriod := func() *api.Pod {
|
||||||
livenessGracePeriod := int64(10)
|
livenessGracePeriod := int64(10)
|
||||||
|
@ -5586,71 +5586,7 @@ func TestValidateVolumeMounts(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateDisabledSubpath(t *testing.T) {
|
|
||||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeSubpath, false)()
|
|
||||||
|
|
||||||
volumes := []core.Volume{
|
|
||||||
{Name: "abc", VolumeSource: core.VolumeSource{PersistentVolumeClaim: &core.PersistentVolumeClaimVolumeSource{ClaimName: "testclaim1"}}},
|
|
||||||
{Name: "abc-123", VolumeSource: core.VolumeSource{PersistentVolumeClaim: &core.PersistentVolumeClaimVolumeSource{ClaimName: "testclaim2"}}},
|
|
||||||
{Name: "123", VolumeSource: core.VolumeSource{HostPath: &core.HostPathVolumeSource{Path: "/foo/baz", Type: newHostPathType(string(core.HostPathUnset))}}},
|
|
||||||
}
|
|
||||||
vols, v1err := ValidateVolumes(volumes, nil, field.NewPath("field"), PodValidationOptions{})
|
|
||||||
if len(v1err) > 0 {
|
|
||||||
t.Errorf("Invalid test volume - expected success %v", v1err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
container := core.Container{
|
|
||||||
SecurityContext: nil,
|
|
||||||
}
|
|
||||||
|
|
||||||
goodVolumeDevices := []core.VolumeDevice{
|
|
||||||
{Name: "xyz", DevicePath: "/foofoo"},
|
|
||||||
{Name: "uvw", DevicePath: "/foofoo/share/test"},
|
|
||||||
}
|
|
||||||
|
|
||||||
cases := map[string]struct {
|
|
||||||
mounts []core.VolumeMount
|
|
||||||
expectError bool
|
|
||||||
}{
|
|
||||||
"subpath not specified": {
|
|
||||||
[]core.VolumeMount{
|
|
||||||
{
|
|
||||||
Name: "abc-123",
|
|
||||||
MountPath: "/bab",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
"subpath specified": {
|
|
||||||
[]core.VolumeMount{
|
|
||||||
{
|
|
||||||
Name: "abc-123",
|
|
||||||
MountPath: "/bab",
|
|
||||||
SubPath: "baz",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
false, // validation should not fail, dropping the field is handled in PrepareForCreate/PrepareForUpdate
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for name, test := range cases {
|
|
||||||
errs := ValidateVolumeMounts(test.mounts, GetVolumeDeviceMap(goodVolumeDevices), vols, &container, field.NewPath("field"))
|
|
||||||
|
|
||||||
if len(errs) != 0 && !test.expectError {
|
|
||||||
t.Errorf("test %v failed: %+v", name, errs)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(errs) == 0 && test.expectError {
|
|
||||||
t.Errorf("test %v failed, expected error", name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestValidateSubpathMutuallyExclusive(t *testing.T) {
|
func TestValidateSubpathMutuallyExclusive(t *testing.T) {
|
||||||
// Enable feature VolumeSubpath
|
|
||||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeSubpath, true)()
|
|
||||||
|
|
||||||
volumes := []core.Volume{
|
volumes := []core.Volume{
|
||||||
{Name: "abc", VolumeSource: core.VolumeSource{PersistentVolumeClaim: &core.PersistentVolumeClaimVolumeSource{ClaimName: "testclaim1"}}},
|
{Name: "abc", VolumeSource: core.VolumeSource{PersistentVolumeClaim: &core.PersistentVolumeClaimVolumeSource{ClaimName: "testclaim1"}}},
|
||||||
{Name: "abc-123", VolumeSource: core.VolumeSource{PersistentVolumeClaim: &core.PersistentVolumeClaimVolumeSource{ClaimName: "testclaim2"}}},
|
{Name: "abc-123", VolumeSource: core.VolumeSource{PersistentVolumeClaim: &core.PersistentVolumeClaimVolumeSource{ClaimName: "testclaim2"}}},
|
||||||
@ -5788,45 +5724,6 @@ func TestValidateDisabledSubpathExpr(t *testing.T) {
|
|||||||
t.Errorf("test %v failed, expected error", name)
|
t.Errorf("test %v failed, expected error", name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Repeat with subpath feature gate off
|
|
||||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeSubpath, false)()
|
|
||||||
cases = map[string]struct {
|
|
||||||
mounts []core.VolumeMount
|
|
||||||
expectError bool
|
|
||||||
}{
|
|
||||||
"subpath expr not specified": {
|
|
||||||
[]core.VolumeMount{
|
|
||||||
{
|
|
||||||
Name: "abc-123",
|
|
||||||
MountPath: "/bab",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
"subpath expr specified": {
|
|
||||||
[]core.VolumeMount{
|
|
||||||
{
|
|
||||||
Name: "abc-123",
|
|
||||||
MountPath: "/bab",
|
|
||||||
SubPathExpr: "$(POD_NAME)",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
false, // validation should not fail, dropping the field is handled in PrepareForCreate/PrepareForUpdate
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for name, test := range cases {
|
|
||||||
errs := ValidateVolumeMounts(test.mounts, GetVolumeDeviceMap(goodVolumeDevices), vols, &container, field.NewPath("field"))
|
|
||||||
|
|
||||||
if len(errs) != 0 && !test.expectError {
|
|
||||||
t.Errorf("test %v failed: %+v", name, errs)
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(errs) == 0 && test.expectError {
|
|
||||||
t.Errorf("test %v failed, expected error", name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestValidateMountPropagation(t *testing.T) {
|
func TestValidateMountPropagation(t *testing.T) {
|
||||||
|
@ -156,13 +156,6 @@ const (
|
|||||||
// to the API server.
|
// to the API server.
|
||||||
BoundServiceAccountTokenVolume featuregate.Feature = "BoundServiceAccountTokenVolume"
|
BoundServiceAccountTokenVolume featuregate.Feature = "BoundServiceAccountTokenVolume"
|
||||||
|
|
||||||
// owner: @saad-ali
|
|
||||||
// ga: v1.10
|
|
||||||
//
|
|
||||||
// Allow mounting a subpath of a volume in a container
|
|
||||||
// Do not remove this feature gate even though it's GA
|
|
||||||
VolumeSubpath featuregate.Feature = "VolumeSubpath"
|
|
||||||
|
|
||||||
// owner: @pohly
|
// owner: @pohly
|
||||||
// alpha: v1.14
|
// alpha: v1.14
|
||||||
// beta: v1.16
|
// beta: v1.16
|
||||||
@ -814,7 +807,6 @@ var defaultKubernetesFeatureGates = map[featuregate.Feature]featuregate.FeatureS
|
|||||||
InTreePluginvSphereUnregister: {Default: false, PreRelease: featuregate.Alpha},
|
InTreePluginvSphereUnregister: {Default: false, PreRelease: featuregate.Alpha},
|
||||||
CSIMigrationOpenStack: {Default: true, PreRelease: featuregate.Beta},
|
CSIMigrationOpenStack: {Default: true, PreRelease: featuregate.Beta},
|
||||||
InTreePluginOpenStackUnregister: {Default: false, PreRelease: featuregate.Alpha},
|
InTreePluginOpenStackUnregister: {Default: false, PreRelease: featuregate.Alpha},
|
||||||
VolumeSubpath: {Default: true, PreRelease: featuregate.GA},
|
|
||||||
ConfigurableFSGroupPolicy: {Default: true, PreRelease: featuregate.Beta},
|
ConfigurableFSGroupPolicy: {Default: true, PreRelease: featuregate.Beta},
|
||||||
CSIInlineVolume: {Default: true, PreRelease: featuregate.Beta},
|
CSIInlineVolume: {Default: true, PreRelease: featuregate.Beta},
|
||||||
CSIStorageCapacity: {Default: true, PreRelease: featuregate.Beta},
|
CSIStorageCapacity: {Default: true, PreRelease: featuregate.Beta},
|
||||||
|
@ -186,10 +186,6 @@ func makeMounts(pod *v1.Pod, podDir string, container *v1.Container, hostName, h
|
|||||||
|
|
||||||
subPath := mount.SubPath
|
subPath := mount.SubPath
|
||||||
if mount.SubPathExpr != "" {
|
if mount.SubPathExpr != "" {
|
||||||
if !utilfeature.DefaultFeatureGate.Enabled(features.VolumeSubpath) {
|
|
||||||
return nil, cleanupAction, fmt.Errorf("volume subpaths are disabled")
|
|
||||||
}
|
|
||||||
|
|
||||||
subPath, err = kubecontainer.ExpandContainerVolumeMounts(mount, expandEnvs)
|
subPath, err = kubecontainer.ExpandContainerVolumeMounts(mount, expandEnvs)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -198,10 +194,6 @@ func makeMounts(pod *v1.Pod, podDir string, container *v1.Container, hostName, h
|
|||||||
}
|
}
|
||||||
|
|
||||||
if subPath != "" {
|
if subPath != "" {
|
||||||
if !utilfeature.DefaultFeatureGate.Enabled(features.VolumeSubpath) {
|
|
||||||
return nil, cleanupAction, fmt.Errorf("volume subpaths are disabled")
|
|
||||||
}
|
|
||||||
|
|
||||||
if filepath.IsAbs(subPath) {
|
if filepath.IsAbs(subPath) {
|
||||||
return nil, cleanupAction, fmt.Errorf("error SubPath `%s` must not be an absolute path", subPath)
|
return nil, cleanupAction, fmt.Errorf("error SubPath `%s` must not be an absolute path", subPath)
|
||||||
}
|
}
|
||||||
|
@ -56,65 +56,8 @@ import (
|
|||||||
"k8s.io/kubernetes/pkg/kubelet/cri/streaming/remotecommand"
|
"k8s.io/kubernetes/pkg/kubelet/cri/streaming/remotecommand"
|
||||||
"k8s.io/kubernetes/pkg/kubelet/prober/results"
|
"k8s.io/kubernetes/pkg/kubelet/prober/results"
|
||||||
kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
|
kubetypes "k8s.io/kubernetes/pkg/kubelet/types"
|
||||||
"k8s.io/kubernetes/pkg/volume/util/hostutil"
|
|
||||||
"k8s.io/kubernetes/pkg/volume/util/subpath"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDisabledSubpath(t *testing.T) {
|
|
||||||
fhu := hostutil.NewFakeHostUtil(nil)
|
|
||||||
fsp := &subpath.FakeSubpath{}
|
|
||||||
pod := v1.Pod{
|
|
||||||
Spec: v1.PodSpec{
|
|
||||||
HostNetwork: true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
podVolumes := kubecontainer.VolumeMap{
|
|
||||||
"disk": kubecontainer.VolumeInfo{Mounter: &stubVolume{path: "/mnt/disk"}},
|
|
||||||
}
|
|
||||||
|
|
||||||
cases := map[string]struct {
|
|
||||||
container v1.Container
|
|
||||||
expectError bool
|
|
||||||
}{
|
|
||||||
"subpath not specified": {
|
|
||||||
v1.Container{
|
|
||||||
VolumeMounts: []v1.VolumeMount{
|
|
||||||
{
|
|
||||||
MountPath: "/mnt/path3",
|
|
||||||
Name: "disk",
|
|
||||||
ReadOnly: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
false,
|
|
||||||
},
|
|
||||||
"subpath specified": {
|
|
||||||
v1.Container{
|
|
||||||
VolumeMounts: []v1.VolumeMount{
|
|
||||||
{
|
|
||||||
MountPath: "/mnt/path3",
|
|
||||||
SubPath: "/must/not/be/absolute",
|
|
||||||
Name: "disk",
|
|
||||||
ReadOnly: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
true,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
defer featuregatetesting.SetFeatureGateDuringTest(t, utilfeature.DefaultFeatureGate, features.VolumeSubpath, false)()
|
|
||||||
for name, test := range cases {
|
|
||||||
_, _, err := makeMounts(&pod, "/pod", &test.container, "fakepodname", "", []string{}, podVolumes, fhu, fsp, nil, false)
|
|
||||||
if err != nil && !test.expectError {
|
|
||||||
t.Errorf("test %v failed: %v", name, err)
|
|
||||||
}
|
|
||||||
if err == nil && test.expectError {
|
|
||||||
t.Errorf("test %v failed: expected error", name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestNodeHostsFileContent(t *testing.T) {
|
func TestNodeHostsFileContent(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
hostsFileName string
|
hostsFileName string
|
||||||
|
Loading…
Reference in New Issue
Block a user