Skip to content

Commit eafd289

Browse files
authored
Merge pull request kubernetes#123180 from AkihiroSuda/rro
KEP-3857: Recursive Read-only (RRO) mounts
2 parents d3d06c3 + d4925ce commit eafd289

File tree

103 files changed

+4243
-1329
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

103 files changed

+4243
-1329
lines changed

api/openapi-spec/swagger.json

Lines changed: 76 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

api/openapi-spec/v3/api__v1_openapi.json

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1590,6 +1590,24 @@
15901590
],
15911591
"default": {},
15921592
"description": "State holds details about the container's current condition."
1593+
},
1594+
"volumeMounts": {
1595+
"description": "Status of volume mounts.",
1596+
"items": {
1597+
"allOf": [
1598+
{
1599+
"$ref": "#/components/schemas/io.k8s.api.core.v1.VolumeMountStatus"
1600+
}
1601+
],
1602+
"default": {}
1603+
},
1604+
"type": "array",
1605+
"x-kubernetes-list-map-keys": [
1606+
"mountPath"
1607+
],
1608+
"x-kubernetes-list-type": "map",
1609+
"x-kubernetes-patch-merge-key": "mountPath",
1610+
"x-kubernetes-patch-strategy": "merge"
15931611
}
15941612
},
15951613
"required": [
@@ -3709,6 +3727,35 @@
37093727
}
37103728
]
37113729
},
3730+
"io.k8s.api.core.v1.NodeRuntimeClass": {
3731+
"description": "NodeRuntimeClass is a set of runtime class information.",
3732+
"properties": {
3733+
"features": {
3734+
"allOf": [
3735+
{
3736+
"$ref": "#/components/schemas/io.k8s.api.core.v1.NodeRuntimeClassFeatures"
3737+
}
3738+
],
3739+
"description": "Supported features."
3740+
},
3741+
"name": {
3742+
"default": "",
3743+
"description": "Runtime class name. Empty for the default runtime class.",
3744+
"type": "string"
3745+
}
3746+
},
3747+
"type": "object"
3748+
},
3749+
"io.k8s.api.core.v1.NodeRuntimeClassFeatures": {
3750+
"description": "NodeRuntimeClassFeatures is a set of runtime features.",
3751+
"properties": {
3752+
"recursiveReadOnlyMounts": {
3753+
"description": "RecursiveReadOnlyMounts is set to true if the runtime class supports RecursiveReadOnlyMounts.",
3754+
"type": "boolean"
3755+
}
3756+
},
3757+
"type": "object"
3758+
},
37123759
"io.k8s.api.core.v1.NodeSelector": {
37133760
"description": "A node selector represents the union of the results of one or more label queries over a set of nodes; that is, it represents the OR of the selectors represented by the node selector terms.",
37143761
"properties": {
@@ -3943,6 +3990,19 @@
39433990
"description": "NodePhase is the recently observed lifecycle phase of the node. More info: https://kubernetes.io/docs/concepts/nodes/node/#phase The field is never populated, and now is deprecated.",
39443991
"type": "string"
39453992
},
3993+
"runtimeClasses": {
3994+
"description": "The available runtime classes.",
3995+
"items": {
3996+
"allOf": [
3997+
{
3998+
"$ref": "#/components/schemas/io.k8s.api.core.v1.NodeRuntimeClass"
3999+
}
4000+
],
4001+
"default": {}
4002+
},
4003+
"type": "array",
4004+
"x-kubernetes-list-type": "atomic"
4005+
},
39464006
"volumesAttached": {
39474007
"description": "List of volumes that are attached to the node.",
39484008
"items": {
@@ -8106,7 +8166,7 @@
81068166
"type": "string"
81078167
},
81088168
"mountPropagation": {
8109-
"description": "mountPropagation determines how mounts are propagated from the host to container and the other way around. When not set, MountPropagationNone is used. This field is beta in 1.10.",
8169+
"description": "mountPropagation determines how mounts are propagated from the host to container and the other way around. When not set, MountPropagationNone is used. This field is beta in 1.10. When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified (which defaults to None).",
81108170
"type": "string"
81118171
},
81128172
"name": {
@@ -8118,6 +8178,10 @@
81188178
"description": "Mounted read-only if true, read-write otherwise (false or unspecified). Defaults to false.",
81198179
"type": "boolean"
81208180
},
8181+
"recursiveReadOnly": {
8182+
"description": "RecursiveReadOnly specifies whether read-only mounts should be handled recursively.\n\nIf ReadOnly is false, this field has no meaning and must be unspecified.\n\nIf ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this field is set to Enabled, the mount is made recursively read-only if it is supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason.\n\nIf this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None).\n\nIf this field is not specified, it is treated as an equivalent of Disabled.",
8183+
"type": "string"
8184+
},
81218185
"subPath": {
81228186
"description": "Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root).",
81238187
"type": "string"
@@ -8133,6 +8197,34 @@
81338197
],
81348198
"type": "object"
81358199
},
8200+
"io.k8s.api.core.v1.VolumeMountStatus": {
8201+
"description": "VolumeMountStatus shows status of volume mounts.",
8202+
"properties": {
8203+
"mountPath": {
8204+
"default": "",
8205+
"description": "MountPath corresponds to the original VolumeMount.",
8206+
"type": "string"
8207+
},
8208+
"name": {
8209+
"default": "",
8210+
"description": "Name corresponds to the name of the original VolumeMount.",
8211+
"type": "string"
8212+
},
8213+
"readOnly": {
8214+
"description": "ReadOnly corresponds to the original VolumeMount.",
8215+
"type": "boolean"
8216+
},
8217+
"recursiveReadOnly": {
8218+
"description": "RecursiveReadOnly must be set to Disabled, Enabled, or unspecified (for non-readonly mounts). An IfPossible value in the original VolumeMount must be translated to Disabled or Enabled, depending on the mount result.",
8219+
"type": "string"
8220+
}
8221+
},
8222+
"required": [
8223+
"name",
8224+
"mountPath"
8225+
],
8226+
"type": "object"
8227+
},
81368228
"io.k8s.api.core.v1.VolumeNodeAffinity": {
81378229
"description": "VolumeNodeAffinity defines constraints that limit what nodes this volume can be accessed from.",
81388230
"properties": {

api/openapi-spec/v3/apis__apps__v1_openapi.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5147,7 +5147,7 @@
51475147
"type": "string"
51485148
},
51495149
"mountPropagation": {
5150-
"description": "mountPropagation determines how mounts are propagated from the host to container and the other way around. When not set, MountPropagationNone is used. This field is beta in 1.10.",
5150+
"description": "mountPropagation determines how mounts are propagated from the host to container and the other way around. When not set, MountPropagationNone is used. This field is beta in 1.10. When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified (which defaults to None).",
51515151
"type": "string"
51525152
},
51535153
"name": {
@@ -5159,6 +5159,10 @@
51595159
"description": "Mounted read-only if true, read-write otherwise (false or unspecified). Defaults to false.",
51605160
"type": "boolean"
51615161
},
5162+
"recursiveReadOnly": {
5163+
"description": "RecursiveReadOnly specifies whether read-only mounts should be handled recursively.\n\nIf ReadOnly is false, this field has no meaning and must be unspecified.\n\nIf ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this field is set to Enabled, the mount is made recursively read-only if it is supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason.\n\nIf this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None).\n\nIf this field is not specified, it is treated as an equivalent of Disabled.",
5164+
"type": "string"
5165+
},
51625166
"subPath": {
51635167
"description": "Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root).",
51645168
"type": "string"

api/openapi-spec/v3/apis__batch__v1_openapi.json

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4351,7 +4351,7 @@
43514351
"type": "string"
43524352
},
43534353
"mountPropagation": {
4354-
"description": "mountPropagation determines how mounts are propagated from the host to container and the other way around. When not set, MountPropagationNone is used. This field is beta in 1.10.",
4354+
"description": "mountPropagation determines how mounts are propagated from the host to container and the other way around. When not set, MountPropagationNone is used. This field is beta in 1.10. When RecursiveReadOnly is set to IfPossible or to Enabled, MountPropagation must be None or unspecified (which defaults to None).",
43554355
"type": "string"
43564356
},
43574357
"name": {
@@ -4363,6 +4363,10 @@
43634363
"description": "Mounted read-only if true, read-write otherwise (false or unspecified). Defaults to false.",
43644364
"type": "boolean"
43654365
},
4366+
"recursiveReadOnly": {
4367+
"description": "RecursiveReadOnly specifies whether read-only mounts should be handled recursively.\n\nIf ReadOnly is false, this field has no meaning and must be unspecified.\n\nIf ReadOnly is true, and this field is set to Disabled, the mount is not made recursively read-only. If this field is set to IfPossible, the mount is made recursively read-only, if it is supported by the container runtime. If this field is set to Enabled, the mount is made recursively read-only if it is supported by the container runtime, otherwise the pod will not be started and an error will be generated to indicate the reason.\n\nIf this field is set to IfPossible or Enabled, MountPropagation must be set to None (or be unspecified, which defaults to None).\n\nIf this field is not specified, it is treated as an equivalent of Disabled.",
4368+
"type": "string"
4369+
},
43664370
"subPath": {
43674371
"description": "Path within the volume from which the container's volume should be mounted. Defaults to \"\" (volume's root).",
43684372
"type": "string"

pkg/api/pod/util.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,6 +685,24 @@ func dropDisabledFields(
685685
// For other types of containers, validateContainers will handle them.
686686
}
687687

688+
if !utilfeature.DefaultFeatureGate.Enabled(features.RecursiveReadOnlyMounts) && !rroInUse(oldPodSpec) {
689+
for i := range podSpec.Containers {
690+
for j := range podSpec.Containers[i].VolumeMounts {
691+
podSpec.Containers[i].VolumeMounts[j].RecursiveReadOnly = nil
692+
}
693+
}
694+
for i := range podSpec.InitContainers {
695+
for j := range podSpec.InitContainers[i].VolumeMounts {
696+
podSpec.InitContainers[i].VolumeMounts[j].RecursiveReadOnly = nil
697+
}
698+
}
699+
for i := range podSpec.EphemeralContainers {
700+
for j := range podSpec.EphemeralContainers[i].VolumeMounts {
701+
podSpec.EphemeralContainers[i].VolumeMounts[j].RecursiveReadOnly = nil
702+
}
703+
}
704+
}
705+
688706
dropPodLifecycleSleepAction(podSpec, oldPodSpec)
689707
}
690708

@@ -790,6 +808,18 @@ func dropDisabledPodStatusFields(podStatus, oldPodStatus *api.PodStatus, podSpec
790808
if !utilfeature.DefaultFeatureGate.Enabled(features.PodHostIPs) && !hostIPsInUse(oldPodStatus) {
791809
podStatus.HostIPs = nil
792810
}
811+
812+
if !utilfeature.DefaultFeatureGate.Enabled(features.RecursiveReadOnlyMounts) && !rroInUse(oldPodSpec) {
813+
for i := range podStatus.ContainerStatuses {
814+
podStatus.ContainerStatuses[i].VolumeMounts = nil
815+
}
816+
for i := range podStatus.InitContainerStatuses {
817+
podStatus.InitContainerStatuses[i].VolumeMounts = nil
818+
}
819+
for i := range podStatus.EphemeralContainerStatuses {
820+
podStatus.EphemeralContainerStatuses[i].VolumeMounts = nil
821+
}
822+
}
793823
}
794824

795825
func hostIPsInUse(podStatus *api.PodStatus) bool {
@@ -1102,6 +1132,23 @@ func clusterTrustBundleProjectionInUse(podSpec *api.PodSpec) bool {
11021132
return false
11031133
}
11041134

1135+
func rroInUse(podSpec *api.PodSpec) bool {
1136+
if podSpec == nil {
1137+
return false
1138+
}
1139+
var inUse bool
1140+
VisitContainers(podSpec, AllContainers, func(c *api.Container, _ ContainerType) bool {
1141+
for _, f := range c.VolumeMounts {
1142+
if f.RecursiveReadOnly != nil {
1143+
inUse = true
1144+
return false
1145+
}
1146+
}
1147+
return true
1148+
})
1149+
return inUse
1150+
}
1151+
11051152
func dropDisabledClusterTrustBundleProjection(podSpec, oldPodSpec *api.PodSpec) {
11061153
if utilfeature.DefaultFeatureGate.Enabled(features.ClusterTrustBundleProjection) {
11071154
return

0 commit comments

Comments
 (0)