Commit e65ac460 authored by Kubernetes Submit Queue's avatar Kubernetes Submit Queue Committed by GitHub

Merge pull request #37237 from jpeeler/implementation-volumeaio

Automatic merge from submit-queue (batch tested with PRs 41709, 41685, 41754, 41759, 37237) Projected volume plugin This is a WIP volume driver implementation as noted in the commit for https://github.com/kubernetes/kubernetes/pull/35313.
parents a5d4afff ec701a65
......@@ -35891,6 +35891,26 @@
}
]
},
"io.k8s.kubernetes.pkg.api.v1.ConfigMapProjection": {
"description": "Adapts a ConfigMap into a projected volume.\n\nThe contents of the target ConfigMap's Data field will be presented in a projected volume as files using the keys in the Data field as the file names, unless the items element is populated with specific mappings of keys to paths. Note that this is identical to a configmap volume source without the default mode.",
"properties": {
"items": {
"description": "If unspecified, each key-value pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the ConfigMap, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'.",
"type": "array",
"items": {
"$ref": "#/definitions/io.k8s.kubernetes.pkg.api.v1.KeyToPath"
}
},
"name": {
"description": "Name of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#names",
"type": "string"
},
"optional": {
"description": "Specify whether the ConfigMap or it's keys must be defined",
"type": "boolean"
}
}
},
"io.k8s.kubernetes.pkg.api.v1.ConfigMapVolumeSource": {
"description": "Adapts a ConfigMap into a volume.\n\nThe contents of the target ConfigMap's Data field will be presented in a volume as files using the keys in the Data field as the file names, unless the items element is populated with specific mappings of keys to paths. ConfigMap volumes support ownership management and SELinux relabeling.",
"properties": {
......@@ -36207,6 +36227,18 @@
}
}
},
"io.k8s.kubernetes.pkg.api.v1.DownwardAPIProjection": {
"description": "Represents downward API info for projecting into a projected volume. Note that this is identical to a downwardAPI volume source without the default mode.",
"properties": {
"items": {
"description": "Items is a list of DownwardAPIVolume file",
"type": "array",
"items": {
"$ref": "#/definitions/io.k8s.kubernetes.pkg.api.v1.DownwardAPIVolumeFile"
}
}
}
},
"io.k8s.kubernetes.pkg.api.v1.DownwardAPIVolumeFile": {
"description": "DownwardAPIVolumeFile represents information to create the file containing the pod field",
"required": [
......@@ -38331,6 +38363,26 @@
}
}
},
"io.k8s.kubernetes.pkg.api.v1.ProjectedVolumeSource": {
"description": "Represents a projected volume source",
"required": [
"sources"
],
"properties": {
"defaultMode": {
"description": "Mode bits to use on created files by default. Must be a value between 0 and 0777. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.",
"type": "integer",
"format": "int32"
},
"sources": {
"description": "list of volume projections",
"type": "array",
"items": {
"$ref": "#/definitions/io.k8s.kubernetes.pkg.api.v1.VolumeProjection"
}
}
}
},
"io.k8s.kubernetes.pkg.api.v1.QuobyteVolumeSource": {
"description": "Represents a Quobyte mount that lasts the lifetime of a pod. Quobyte volumes do not support ownership management or SELinux relabeling.",
"required": [
......@@ -38839,6 +38891,26 @@
}
]
},
"io.k8s.kubernetes.pkg.api.v1.SecretProjection": {
"description": "Adapts a secret into a projected volume.\n\nThe contents of the target Secret's Data field will be presented in a projected volume as files using the keys in the Data field as the file names. Note that this is identical to a secret volume source without the default mode.",
"properties": {
"items": {
"description": "If unspecified, each key-value pair in the Data field of the referenced Secret will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the Secret, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'.",
"type": "array",
"items": {
"$ref": "#/definitions/io.k8s.kubernetes.pkg.api.v1.KeyToPath"
}
},
"name": {
"description": "Name of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#names",
"type": "string"
},
"optional": {
"description": "Specify whether the Secret or its key must be defined",
"type": "boolean"
}
}
},
"io.k8s.kubernetes.pkg.api.v1.SecretVolumeSource": {
"description": "Adapts a Secret into a volume.\n\nThe contents of the target Secret's Data field will be presented in a volume as files using the keys in the Data field as the file names. Secret volumes support ownership management and SELinux relabeling.",
"properties": {
......@@ -39233,6 +39305,10 @@
"description": "PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine",
"$ref": "#/definitions/io.k8s.kubernetes.pkg.api.v1.PhotonPersistentDiskVolumeSource"
},
"projected": {
"description": "Items for all in one resources secrets, configmaps, and downward API",
"$ref": "#/definitions/io.k8s.kubernetes.pkg.api.v1.ProjectedVolumeSource"
},
"quobyte": {
"description": "Quobyte represents a Quobyte mount on the host that shares a pod's lifetime",
"$ref": "#/definitions/io.k8s.kubernetes.pkg.api.v1.QuobyteVolumeSource"
......@@ -39276,6 +39352,23 @@
}
}
},
"io.k8s.kubernetes.pkg.api.v1.VolumeProjection": {
"description": "Projection that may be projected along with other supported volume types",
"properties": {
"configMap": {
"description": "information about the configMap data to project",
"$ref": "#/definitions/io.k8s.kubernetes.pkg.api.v1.ConfigMapProjection"
},
"downwardAPI": {
"description": "information about the downwardAPI data to project",
"$ref": "#/definitions/io.k8s.kubernetes.pkg.api.v1.DownwardAPIProjection"
},
"secret": {
"description": "information about the secret data to project",
"$ref": "#/definitions/io.k8s.kubernetes.pkg.api.v1.SecretProjection"
}
}
},
"io.k8s.kubernetes.pkg.api.v1.VsphereVirtualDiskVolumeSource": {
"description": "Represents a vSphere volume resource.",
"required": [
......@@ -1473,6 +1473,10 @@
"photonPersistentDisk": {
"$ref": "v1.PhotonPersistentDiskVolumeSource",
"description": "PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine"
},
"projected": {
"$ref": "v1.ProjectedVolumeSource",
"description": "Items for all in one resources secrets, configmaps, and downward API"
}
}
},
......@@ -2139,6 +2143,100 @@
}
}
},
"v1.ProjectedVolumeSource": {
"id": "v1.ProjectedVolumeSource",
"description": "Represents a projected volume source",
"required": [
"sources"
],
"properties": {
"sources": {
"type": "array",
"items": {
"$ref": "v1.VolumeProjection"
},
"description": "list of volume projections"
},
"defaultMode": {
"type": "integer",
"format": "int32",
"description": "Mode bits to use on created files by default. Must be a value between 0 and 0777. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set."
}
}
},
"v1.VolumeProjection": {
"id": "v1.VolumeProjection",
"description": "Projection that may be projected along with other supported volume types",
"properties": {
"secret": {
"$ref": "v1.SecretProjection",
"description": "information about the secret data to project"
},
"downwardAPI": {
"$ref": "v1.DownwardAPIProjection",
"description": "information about the downwardAPI data to project"
},
"configMap": {
"$ref": "v1.ConfigMapProjection",
"description": "information about the configMap data to project"
}
}
},
"v1.SecretProjection": {
"id": "v1.SecretProjection",
"description": "Adapts a secret into a projected volume.\n\nThe contents of the target Secret's Data field will be presented in a projected volume as files using the keys in the Data field as the file names. Note that this is identical to a secret volume source without the default mode.",
"properties": {
"name": {
"type": "string",
"description": "Name of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#names"
},
"items": {
"type": "array",
"items": {
"$ref": "v1.KeyToPath"
},
"description": "If unspecified, each key-value pair in the Data field of the referenced Secret will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the Secret, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'."
},
"optional": {
"type": "boolean",
"description": "Specify whether the Secret or its key must be defined"
}
}
},
"v1.DownwardAPIProjection": {
"id": "v1.DownwardAPIProjection",
"description": "Represents downward API info for projecting into a projected volume. Note that this is identical to a downwardAPI volume source without the default mode.",
"properties": {
"items": {
"type": "array",
"items": {
"$ref": "v1.DownwardAPIVolumeFile"
},
"description": "Items is a list of DownwardAPIVolume file"
}
}
},
"v1.ConfigMapProjection": {
"id": "v1.ConfigMapProjection",
"description": "Adapts a ConfigMap into a projected volume.\n\nThe contents of the target ConfigMap's Data field will be presented in a projected volume as files using the keys in the Data field as the file names, unless the items element is populated with specific mappings of keys to paths. Note that this is identical to a configmap volume source without the default mode.",
"properties": {
"name": {
"type": "string",
"description": "Name of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#names"
},
"items": {
"type": "array",
"items": {
"$ref": "v1.KeyToPath"
},
"description": "If unspecified, each key-value pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the ConfigMap, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'."
},
"optional": {
"type": "boolean",
"description": "Specify whether the ConfigMap or it's keys must be defined"
}
}
},
"v1.Container": {
"id": "v1.Container",
"description": "A single application container that you want to run within a pod.",
......
......@@ -1478,6 +1478,10 @@
"photonPersistentDisk": {
"$ref": "v1.PhotonPersistentDiskVolumeSource",
"description": "PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine"
},
"projected": {
"$ref": "v1.ProjectedVolumeSource",
"description": "Items for all in one resources secrets, configmaps, and downward API"
}
}
},
......@@ -2144,6 +2148,100 @@
}
}
},
"v1.ProjectedVolumeSource": {
"id": "v1.ProjectedVolumeSource",
"description": "Represents a projected volume source",
"required": [
"sources"
],
"properties": {
"sources": {
"type": "array",
"items": {
"$ref": "v1.VolumeProjection"
},
"description": "list of volume projections"
},
"defaultMode": {
"type": "integer",
"format": "int32",
"description": "Mode bits to use on created files by default. Must be a value between 0 and 0777. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set."
}
}
},
"v1.VolumeProjection": {
"id": "v1.VolumeProjection",
"description": "Projection that may be projected along with other supported volume types",
"properties": {
"secret": {
"$ref": "v1.SecretProjection",
"description": "information about the secret data to project"
},
"downwardAPI": {
"$ref": "v1.DownwardAPIProjection",
"description": "information about the downwardAPI data to project"
},
"configMap": {
"$ref": "v1.ConfigMapProjection",
"description": "information about the configMap data to project"
}
}
},
"v1.SecretProjection": {
"id": "v1.SecretProjection",
"description": "Adapts a secret into a projected volume.\n\nThe contents of the target Secret's Data field will be presented in a projected volume as files using the keys in the Data field as the file names. Note that this is identical to a secret volume source without the default mode.",
"properties": {
"name": {
"type": "string",
"description": "Name of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#names"
},
"items": {
"type": "array",
"items": {
"$ref": "v1.KeyToPath"
},
"description": "If unspecified, each key-value pair in the Data field of the referenced Secret will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the Secret, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'."
},
"optional": {
"type": "boolean",
"description": "Specify whether the Secret or its key must be defined"
}
}
},
"v1.DownwardAPIProjection": {
"id": "v1.DownwardAPIProjection",
"description": "Represents downward API info for projecting into a projected volume. Note that this is identical to a downwardAPI volume source without the default mode.",
"properties": {
"items": {
"type": "array",
"items": {
"$ref": "v1.DownwardAPIVolumeFile"
},
"description": "Items is a list of DownwardAPIVolume file"
}
}
},
"v1.ConfigMapProjection": {
"id": "v1.ConfigMapProjection",
"description": "Adapts a ConfigMap into a projected volume.\n\nThe contents of the target ConfigMap's Data field will be presented in a projected volume as files using the keys in the Data field as the file names, unless the items element is populated with specific mappings of keys to paths. Note that this is identical to a configmap volume source without the default mode.",
"properties": {
"name": {
"type": "string",
"description": "Name of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#names"
},
"items": {
"type": "array",
"items": {
"$ref": "v1.KeyToPath"
},
"description": "If unspecified, each key-value pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the ConfigMap, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'."
},
"optional": {
"type": "boolean",
"description": "Specify whether the ConfigMap or it's keys must be defined"
}
}
},
"v1.Container": {
"id": "v1.Container",
"description": "A single application container that you want to run within a pod.",
......
......@@ -6880,6 +6880,10 @@
"photonPersistentDisk": {
"$ref": "v1.PhotonPersistentDiskVolumeSource",
"description": "PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine"
},
"projected": {
"$ref": "v1.ProjectedVolumeSource",
"description": "Items for all in one resources secrets, configmaps, and downward API"
}
}
},
......@@ -7546,6 +7550,100 @@
}
}
},
"v1.ProjectedVolumeSource": {
"id": "v1.ProjectedVolumeSource",
"description": "Represents a projected volume source",
"required": [
"sources"
],
"properties": {
"sources": {
"type": "array",
"items": {
"$ref": "v1.VolumeProjection"
},
"description": "list of volume projections"
},
"defaultMode": {
"type": "integer",
"format": "int32",
"description": "Mode bits to use on created files by default. Must be a value between 0 and 0777. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set."
}
}
},
"v1.VolumeProjection": {
"id": "v1.VolumeProjection",
"description": "Projection that may be projected along with other supported volume types",
"properties": {
"secret": {
"$ref": "v1.SecretProjection",
"description": "information about the secret data to project"
},
"downwardAPI": {
"$ref": "v1.DownwardAPIProjection",
"description": "information about the downwardAPI data to project"
},
"configMap": {
"$ref": "v1.ConfigMapProjection",
"description": "information about the configMap data to project"
}
}
},
"v1.SecretProjection": {
"id": "v1.SecretProjection",
"description": "Adapts a secret into a projected volume.\n\nThe contents of the target Secret's Data field will be presented in a projected volume as files using the keys in the Data field as the file names. Note that this is identical to a secret volume source without the default mode.",
"properties": {
"name": {
"type": "string",
"description": "Name of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#names"
},
"items": {
"type": "array",
"items": {
"$ref": "v1.KeyToPath"
},
"description": "If unspecified, each key-value pair in the Data field of the referenced Secret will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the Secret, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'."
},
"optional": {
"type": "boolean",
"description": "Specify whether the Secret or its key must be defined"
}
}
},
"v1.DownwardAPIProjection": {
"id": "v1.DownwardAPIProjection",
"description": "Represents downward API info for projecting into a projected volume. Note that this is identical to a downwardAPI volume source without the default mode.",
"properties": {
"items": {
"type": "array",
"items": {
"$ref": "v1.DownwardAPIVolumeFile"
},
"description": "Items is a list of DownwardAPIVolume file"
}
}
},
"v1.ConfigMapProjection": {
"id": "v1.ConfigMapProjection",
"description": "Adapts a ConfigMap into a projected volume.\n\nThe contents of the target ConfigMap's Data field will be presented in a projected volume as files using the keys in the Data field as the file names, unless the items element is populated with specific mappings of keys to paths. Note that this is identical to a configmap volume source without the default mode.",
"properties": {
"name": {
"type": "string",
"description": "Name of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#names"
},
"items": {
"type": "array",
"items": {
"$ref": "v1.KeyToPath"
},
"description": "If unspecified, each key-value pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the ConfigMap, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'."
},
"optional": {
"type": "boolean",
"description": "Specify whether the ConfigMap or it's keys must be defined"
}
}
},
"v1.Container": {
"id": "v1.Container",
"description": "A single application container that you want to run within a pod.",
......
......@@ -18604,6 +18604,10 @@
"photonPersistentDisk": {
"$ref": "v1.PhotonPersistentDiskVolumeSource",
"description": "PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine"
},
"projected": {
"$ref": "v1.ProjectedVolumeSource",
"description": "Items for all in one resources secrets, configmaps, and downward API"
}
}
},
......@@ -18812,6 +18816,100 @@
}
}
},
"v1.ProjectedVolumeSource": {
"id": "v1.ProjectedVolumeSource",
"description": "Represents a projected volume source",
"required": [
"sources"
],
"properties": {
"sources": {
"type": "array",
"items": {
"$ref": "v1.VolumeProjection"
},
"description": "list of volume projections"
},
"defaultMode": {
"type": "integer",
"format": "int32",
"description": "Mode bits to use on created files by default. Must be a value between 0 and 0777. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set."
}
}
},
"v1.VolumeProjection": {
"id": "v1.VolumeProjection",
"description": "Projection that may be projected along with other supported volume types",
"properties": {
"secret": {
"$ref": "v1.SecretProjection",
"description": "information about the secret data to project"
},
"downwardAPI": {
"$ref": "v1.DownwardAPIProjection",
"description": "information about the downwardAPI data to project"
},
"configMap": {
"$ref": "v1.ConfigMapProjection",
"description": "information about the configMap data to project"
}
}
},
"v1.SecretProjection": {
"id": "v1.SecretProjection",
"description": "Adapts a secret into a projected volume.\n\nThe contents of the target Secret's Data field will be presented in a projected volume as files using the keys in the Data field as the file names. Note that this is identical to a secret volume source without the default mode.",
"properties": {
"name": {
"type": "string",
"description": "Name of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#names"
},
"items": {
"type": "array",
"items": {
"$ref": "v1.KeyToPath"
},
"description": "If unspecified, each key-value pair in the Data field of the referenced Secret will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the Secret, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'."
},
"optional": {
"type": "boolean",
"description": "Specify whether the Secret or its key must be defined"
}
}
},
"v1.DownwardAPIProjection": {
"id": "v1.DownwardAPIProjection",
"description": "Represents downward API info for projecting into a projected volume. Note that this is identical to a downwardAPI volume source without the default mode.",
"properties": {
"items": {
"type": "array",
"items": {
"$ref": "v1.DownwardAPIVolumeFile"
},
"description": "Items is a list of DownwardAPIVolume file"
}
}
},
"v1.ConfigMapProjection": {
"id": "v1.ConfigMapProjection",
"description": "Adapts a ConfigMap into a projected volume.\n\nThe contents of the target ConfigMap's Data field will be presented in a projected volume as files using the keys in the Data field as the file names, unless the items element is populated with specific mappings of keys to paths. Note that this is identical to a configmap volume source without the default mode.",
"properties": {
"name": {
"type": "string",
"description": "Name of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#names"
},
"items": {
"type": "array",
"items": {
"$ref": "v1.KeyToPath"
},
"description": "If unspecified, each key-value pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the ConfigMap, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'."
},
"optional": {
"type": "boolean",
"description": "Specify whether the ConfigMap or it's keys must be defined"
}
}
},
"v1.Container": {
"id": "v1.Container",
"description": "A single application container that you want to run within a pod.",
......
......@@ -89,6 +89,7 @@ go_library(
"//pkg/volume/iscsi:go_default_library",
"//pkg/volume/nfs:go_default_library",
"//pkg/volume/photon_pd:go_default_library",
"//pkg/volume/projected:go_default_library",
"//pkg/volume/quobyte:go_default_library",
"//pkg/volume/rbd:go_default_library",
"//pkg/volume/secret:go_default_library",
......
......@@ -46,6 +46,7 @@ import (
"k8s.io/kubernetes/pkg/volume/iscsi"
"k8s.io/kubernetes/pkg/volume/nfs"
"k8s.io/kubernetes/pkg/volume/photon_pd"
"k8s.io/kubernetes/pkg/volume/projected"
"k8s.io/kubernetes/pkg/volume/quobyte"
"k8s.io/kubernetes/pkg/volume/rbd"
"k8s.io/kubernetes/pkg/volume/secret"
......@@ -88,6 +89,7 @@ func ProbeVolumePlugins(pluginDir string) []volume.VolumePlugin {
allPlugins = append(allPlugins, vsphere_volume.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, azure_dd.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, photon_pd.ProbeVolumePlugins()...)
allPlugins = append(allPlugins, projected.ProbeVolumePlugins()...)
return allPlugins
}
......
......@@ -11407,6 +11407,26 @@
}
]
},
"io.k8s.kubernetes.pkg.api.v1.ConfigMapProjection": {
"description": "Adapts a ConfigMap into a projected volume.\n\nThe contents of the target ConfigMap's Data field will be presented in a projected volume as files using the keys in the Data field as the file names, unless the items element is populated with specific mappings of keys to paths. Note that this is identical to a configmap volume source without the default mode.",
"properties": {
"items": {
"description": "If unspecified, each key-value pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the ConfigMap, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'.",
"type": "array",
"items": {
"$ref": "#/definitions/io.k8s.kubernetes.pkg.api.v1.KeyToPath"
}
},
"name": {
"description": "Name of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#names",
"type": "string"
},
"optional": {
"description": "Specify whether the ConfigMap or it's keys must be defined",
"type": "boolean"
}
}
},
"io.k8s.kubernetes.pkg.api.v1.ConfigMapVolumeSource": {
"description": "Adapts a ConfigMap into a volume.\n\nThe contents of the target ConfigMap's Data field will be presented in a volume as files using the keys in the Data field as the file names, unless the items element is populated with specific mappings of keys to paths. ConfigMap volumes support ownership management and SELinux relabeling.",
"properties": {
......@@ -11568,6 +11588,18 @@
}
}
},
"io.k8s.kubernetes.pkg.api.v1.DownwardAPIProjection": {
"description": "Represents downward API info for projecting into a projected volume. Note that this is identical to a downwardAPI volume source without the default mode.",
"properties": {
"items": {
"description": "Items is a list of DownwardAPIVolume file",
"type": "array",
"items": {
"$ref": "#/definitions/io.k8s.kubernetes.pkg.api.v1.DownwardAPIVolumeFile"
}
}
}
},
"io.k8s.kubernetes.pkg.api.v1.DownwardAPIVolumeFile": {
"description": "DownwardAPIVolumeFile represents information to create the file containing the pod field",
"required": [
......@@ -12657,6 +12689,26 @@
}
}
},
"io.k8s.kubernetes.pkg.api.v1.ProjectedVolumeSource": {
"description": "Represents a projected volume source",
"required": [
"sources"
],
"properties": {
"defaultMode": {
"description": "Mode bits to use on created files by default. Must be a value between 0 and 0777. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.",
"type": "integer",
"format": "int32"
},
"sources": {
"description": "list of volume projections",
"type": "array",
"items": {
"$ref": "#/definitions/io.k8s.kubernetes.pkg.api.v1.VolumeProjection"
}
}
}
},
"io.k8s.kubernetes.pkg.api.v1.QuobyteVolumeSource": {
"description": "Represents a Quobyte mount that lasts the lifetime of a pod. Quobyte volumes do not support ownership management or SELinux relabeling.",
"required": [
......@@ -12900,6 +12952,26 @@
}
]
},
"io.k8s.kubernetes.pkg.api.v1.SecretProjection": {
"description": "Adapts a secret into a projected volume.\n\nThe contents of the target Secret's Data field will be presented in a projected volume as files using the keys in the Data field as the file names. Note that this is identical to a secret volume source without the default mode.",
"properties": {
"items": {
"description": "If unspecified, each key-value pair in the Data field of the referenced Secret will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the Secret, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'.",
"type": "array",
"items": {
"$ref": "#/definitions/io.k8s.kubernetes.pkg.api.v1.KeyToPath"
}
},
"name": {
"description": "Name of the referent. More info: http://kubernetes.io/docs/user-guide/identifiers#names",
"type": "string"
},
"optional": {
"description": "Specify whether the Secret or its key must be defined",
"type": "boolean"
}
}
},
"io.k8s.kubernetes.pkg.api.v1.SecretVolumeSource": {
"description": "Adapts a Secret into a volume.\n\nThe contents of the target Secret's Data field will be presented in a volume as files using the keys in the Data field as the file names. Secret volumes support ownership management and SELinux relabeling.",
"properties": {
......@@ -13218,6 +13290,10 @@
"description": "PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine",
"$ref": "#/definitions/io.k8s.kubernetes.pkg.api.v1.PhotonPersistentDiskVolumeSource"
},
"projected": {
"description": "Items for all in one resources secrets, configmaps, and downward API",
"$ref": "#/definitions/io.k8s.kubernetes.pkg.api.v1.ProjectedVolumeSource"
},
"quobyte": {
"description": "Quobyte represents a Quobyte mount on the host that shares a pod's lifetime",
"$ref": "#/definitions/io.k8s.kubernetes.pkg.api.v1.QuobyteVolumeSource"
......@@ -13261,6 +13337,23 @@
}
}
},
"io.k8s.kubernetes.pkg.api.v1.VolumeProjection": {
"description": "Projection that may be projected along with other supported volume types",
"properties": {
"configMap": {
"description": "information about the configMap data to project",
"$ref": "#/definitions/io.k8s.kubernetes.pkg.api.v1.ConfigMapProjection"
},
"downwardAPI": {
"description": "information about the downwardAPI data to project",
"$ref": "#/definitions/io.k8s.kubernetes.pkg.api.v1.DownwardAPIProjection"
},
"secret": {
"description": "information about the secret data to project",
"$ref": "#/definitions/io.k8s.kubernetes.pkg.api.v1.SecretProjection"
}
}
},
"io.k8s.kubernetes.pkg.api.v1.VsphereVirtualDiskVolumeSource": {
"description": "Represents a vSphere volume resource.",
"required": [
......
......@@ -243,6 +243,7 @@ pkg/util/yaml
pkg/version/prometheus
pkg/volume
pkg/volume/downwardapi
pkg/volume/projected
pkg/volume/quobyte
pkg/volume/util/nestedpendingoperations
pkg/volume/util/operationexecutor
......
......@@ -147,6 +147,14 @@ test/e2e/common/host_path.go: fmt.Sprintf("--file_content_in_loop=%v", filePat
test/e2e/common/host_path.go: fmt.Sprintf("--file_content_in_loop=%v", filePathInReader),
test/e2e/common/host_path.go: fmt.Sprintf("--retry_time=%d", retryDuration),
test/e2e/common/host_path.go: fmt.Sprintf("--retry_time=%d", retryDuration),
test/e2e/common/projected.go: Command: []string{"/mt", "--break_on_expected_content=false", "--retry_time=120", "--file_content_in_loop=/etc/projected-configmap-volume/data-1"},
test/e2e/common/projected.go: Command: []string{"/mt", "--break_on_expected_content=false", "--retry_time=120", "--file_content_in_loop=/etc/projected-configmap-volumes/create/data-1"},
test/e2e/common/projected.go: Command: []string{"/mt", "--break_on_expected_content=false", "--retry_time=120", "--file_content_in_loop=/etc/projected-configmap-volumes/delete/data-1"},
test/e2e/common/projected.go: Command: []string{"/mt", "--break_on_expected_content=false", "--retry_time=120", "--file_content_in_loop=/etc/projected-configmap-volumes/update/data-3"},
test/e2e/common/projected.go: Command: []string{"/mt", "--break_on_expected_content=false", "--retry_time=120", "--file_content_in_loop=/etc/projected-secret-volumes/create/data-1"},
test/e2e/common/projected.go: Command: []string{"/mt", "--break_on_expected_content=false", "--retry_time=120", "--file_content_in_loop=/etc/projected-secret-volumes/delete/data-1"},
test/e2e/common/projected.go: Command: []string{"/mt", "--break_on_expected_content=false", "--retry_time=120", "--file_content_in_loop=/etc/projected-secret-volumes/update/data-3"},
test/e2e/common/projected.go: Command: []string{"/mt", "--break_on_expected_content=false", "--retry_time=120", "--file_content_in_loop=" + filePath},
test/e2e/common/secrets.go: Command: []string{"/mt", "--break_on_expected_content=false", "--retry_time=120", "--file_content_in_loop=/etc/secret-volumes/create/data-1"},
test/e2e/common/secrets.go: Command: []string{"/mt", "--break_on_expected_content=false", "--retry_time=120", "--file_content_in_loop=/etc/secret-volumes/delete/data-1"},
test/e2e/common/secrets.go: Command: []string{"/mt", "--break_on_expected_content=false", "--retry_time=120", "--file_content_in_loop=/etc/secret-volumes/update/data-3"},
......
......@@ -267,6 +267,16 @@ func coreFuncs(t apitesting.TestingCommon) []interface{} {
mode &= 0777
d.DefaultMode = &mode
},
func(s *api.ProjectedVolumeSource, c fuzz.Continue) {
c.FuzzNoCustom(s) // fuzz self without calling this function again
// DefaultMode should always be set, it has a default
// value and it is expected to be between 0 and 0777
var mode int32
c.Fuzz(&mode)
mode &= 0777
s.DefaultMode = &mode
},
func(k *api.KeyToPath, c fuzz.Continue) {
c.FuzzNoCustom(k) // fuzz self without calling this function again
k.Key = c.RandString()
......
......@@ -294,6 +294,8 @@ type VolumeSource struct {
AzureDisk *AzureDiskVolumeSource
// PhotonPersistentDisk represents a Photon Controller persistent disk attached and mounted on kubelets host machine
PhotonPersistentDisk *PhotonPersistentDiskVolumeSource
// Items for all in one resources secrets, configmaps, and downward API
Projected *ProjectedVolumeSource
}
// Similar to VolumeSource but meant for the administrator who creates PVs.
......@@ -746,7 +748,29 @@ type SecretVolumeSource struct {
// mode, like fsGroup, and the result can be other mode bits set.
// +optional
DefaultMode *int32
// Specify whether the Secret or it's key must be defined
// Specify whether the Secret or its key must be defined
// +optional
Optional *bool
}
// Adapts a secret into a projected volume.
//
// The contents of the target Secret's Data field will be presented in a
// projected volume as files using the keys in the Data field as the file names.
// Note that this is identical to a secret volume source without the default
// mode.
type SecretProjection struct {
LocalObjectReference
// If unspecified, each key-value pair in the Data field of the referenced
// Secret will be projected into the volume as a file whose name is the
// key and content is the value. If specified, the listed keys will be
// projected into the specified paths, and unlisted keys will not be
// present. If a key is specified which is not present in the Secret,
// the volume setup will error unless it is marked optional. Paths must be
// relative and may not contain the '..' path or start with '..'.
// +optional
Items []KeyToPath
// Specify whether the Secret or its key must be defined
// +optional
Optional *bool
}
......@@ -927,6 +951,15 @@ type DownwardAPIVolumeFile struct {
Mode *int32
}
// Represents downward API info for projecting into a projected volume.
// Note that this is identical to a downwardAPI volume source without the default
// mode.
type DownwardAPIProjection struct {
// Items is a list of DownwardAPIVolume file
// +optional
Items []DownwardAPIVolumeFile
}
// AzureFile represents an Azure File Service mount on the host and bind mount to the pod.
type AzureFileVolumeSource struct {
// the name of secret that contains Azure Storage Account Name and Key
......@@ -1017,6 +1050,54 @@ type ConfigMapVolumeSource struct {
Optional *bool
}
// Adapts a ConfigMap into a projected volume.
//
// The contents of the target ConfigMap's Data field will be presented in a
// projected volume as files using the keys in the Data field as the file names,
// unless the items element is populated with specific mappings of keys to paths.
// Note that this is identical to a configmap volume source without the default
// mode.
type ConfigMapProjection struct {
LocalObjectReference
// If unspecified, each key-value pair in the Data field of the referenced
// ConfigMap will be projected into the volume as a file whose name is the
// key and content is the value. If specified, the listed keys will be
// projected into the specified paths, and unlisted keys will not be
// present. If a key is specified which is not present in the ConfigMap,
// the volume setup will error unless it is marked optional. Paths must be
// relative and may not contain the '..' path or start with '..'.
// +optional
Items []KeyToPath
// Specify whether the ConfigMap or it's keys must be defined
// +optional
Optional *bool
}
// Represents a projected volume source
type ProjectedVolumeSource struct {
// list of volume projections
Sources []VolumeProjection
// Mode bits to use on created files by default. Must be a value between
// 0 and 0777.
// Directories within the path are not affected by this setting.
// This might be in conflict with other options that affect the file
// mode, like fsGroup, and the result can be other mode bits set.
// +optional
DefaultMode *int32
}
// Projection that may be projected along with other supported volume types
type VolumeProjection struct {
// all types below are the supported types for projection into the same volume
// information about the secret data to project
Secret *SecretProjection
// information about the downwardAPI data to project
DownwardAPI *DownwardAPIProjection
// information about the configMap data to project
ConfigMap *ConfigMapProjection
}
// Maps a string key to a path within a volume.
type KeyToPath struct {
// The key to project.
......
......@@ -39,6 +39,7 @@ func addDefaultingFuncs(scheme *runtime.Scheme) error {
SetDefaults_SecretVolumeSource,
SetDefaults_ConfigMapVolumeSource,
SetDefaults_DownwardAPIVolumeSource,
SetDefaults_ProjectedVolumeSource,
SetDefaults_Secret,
SetDefaults_PersistentVolume,
SetDefaults_PersistentVolumeClaim,
......@@ -218,6 +219,12 @@ func SetDefaults_Secret(obj *Secret) {
obj.Type = SecretTypeOpaque
}
}
func SetDefaults_ProjectedVolumeSource(obj *ProjectedVolumeSource) {
if obj.DefaultMode == nil {
perm := int32(ProjectedVolumeSourceDefaultMode)
obj.DefaultMode = &perm
}
}
func SetDefaults_PersistentVolume(obj *PersistentVolume) {
if obj.Status.Phase == "" {
obj.Status.Phase = VolumePending
......
......@@ -376,6 +376,28 @@ func TestSetDefaultDownwardAPIVolumeSource(t *testing.T) {
}
}
func TestSetDefaultProjectedVolumeSource(t *testing.T) {
s := v1.PodSpec{}
s.Volumes = []v1.Volume{
{
VolumeSource: v1.VolumeSource{
Projected: &v1.ProjectedVolumeSource{},
},
},
}
pod := &v1.Pod{
Spec: s,
}
output := roundTrip(t, runtime.Object(pod))
pod2 := output.(*v1.Pod)
defaultMode := pod2.Spec.Volumes[0].VolumeSource.Projected.DefaultMode
expectedMode := v1.ProjectedVolumeSourceDefaultMode
if defaultMode == nil || *defaultMode != expectedMode {
t.Errorf("Expected ProjectedVolumeSource DefaultMode %v, got %v", expectedMode, defaultMode)
}
}
func TestSetDefaultSecret(t *testing.T) {
s := &v1.Secret{}
obj2 := roundTrip(t, runtime.Object(s))
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -309,6 +309,31 @@ message ConfigMapList {
repeated ConfigMap items = 2;
}
// Adapts a ConfigMap into a projected volume.
//
// The contents of the target ConfigMap's Data field will be presented in a
// projected volume as files using the keys in the Data field as the file names,
// unless the items element is populated with specific mappings of keys to paths.
// Note that this is identical to a configmap volume source without the default
// mode.
message ConfigMapProjection {
optional LocalObjectReference localObjectReference = 1;
// If unspecified, each key-value pair in the Data field of the referenced
// ConfigMap will be projected into the volume as a file whose name is the
// key and content is the value. If specified, the listed keys will be
// projected into the specified paths, and unlisted keys will not be
// present. If a key is specified which is not present in the ConfigMap,
// the volume setup will error unless it is marked optional. Paths must be
// relative and may not contain the '..' path or start with '..'.
// +optional
repeated KeyToPath items = 2;
// Specify whether the ConfigMap or it's keys must be defined
// +optional
optional bool optional = 4;
}
// Adapts a ConfigMap into a volume.
//
// The contents of the target ConfigMap's Data field will be presented in a
......@@ -661,6 +686,15 @@ message DeleteOptions {
optional bool orphanDependents = 3;
}
// Represents downward API info for projecting into a projected volume.
// Note that this is identical to a downwardAPI volume source without the default
// mode.
message DownwardAPIProjection {
// Items is a list of DownwardAPIVolume file
// +optional
repeated DownwardAPIVolumeFile items = 1;
}
// DownwardAPIVolumeFile represents information to create the file containing the pod field
message DownwardAPIVolumeFile {
// Required: Path is the relative path name of the file to be created. Must not be absolute or contain the '..' path. Must be utf-8 encoded. The first item of the relative path must not start with '..'
......@@ -2807,6 +2841,20 @@ message Probe {
optional int32 failureThreshold = 6;
}
// Represents a projected volume source
message ProjectedVolumeSource {
// list of volume projections
repeated VolumeProjection sources = 1;
// Mode bits to use on created files by default. Must be a value between
// 0 and 0777.
// Directories within the path are not affected by this setting.
// This might be in conflict with other options that affect the file
// mode, like fsGroup, and the result can be other mode bits set.
// +optional
optional int32 defaultMode = 2;
}
// Represents a Quobyte mount that lasts the lifetime of a pod.
// Quobyte volumes do not support ownership management or SELinux relabeling.
message QuobyteVolumeSource {
......@@ -3183,6 +3231,30 @@ message SecretList {
repeated Secret items = 2;
}
// Adapts a secret into a projected volume.
//
// The contents of the target Secret's Data field will be presented in a
// projected volume as files using the keys in the Data field as the file names.
// Note that this is identical to a secret volume source without the default
// mode.
message SecretProjection {
optional LocalObjectReference localObjectReference = 1;
// If unspecified, each key-value pair in the Data field of the referenced
// Secret will be projected into the volume as a file whose name is the
// key and content is the value. If specified, the listed keys will be
// projected into the specified paths, and unlisted keys will not be
// present. If a key is specified which is not present in the Secret,
// the volume setup will error unless it is marked optional. Paths must be
// relative and may not contain the '..' path or start with '..'.
// +optional
repeated KeyToPath items = 2;
// Specify whether the Secret or its key must be defined
// +optional
optional bool optional = 4;
}
// Adapts a Secret into a volume.
//
// The contents of the target Secret's Data field will be presented in a volume
......@@ -3591,6 +3663,18 @@ message VolumeMount {
optional string subPath = 4;
}
// Projection that may be projected along with other supported volume types
message VolumeProjection {
// information about the secret data to project
optional SecretProjection secret = 1;
// information about the downwardAPI data to project
optional DownwardAPIProjection downwardAPI = 2;
// information about the configMap data to project
optional ConfigMapProjection configMap = 3;
}
// Represents the source of a volume to mount.
// Only one of its members may be specified.
message VolumeSource {
......@@ -3707,6 +3791,9 @@ message VolumeSource {
// PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine
optional PhotonPersistentDiskVolumeSource photonPersistentDisk = 23;
// Items for all in one resources secrets, configmaps, and downward API
optional ProjectedVolumeSource projected = 24;
}
// Represents a vSphere volume resource.
......
......@@ -326,6 +326,8 @@ type VolumeSource struct {
AzureDisk *AzureDiskVolumeSource `json:"azureDisk,omitempty" protobuf:"bytes,22,opt,name=azureDisk"`
// PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine
PhotonPersistentDisk *PhotonPersistentDiskVolumeSource `json:"photonPersistentDisk,omitempty" protobuf:"bytes,23,opt,name=photonPersistentDisk"`
// Items for all in one resources secrets, configmaps, and downward API
Projected *ProjectedVolumeSource `json:"projected,omitempty"`
}
// PersistentVolumeClaimVolumeSource references the user's PVC in the same namespace.
......@@ -944,6 +946,28 @@ const (
SecretVolumeSourceDefaultMode int32 = 0644
)
// Adapts a secret into a projected volume.
//
// The contents of the target Secret's Data field will be presented in a
// projected volume as files using the keys in the Data field as the file names.
// Note that this is identical to a secret volume source without the default
// mode.
type SecretProjection struct {
LocalObjectReference `json:",inline" protobuf:"bytes,1,opt,name=localObjectReference"`
// If unspecified, each key-value pair in the Data field of the referenced
// Secret will be projected into the volume as a file whose name is the
// key and content is the value. If specified, the listed keys will be
// projected into the specified paths, and unlisted keys will not be
// present. If a key is specified which is not present in the Secret,
// the volume setup will error unless it is marked optional. Paths must be
// relative and may not contain the '..' path or start with '..'.
// +optional
Items []KeyToPath `json:"items,omitempty" protobuf:"bytes,2,rep,name=items"`
// Specify whether the Secret or its key must be defined
// +optional
Optional *bool `json:"optional,omitempty" protobuf:"varint,4,opt,name=optional"`
}
// Represents an NFS mount that lasts the lifetime of a pod.
// NFS volumes do not support ownership management or SELinux relabeling.
type NFSVolumeSource struct {
......@@ -1108,6 +1132,58 @@ const (
ConfigMapVolumeSourceDefaultMode int32 = 0644
)
// Adapts a ConfigMap into a projected volume.
//
// The contents of the target ConfigMap's Data field will be presented in a
// projected volume as files using the keys in the Data field as the file names,
// unless the items element is populated with specific mappings of keys to paths.
// Note that this is identical to a configmap volume source without the default
// mode.
type ConfigMapProjection struct {
LocalObjectReference `json:",inline" protobuf:"bytes,1,opt,name=localObjectReference"`
// If unspecified, each key-value pair in the Data field of the referenced
// ConfigMap will be projected into the volume as a file whose name is the
// key and content is the value. If specified, the listed keys will be
// projected into the specified paths, and unlisted keys will not be
// present. If a key is specified which is not present in the ConfigMap,
// the volume setup will error unless it is marked optional. Paths must be
// relative and may not contain the '..' path or start with '..'.
// +optional
Items []KeyToPath `json:"items,omitempty" protobuf:"bytes,2,rep,name=items"`
// Specify whether the ConfigMap or it's keys must be defined
// +optional
Optional *bool `json:"optional,omitempty" protobuf:"varint,4,opt,name=optional"`
}
// Represents a projected volume source
type ProjectedVolumeSource struct {
// list of volume projections
Sources []VolumeProjection `json:"sources"`
// Mode bits to use on created files by default. Must be a value between
// 0 and 0777.
// Directories within the path are not affected by this setting.
// This might be in conflict with other options that affect the file
// mode, like fsGroup, and the result can be other mode bits set.
// +optional
DefaultMode *int32 `json:"defaultMode,omitempty"`
}
// Projection that may be projected along with other supported volume types
type VolumeProjection struct {
// all types below are the supported types for projection into the same volume
// information about the secret data to project
Secret *SecretProjection `json:"secret,omitempty"`
// information about the downwardAPI data to project
DownwardAPI *DownwardAPIProjection `json:"downwardAPI,omitempty"`
// information about the configMap data to project
ConfigMap *ConfigMapProjection `json:"configMap,omitempty"`
}
const (
ProjectedVolumeSourceDefaultMode int32 = 0644
)
// Maps a string key to a path within a volume.
type KeyToPath struct {
// The key to project.
......@@ -4097,6 +4173,15 @@ type DownwardAPIVolumeFile struct {
Mode *int32 `json:"mode,omitempty" protobuf:"varint,4,opt,name=mode"`
}
// Represents downward API info for projecting into a projected volume.
// Note that this is identical to a downwardAPI volume source without the default
// mode.
type DownwardAPIProjection struct {
// Items is a list of DownwardAPIVolume file
// +optional
Items []DownwardAPIVolumeFile `json:"items,omitempty" protobuf:"bytes,1,rep,name=items"`
}
// SecurityContext holds security configuration that will be applied to a container.
// Some fields are present in both SecurityContext and PodSecurityContext. When both
// are set, the values in SecurityContext take precedence.
......
......@@ -209,6 +209,16 @@ func (ConfigMapList) SwaggerDoc() map[string]string {
return map_ConfigMapList
}
var map_ConfigMapProjection = map[string]string{
"": "Adapts a ConfigMap into a projected volume.\n\nThe contents of the target ConfigMap's Data field will be presented in a projected volume as files using the keys in the Data field as the file names, unless the items element is populated with specific mappings of keys to paths. Note that this is identical to a configmap volume source without the default mode.",
"items": "If unspecified, each key-value pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the ConfigMap, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'.",
"optional": "Specify whether the ConfigMap or it's keys must be defined",
}
func (ConfigMapProjection) SwaggerDoc() map[string]string {
return map_ConfigMapProjection
}
var map_ConfigMapVolumeSource = map[string]string{
"": "Adapts a ConfigMap into a volume.\n\nThe contents of the target ConfigMap's Data field will be presented in a volume as files using the keys in the Data field as the file names, unless the items element is populated with specific mappings of keys to paths. ConfigMap volumes support ownership management and SELinux relabeling.",
"items": "If unspecified, each key-value pair in the Data field of the referenced ConfigMap will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the ConfigMap, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'.",
......@@ -352,6 +362,15 @@ func (DeleteOptions) SwaggerDoc() map[string]string {
return map_DeleteOptions
}
var map_DownwardAPIProjection = map[string]string{
"": "Represents downward API info for projecting into a projected volume. Note that this is identical to a downwardAPI volume source without the default mode.",
"items": "Items is a list of DownwardAPIVolume file",
}
func (DownwardAPIProjection) SwaggerDoc() map[string]string {
return map_DownwardAPIProjection
}
var map_DownwardAPIVolumeFile = map[string]string{
"": "DownwardAPIVolumeFile represents information to create the file containing the pod field",
"path": "Required: Path is the relative path name of the file to be created. Must not be absolute or contain the '..' path. Must be utf-8 encoded. The first item of the relative path must not start with '..'",
......@@ -1420,6 +1439,16 @@ func (Probe) SwaggerDoc() map[string]string {
return map_Probe
}
var map_ProjectedVolumeSource = map[string]string{
"": "Represents a projected volume source",
"sources": "list of volume projections",
"defaultMode": "Mode bits to use on created files by default. Must be a value between 0 and 0777. Directories within the path are not affected by this setting. This might be in conflict with other options that affect the file mode, like fsGroup, and the result can be other mode bits set.",
}
func (ProjectedVolumeSource) SwaggerDoc() map[string]string {
return map_ProjectedVolumeSource
}
var map_QuobyteVolumeSource = map[string]string{
"": "Represents a Quobyte mount that lasts the lifetime of a pod. Quobyte volumes do not support ownership management or SELinux relabeling.",
"registry": "Registry represents a single or multiple Quobyte Registry services specified as a string as host:port pair (multiple entries are separated with commas) which acts as the central registry for volumes",
......@@ -1635,6 +1664,16 @@ func (SecretList) SwaggerDoc() map[string]string {
return map_SecretList
}
var map_SecretProjection = map[string]string{
"": "Adapts a secret into a projected volume.\n\nThe contents of the target Secret's Data field will be presented in a projected volume as files using the keys in the Data field as the file names. Note that this is identical to a secret volume source without the default mode.",
"items": "If unspecified, each key-value pair in the Data field of the referenced Secret will be projected into the volume as a file whose name is the key and content is the value. If specified, the listed keys will be projected into the specified paths, and unlisted keys will not be present. If a key is specified which is not present in the Secret, the volume setup will error unless it is marked optional. Paths must be relative and may not contain the '..' path or start with '..'.",
"optional": "Specify whether the Secret or its key must be defined",
}
func (SecretProjection) SwaggerDoc() map[string]string {
return map_SecretProjection
}
var map_SecretVolumeSource = map[string]string{
"": "Adapts a Secret into a volume.\n\nThe contents of the target Secret's Data field will be presented in a volume as files using the keys in the Data field as the file names. Secret volumes support ownership management and SELinux relabeling.",
"secretName": "Name of the secret in the pod's namespace to use. More info: http://kubernetes.io/docs/user-guide/volumes#secrets",
......@@ -1817,6 +1856,17 @@ func (VolumeMount) SwaggerDoc() map[string]string {
return map_VolumeMount
}
var map_VolumeProjection = map[string]string{
"": "Projection that may be projected along with other supported volume types",
"secret": "information about the secret data to project",
"downwardAPI": "information about the downwardAPI data to project",
"configMap": "information about the configMap data to project",
}
func (VolumeProjection) SwaggerDoc() map[string]string {
return map_VolumeProjection
}
var map_VolumeSource = map[string]string{
"": "Represents the source of a volume to mount. Only one of its members may be specified.",
"hostPath": "HostPath represents a pre-existing file or directory on the host machine that is directly exposed to the container. This is generally used for system agents or other privileged things that are allowed to see the host machine. Most containers will NOT need this. More info: http://kubernetes.io/docs/user-guide/volumes#hostpath",
......@@ -1842,6 +1892,7 @@ var map_VolumeSource = map[string]string{
"quobyte": "Quobyte represents a Quobyte mount on the host that shares a pod's lifetime",
"azureDisk": "AzureDisk represents an Azure Data Disk mount on the host and bind mount to the pod.",
"photonPersistentDisk": "PhotonPersistentDisk represents a PhotonController persistent disk attached and mounted on kubelets host machine",
"projected": "Items for all in one resources secrets, configmaps, and downward API",
}
func (VolumeSource) SwaggerDoc() map[string]string {
......
......@@ -53,6 +53,7 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_ConfigMapEnvSource, InType: reflect.TypeOf(&ConfigMapEnvSource{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_ConfigMapKeySelector, InType: reflect.TypeOf(&ConfigMapKeySelector{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_ConfigMapList, InType: reflect.TypeOf(&ConfigMapList{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_ConfigMapProjection, InType: reflect.TypeOf(&ConfigMapProjection{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_ConfigMapVolumeSource, InType: reflect.TypeOf(&ConfigMapVolumeSource{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_Container, InType: reflect.TypeOf(&Container{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_ContainerImage, InType: reflect.TypeOf(&ContainerImage{})},
......@@ -64,6 +65,7 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_ContainerStatus, InType: reflect.TypeOf(&ContainerStatus{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_DaemonEndpoint, InType: reflect.TypeOf(&DaemonEndpoint{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_DeleteOptions, InType: reflect.TypeOf(&DeleteOptions{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_DownwardAPIProjection, InType: reflect.TypeOf(&DownwardAPIProjection{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_DownwardAPIVolumeFile, InType: reflect.TypeOf(&DownwardAPIVolumeFile{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_DownwardAPIVolumeSource, InType: reflect.TypeOf(&DownwardAPIVolumeSource{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_EmptyDirVolumeSource, InType: reflect.TypeOf(&EmptyDirVolumeSource{})},
......@@ -157,6 +159,7 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_PreferAvoidPodsEntry, InType: reflect.TypeOf(&PreferAvoidPodsEntry{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_PreferredSchedulingTerm, InType: reflect.TypeOf(&PreferredSchedulingTerm{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_Probe, InType: reflect.TypeOf(&Probe{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_ProjectedVolumeSource, InType: reflect.TypeOf(&ProjectedVolumeSource{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_QuobyteVolumeSource, InType: reflect.TypeOf(&QuobyteVolumeSource{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_RBDVolumeSource, InType: reflect.TypeOf(&RBDVolumeSource{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_RangeAllocation, InType: reflect.TypeOf(&RangeAllocation{})},
......@@ -176,6 +179,7 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_SecretEnvSource, InType: reflect.TypeOf(&SecretEnvSource{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_SecretKeySelector, InType: reflect.TypeOf(&SecretKeySelector{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_SecretList, InType: reflect.TypeOf(&SecretList{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_SecretProjection, InType: reflect.TypeOf(&SecretProjection{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_SecretVolumeSource, InType: reflect.TypeOf(&SecretVolumeSource{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_SecurityContext, InType: reflect.TypeOf(&SecurityContext{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_SerializedReference, InType: reflect.TypeOf(&SerializedReference{})},
......@@ -193,6 +197,7 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_Toleration, InType: reflect.TypeOf(&Toleration{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_Volume, InType: reflect.TypeOf(&Volume{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_VolumeMount, InType: reflect.TypeOf(&VolumeMount{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_VolumeProjection, InType: reflect.TypeOf(&VolumeProjection{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_VolumeSource, InType: reflect.TypeOf(&VolumeSource{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_VsphereVirtualDiskVolumeSource, InType: reflect.TypeOf(&VsphereVirtualDiskVolumeSource{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_WeightedPodAffinityTerm, InType: reflect.TypeOf(&WeightedPodAffinityTerm{})},
......@@ -472,6 +477,29 @@ func DeepCopy_v1_ConfigMapList(in interface{}, out interface{}, c *conversion.Cl
}
}
func DeepCopy_v1_ConfigMapProjection(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*ConfigMapProjection)
out := out.(*ConfigMapProjection)
*out = *in
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]KeyToPath, len(*in))
for i := range *in {
if err := DeepCopy_v1_KeyToPath(&(*in)[i], &(*out)[i], c); err != nil {
return err
}
}
}
if in.Optional != nil {
in, out := &in.Optional, &out.Optional
*out = new(bool)
**out = **in
}
return nil
}
}
func DeepCopy_v1_ConfigMapVolumeSource(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*ConfigMapVolumeSource)
......@@ -709,6 +737,24 @@ func DeepCopy_v1_DeleteOptions(in interface{}, out interface{}, c *conversion.Cl
}
}
func DeepCopy_v1_DownwardAPIProjection(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*DownwardAPIProjection)
out := out.(*DownwardAPIProjection)
*out = *in
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]DownwardAPIVolumeFile, len(*in))
for i := range *in {
if err := DeepCopy_v1_DownwardAPIVolumeFile(&(*in)[i], &(*out)[i], c); err != nil {
return err
}
}
}
return nil
}
}
func DeepCopy_v1_DownwardAPIVolumeFile(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*DownwardAPIVolumeFile)
......@@ -2492,6 +2538,29 @@ func DeepCopy_v1_Probe(in interface{}, out interface{}, c *conversion.Cloner) er
}
}
func DeepCopy_v1_ProjectedVolumeSource(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*ProjectedVolumeSource)
out := out.(*ProjectedVolumeSource)
*out = *in
if in.Sources != nil {
in, out := &in.Sources, &out.Sources
*out = make([]VolumeProjection, len(*in))
for i := range *in {
if err := DeepCopy_v1_VolumeProjection(&(*in)[i], &(*out)[i], c); err != nil {
return err
}
}
}
if in.DefaultMode != nil {
in, out := &in.DefaultMode, &out.DefaultMode
*out = new(int32)
**out = **in
}
return nil
}
}
func DeepCopy_v1_QuobyteVolumeSource(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*QuobyteVolumeSource)
......@@ -2835,6 +2904,29 @@ func DeepCopy_v1_SecretList(in interface{}, out interface{}, c *conversion.Clone
}
}
func DeepCopy_v1_SecretProjection(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*SecretProjection)
out := out.(*SecretProjection)
*out = *in
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]KeyToPath, len(*in))
for i := range *in {
if err := DeepCopy_v1_KeyToPath(&(*in)[i], &(*out)[i], c); err != nil {
return err
}
}
}
if in.Optional != nil {
in, out := &in.Optional, &out.Optional
*out = new(bool)
**out = **in
}
return nil
}
}
func DeepCopy_v1_SecretVolumeSource(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*SecretVolumeSource)
......@@ -3127,6 +3219,36 @@ func DeepCopy_v1_VolumeMount(in interface{}, out interface{}, c *conversion.Clon
}
}
func DeepCopy_v1_VolumeProjection(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*VolumeProjection)
out := out.(*VolumeProjection)
*out = *in
if in.Secret != nil {
in, out := &in.Secret, &out.Secret
*out = new(SecretProjection)
if err := DeepCopy_v1_SecretProjection(*in, *out, c); err != nil {
return err
}
}
if in.DownwardAPI != nil {
in, out := &in.DownwardAPI, &out.DownwardAPI
*out = new(DownwardAPIProjection)
if err := DeepCopy_v1_DownwardAPIProjection(*in, *out, c); err != nil {
return err
}
}
if in.ConfigMap != nil {
in, out := &in.ConfigMap, &out.ConfigMap
*out = new(ConfigMapProjection)
if err := DeepCopy_v1_ConfigMapProjection(*in, *out, c); err != nil {
return err
}
}
return nil
}
}
func DeepCopy_v1_VolumeSource(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*VolumeSource)
......@@ -3265,6 +3387,13 @@ func DeepCopy_v1_VolumeSource(in interface{}, out interface{}, c *conversion.Clo
*out = new(PhotonPersistentDiskVolumeSource)
**out = **in
}
if in.Projected != nil {
in, out := &in.Projected, &out.Projected
*out = new(ProjectedVolumeSource)
if err := DeepCopy_v1_ProjectedVolumeSource(*in, *out, c); err != nil {
return err
}
}
return nil
}
}
......
......@@ -190,6 +190,20 @@ func SetObjectDefaults_Pod(in *Pod) {
if a.VolumeSource.AzureDisk != nil {
SetDefaults_AzureDiskVolumeSource(a.VolumeSource.AzureDisk)
}
if a.VolumeSource.Projected != nil {
SetDefaults_ProjectedVolumeSource(a.VolumeSource.Projected)
for j := range a.VolumeSource.Projected.Sources {
b := &a.VolumeSource.Projected.Sources[j]
if b.DownwardAPI != nil {
for k := range b.DownwardAPI.Items {
c := &b.DownwardAPI.Items[k]
if c.FieldRef != nil {
SetDefaults_ObjectFieldSelector(c.FieldRef)
}
}
}
}
}
}
for i := range in.Spec.InitContainers {
a := &in.Spec.InitContainers[i]
......@@ -321,6 +335,20 @@ func SetObjectDefaults_PodTemplate(in *PodTemplate) {
if a.VolumeSource.AzureDisk != nil {
SetDefaults_AzureDiskVolumeSource(a.VolumeSource.AzureDisk)
}
if a.VolumeSource.Projected != nil {
SetDefaults_ProjectedVolumeSource(a.VolumeSource.Projected)
for j := range a.VolumeSource.Projected.Sources {
b := &a.VolumeSource.Projected.Sources[j]
if b.DownwardAPI != nil {
for k := range b.DownwardAPI.Items {
c := &b.DownwardAPI.Items[k]
if c.FieldRef != nil {
SetDefaults_ObjectFieldSelector(c.FieldRef)
}
}
}
}
}
}
for i := range in.Template.Spec.InitContainers {
a := &in.Template.Spec.InitContainers[i]
......@@ -446,6 +474,20 @@ func SetObjectDefaults_ReplicationController(in *ReplicationController) {
if a.VolumeSource.AzureDisk != nil {
SetDefaults_AzureDiskVolumeSource(a.VolumeSource.AzureDisk)
}
if a.VolumeSource.Projected != nil {
SetDefaults_ProjectedVolumeSource(a.VolumeSource.Projected)
for j := range a.VolumeSource.Projected.Sources {
b := &a.VolumeSource.Projected.Sources[j]
if b.DownwardAPI != nil {
for k := range b.DownwardAPI.Items {
c := &b.DownwardAPI.Items[k]
if c.FieldRef != nil {
SetDefaults_ObjectFieldSelector(c.FieldRef)
}
}
}
}
}
}
for i := range in.Spec.Template.Spec.InitContainers {
a := &in.Spec.Template.Spec.InitContainers[i]
......
......@@ -518,6 +518,14 @@ func validateVolumeSource(source *api.VolumeSource, fldPath *field.Path) field.E
numVolumes++
allErrs = append(allErrs, validateAzureDisk(source.AzureDisk, fldPath.Child("azureDisk"))...)
}
if source.Projected != nil {
if numVolumes > 0 {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("projected"), "may not specify more than 1 volume type"))
} else {
numVolumes++
allErrs = append(allErrs, validateProjectedVolumeSource(source.Projected, fldPath.Child("projected"))...)
}
}
if numVolumes == 0 {
allErrs = append(allErrs, field.Required(fldPath, "must specify a volume type"))
......@@ -723,6 +731,30 @@ var validDownwardAPIFieldPathExpressions = sets.NewString(
"metadata.labels",
"metadata.annotations")
func validateDownwardAPIVolumeFile(file *api.DownwardAPIVolumeFile, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
if len(file.Path) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("path"), ""))
}
allErrs = append(allErrs, validateLocalNonReservedPath(file.Path, fldPath.Child("path"))...)
if file.FieldRef != nil {
allErrs = append(allErrs, validateObjectFieldSelector(file.FieldRef, &validDownwardAPIFieldPathExpressions, fldPath.Child("fieldRef"))...)
if file.ResourceFieldRef != nil {
allErrs = append(allErrs, field.Invalid(fldPath, "resource", "fieldRef and resourceFieldRef can not be specified simultaneously"))
}
} else if file.ResourceFieldRef != nil {
allErrs = append(allErrs, validateContainerResourceFieldSelector(file.ResourceFieldRef, &validContainerResourceFieldPathExpressions, fldPath.Child("resourceFieldRef"), true)...)
} else {
allErrs = append(allErrs, field.Required(fldPath, "one of fieldRef and resourceFieldRef is required"))
}
if file.Mode != nil && (*file.Mode > 0777 || *file.Mode < 0) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("mode"), *file.Mode, volumeModeErrorMsg))
}
return allErrs
}
func validateDownwardAPIVolumeSource(downwardAPIVolume *api.DownwardAPIVolumeSource, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
......@@ -732,24 +764,96 @@ func validateDownwardAPIVolumeSource(downwardAPIVolume *api.DownwardAPIVolumeSou
}
for _, file := range downwardAPIVolume.Items {
if len(file.Path) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("path"), ""))
}
allErrs = append(allErrs, validateLocalNonReservedPath(file.Path, fldPath.Child("path"))...)
if file.FieldRef != nil {
allErrs = append(allErrs, validateObjectFieldSelector(file.FieldRef, &validDownwardAPIFieldPathExpressions, fldPath.Child("fieldRef"))...)
if file.ResourceFieldRef != nil {
allErrs = append(allErrs, field.Invalid(fldPath, "resource", "fieldRef and resourceFieldRef can not be specified simultaneously"))
allErrs = append(allErrs, validateDownwardAPIVolumeFile(&file, fldPath)...)
}
return allErrs
}
func validateProjectionSources(projection *api.ProjectedVolumeSource, projectionMode *int32, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
allPaths := sets.String{}
for _, source := range projection.Sources {
numSources := 0
if source.Secret != nil {
if numSources > 0 {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("secret"), "may not specify more than 1 volume type"))
} else {
numSources++
if len(source.Secret.Name) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("name"), ""))
}
itemsPath := fldPath.Child("items")
for i, kp := range source.Secret.Items {
itemPath := itemsPath.Index(i)
allErrs = append(allErrs, validateKeyToPath(&kp, itemPath)...)
if len(kp.Path) > 0 {
curPath := kp.Path
if !allPaths.Has(curPath) {
allPaths.Insert(curPath)
} else {
allErrs = append(allErrs, field.Invalid(fldPath, source.Secret.Name, "conflicting duplicate paths"))
}
}
}
}
} else if file.ResourceFieldRef != nil {
allErrs = append(allErrs, validateContainerResourceFieldSelector(file.ResourceFieldRef, &validContainerResourceFieldPathExpressions, fldPath.Child("resourceFieldRef"), true)...)
} else {
allErrs = append(allErrs, field.Required(fldPath, "one of fieldRef and resourceFieldRef is required"))
}
if file.Mode != nil && (*file.Mode > 0777 || *file.Mode < 0) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("mode"), *file.Mode, volumeModeErrorMsg))
if source.ConfigMap != nil {
if numSources > 0 {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("configMap"), "may not specify more than 1 volume type"))
} else {
numSources++
if len(source.ConfigMap.Name) == 0 {
allErrs = append(allErrs, field.Required(fldPath.Child("name"), ""))
}
itemsPath := fldPath.Child("items")
for i, kp := range source.ConfigMap.Items {
itemPath := itemsPath.Index(i)
allErrs = append(allErrs, validateKeyToPath(&kp, itemPath)...)
if len(kp.Path) > 0 {
curPath := kp.Path
if !allPaths.Has(curPath) {
allPaths.Insert(curPath)
} else {
allErrs = append(allErrs, field.Invalid(fldPath, source.ConfigMap.Name, "conflicting duplicate paths"))
}
}
}
}
}
if source.DownwardAPI != nil {
if numSources > 0 {
allErrs = append(allErrs, field.Forbidden(fldPath.Child("downwardAPI"), "may not specify more than 1 volume type"))
} else {
numSources++
for _, file := range source.DownwardAPI.Items {
allErrs = append(allErrs, validateDownwardAPIVolumeFile(&file, fldPath.Child("downwardAPI"))...)
if len(file.Path) > 0 {
curPath := file.Path
if !allPaths.Has(curPath) {
allPaths.Insert(curPath)
} else {
allErrs = append(allErrs, field.Invalid(fldPath, curPath, "conflicting duplicate paths"))
}
}
}
}
}
}
return allErrs
}
func validateProjectedVolumeSource(projection *api.ProjectedVolumeSource, fldPath *field.Path) field.ErrorList {
allErrs := field.ErrorList{}
projectionMode := projection.DefaultMode
if projectionMode != nil && (*projectionMode > 0777 || *projectionMode < 0) {
allErrs = append(allErrs, field.Invalid(fldPath.Child("defaultMode"), *projectionMode, volumeModeErrorMsg))
}
allErrs = append(allErrs, validateProjectionSources(projection, projectionMode, fldPath)...)
return allErrs
}
......
......@@ -55,6 +55,7 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ConfigMapEnvSource, InType: reflect.TypeOf(&ConfigMapEnvSource{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ConfigMapKeySelector, InType: reflect.TypeOf(&ConfigMapKeySelector{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ConfigMapList, InType: reflect.TypeOf(&ConfigMapList{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ConfigMapProjection, InType: reflect.TypeOf(&ConfigMapProjection{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ConfigMapVolumeSource, InType: reflect.TypeOf(&ConfigMapVolumeSource{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_Container, InType: reflect.TypeOf(&Container{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ContainerImage, InType: reflect.TypeOf(&ContainerImage{})},
......@@ -67,6 +68,7 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ConversionError, InType: reflect.TypeOf(&ConversionError{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_DaemonEndpoint, InType: reflect.TypeOf(&DaemonEndpoint{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_DeleteOptions, InType: reflect.TypeOf(&DeleteOptions{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_DownwardAPIProjection, InType: reflect.TypeOf(&DownwardAPIProjection{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_DownwardAPIVolumeFile, InType: reflect.TypeOf(&DownwardAPIVolumeFile{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_DownwardAPIVolumeSource, InType: reflect.TypeOf(&DownwardAPIVolumeSource{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_EmptyDirVolumeSource, InType: reflect.TypeOf(&EmptyDirVolumeSource{})},
......@@ -160,6 +162,7 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_PreferAvoidPodsEntry, InType: reflect.TypeOf(&PreferAvoidPodsEntry{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_PreferredSchedulingTerm, InType: reflect.TypeOf(&PreferredSchedulingTerm{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_Probe, InType: reflect.TypeOf(&Probe{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_ProjectedVolumeSource, InType: reflect.TypeOf(&ProjectedVolumeSource{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_QuobyteVolumeSource, InType: reflect.TypeOf(&QuobyteVolumeSource{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_RBDVolumeSource, InType: reflect.TypeOf(&RBDVolumeSource{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_RangeAllocation, InType: reflect.TypeOf(&RangeAllocation{})},
......@@ -179,6 +182,7 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_SecretEnvSource, InType: reflect.TypeOf(&SecretEnvSource{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_SecretKeySelector, InType: reflect.TypeOf(&SecretKeySelector{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_SecretList, InType: reflect.TypeOf(&SecretList{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_SecretProjection, InType: reflect.TypeOf(&SecretProjection{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_SecretVolumeSource, InType: reflect.TypeOf(&SecretVolumeSource{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_SecurityContext, InType: reflect.TypeOf(&SecurityContext{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_SerializedReference, InType: reflect.TypeOf(&SerializedReference{})},
......@@ -196,6 +200,7 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_Toleration, InType: reflect.TypeOf(&Toleration{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_Volume, InType: reflect.TypeOf(&Volume{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_VolumeMount, InType: reflect.TypeOf(&VolumeMount{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_VolumeProjection, InType: reflect.TypeOf(&VolumeProjection{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_VolumeSource, InType: reflect.TypeOf(&VolumeSource{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_VsphereVirtualDiskVolumeSource, InType: reflect.TypeOf(&VsphereVirtualDiskVolumeSource{})},
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_WeightedPodAffinityTerm, InType: reflect.TypeOf(&WeightedPodAffinityTerm{})},
......@@ -475,6 +480,29 @@ func DeepCopy_api_ConfigMapList(in interface{}, out interface{}, c *conversion.C
}
}
func DeepCopy_api_ConfigMapProjection(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*ConfigMapProjection)
out := out.(*ConfigMapProjection)
*out = *in
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]KeyToPath, len(*in))
for i := range *in {
if err := DeepCopy_api_KeyToPath(&(*in)[i], &(*out)[i], c); err != nil {
return err
}
}
}
if in.Optional != nil {
in, out := &in.Optional, &out.Optional
*out = new(bool)
**out = **in
}
return nil
}
}
func DeepCopy_api_ConfigMapVolumeSource(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*ConfigMapVolumeSource)
......@@ -737,6 +765,24 @@ func DeepCopy_api_DeleteOptions(in interface{}, out interface{}, c *conversion.C
}
}
func DeepCopy_api_DownwardAPIProjection(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*DownwardAPIProjection)
out := out.(*DownwardAPIProjection)
*out = *in
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]DownwardAPIVolumeFile, len(*in))
for i := range *in {
if err := DeepCopy_api_DownwardAPIVolumeFile(&(*in)[i], &(*out)[i], c); err != nil {
return err
}
}
}
return nil
}
}
func DeepCopy_api_DownwardAPIVolumeFile(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*DownwardAPIVolumeFile)
......@@ -2536,6 +2582,29 @@ func DeepCopy_api_Probe(in interface{}, out interface{}, c *conversion.Cloner) e
}
}
func DeepCopy_api_ProjectedVolumeSource(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*ProjectedVolumeSource)
out := out.(*ProjectedVolumeSource)
*out = *in
if in.Sources != nil {
in, out := &in.Sources, &out.Sources
*out = make([]VolumeProjection, len(*in))
for i := range *in {
if err := DeepCopy_api_VolumeProjection(&(*in)[i], &(*out)[i], c); err != nil {
return err
}
}
}
if in.DefaultMode != nil {
in, out := &in.DefaultMode, &out.DefaultMode
*out = new(int32)
**out = **in
}
return nil
}
}
func DeepCopy_api_QuobyteVolumeSource(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*QuobyteVolumeSource)
......@@ -2867,6 +2936,29 @@ func DeepCopy_api_SecretList(in interface{}, out interface{}, c *conversion.Clon
}
}
func DeepCopy_api_SecretProjection(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*SecretProjection)
out := out.(*SecretProjection)
*out = *in
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]KeyToPath, len(*in))
for i := range *in {
if err := DeepCopy_api_KeyToPath(&(*in)[i], &(*out)[i], c); err != nil {
return err
}
}
}
if in.Optional != nil {
in, out := &in.Optional, &out.Optional
*out = new(bool)
**out = **in
}
return nil
}
}
func DeepCopy_api_SecretVolumeSource(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*SecretVolumeSource)
......@@ -3154,6 +3246,36 @@ func DeepCopy_api_VolumeMount(in interface{}, out interface{}, c *conversion.Clo
}
}
func DeepCopy_api_VolumeProjection(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*VolumeProjection)
out := out.(*VolumeProjection)
*out = *in
if in.Secret != nil {
in, out := &in.Secret, &out.Secret
*out = new(SecretProjection)
if err := DeepCopy_api_SecretProjection(*in, *out, c); err != nil {
return err
}
}
if in.DownwardAPI != nil {
in, out := &in.DownwardAPI, &out.DownwardAPI
*out = new(DownwardAPIProjection)
if err := DeepCopy_api_DownwardAPIProjection(*in, *out, c); err != nil {
return err
}
}
if in.ConfigMap != nil {
in, out := &in.ConfigMap, &out.ConfigMap
*out = new(ConfigMapProjection)
if err := DeepCopy_api_ConfigMapProjection(*in, *out, c); err != nil {
return err
}
}
return nil
}
}
func DeepCopy_api_VolumeSource(in interface{}, out interface{}, c *conversion.Cloner) error {
{
in := in.(*VolumeSource)
......@@ -3292,6 +3414,13 @@ func DeepCopy_api_VolumeSource(in interface{}, out interface{}, c *conversion.Cl
*out = new(PhotonPersistentDiskVolumeSource)
**out = **in
}
if in.Projected != nil {
in, out := &in.Projected, &out.Projected
*out = new(ProjectedVolumeSource)
if err := DeepCopy_api_ProjectedVolumeSource(*in, *out, c); err != nil {
return err
}
}
return nil
}
}
......
......@@ -64,6 +64,20 @@ func SetObjectDefaults_StatefulSet(in *StatefulSet) {
if a.VolumeSource.AzureDisk != nil {
v1.SetDefaults_AzureDiskVolumeSource(a.VolumeSource.AzureDisk)
}
if a.VolumeSource.Projected != nil {
v1.SetDefaults_ProjectedVolumeSource(a.VolumeSource.Projected)
for j := range a.VolumeSource.Projected.Sources {
b := &a.VolumeSource.Projected.Sources[j]
if b.DownwardAPI != nil {
for k := range b.DownwardAPI.Items {
c := &b.DownwardAPI.Items[k]
if c.FieldRef != nil {
v1.SetDefaults_ObjectFieldSelector(c.FieldRef)
}
}
}
}
}
}
for i := range in.Spec.Template.Spec.InitContainers {
a := &in.Spec.Template.Spec.InitContainers[i]
......
......@@ -64,6 +64,20 @@ func SetObjectDefaults_Job(in *Job) {
if a.VolumeSource.AzureDisk != nil {
api_v1.SetDefaults_AzureDiskVolumeSource(a.VolumeSource.AzureDisk)
}
if a.VolumeSource.Projected != nil {
api_v1.SetDefaults_ProjectedVolumeSource(a.VolumeSource.Projected)
for j := range a.VolumeSource.Projected.Sources {
b := &a.VolumeSource.Projected.Sources[j]
if b.DownwardAPI != nil {
for k := range b.DownwardAPI.Items {
c := &b.DownwardAPI.Items[k]
if c.FieldRef != nil {
api_v1.SetDefaults_ObjectFieldSelector(c.FieldRef)
}
}
}
}
}
}
for i := range in.Spec.Template.Spec.InitContainers {
a := &in.Spec.Template.Spec.InitContainers[i]
......
......@@ -67,6 +67,20 @@ func SetObjectDefaults_CronJob(in *CronJob) {
if a.VolumeSource.AzureDisk != nil {
v1.SetDefaults_AzureDiskVolumeSource(a.VolumeSource.AzureDisk)
}
if a.VolumeSource.Projected != nil {
v1.SetDefaults_ProjectedVolumeSource(a.VolumeSource.Projected)
for j := range a.VolumeSource.Projected.Sources {
b := &a.VolumeSource.Projected.Sources[j]
if b.DownwardAPI != nil {
for k := range b.DownwardAPI.Items {
c := &b.DownwardAPI.Items[k]
if c.FieldRef != nil {
v1.SetDefaults_ObjectFieldSelector(c.FieldRef)
}
}
}
}
}
}
for i := range in.Spec.JobTemplate.Spec.Template.Spec.InitContainers {
a := &in.Spec.JobTemplate.Spec.Template.Spec.InitContainers[i]
......@@ -191,6 +205,20 @@ func SetObjectDefaults_Job(in *Job) {
if a.VolumeSource.AzureDisk != nil {
v1.SetDefaults_AzureDiskVolumeSource(a.VolumeSource.AzureDisk)
}
if a.VolumeSource.Projected != nil {
v1.SetDefaults_ProjectedVolumeSource(a.VolumeSource.Projected)
for j := range a.VolumeSource.Projected.Sources {
b := &a.VolumeSource.Projected.Sources[j]
if b.DownwardAPI != nil {
for k := range b.DownwardAPI.Items {
c := &b.DownwardAPI.Items[k]
if c.FieldRef != nil {
v1.SetDefaults_ObjectFieldSelector(c.FieldRef)
}
}
}
}
}
}
for i := range in.Spec.Template.Spec.InitContainers {
a := &in.Spec.Template.Spec.InitContainers[i]
......@@ -314,6 +342,20 @@ func SetObjectDefaults_JobTemplate(in *JobTemplate) {
if a.VolumeSource.AzureDisk != nil {
v1.SetDefaults_AzureDiskVolumeSource(a.VolumeSource.AzureDisk)
}
if a.VolumeSource.Projected != nil {
v1.SetDefaults_ProjectedVolumeSource(a.VolumeSource.Projected)
for j := range a.VolumeSource.Projected.Sources {
b := &a.VolumeSource.Projected.Sources[j]
if b.DownwardAPI != nil {
for k := range b.DownwardAPI.Items {
c := &b.DownwardAPI.Items[k]
if c.FieldRef != nil {
v1.SetDefaults_ObjectFieldSelector(c.FieldRef)
}
}
}
}
}
}
for i := range in.Template.Spec.Template.Spec.InitContainers {
a := &in.Template.Spec.Template.Spec.InitContainers[i]
......
......@@ -905,6 +905,7 @@ var (
Quobyte FSType = "quobyte"
AzureDisk FSType = "azureDisk"
PhotonPersistentDisk FSType = "photonPersistentDisk"
Projected FSType = "projected"
All FSType = "*"
)
......
......@@ -70,6 +70,20 @@ func SetObjectDefaults_DaemonSet(in *DaemonSet) {
if a.VolumeSource.AzureDisk != nil {
v1.SetDefaults_AzureDiskVolumeSource(a.VolumeSource.AzureDisk)
}
if a.VolumeSource.Projected != nil {
v1.SetDefaults_ProjectedVolumeSource(a.VolumeSource.Projected)
for j := range a.VolumeSource.Projected.Sources {
b := &a.VolumeSource.Projected.Sources[j]
if b.DownwardAPI != nil {
for k := range b.DownwardAPI.Items {
c := &b.DownwardAPI.Items[k]
if c.FieldRef != nil {
v1.SetDefaults_ObjectFieldSelector(c.FieldRef)
}
}
}
}
}
}
for i := range in.Spec.Template.Spec.InitContainers {
a := &in.Spec.Template.Spec.InitContainers[i]
......@@ -194,6 +208,20 @@ func SetObjectDefaults_Deployment(in *Deployment) {
if a.VolumeSource.AzureDisk != nil {
v1.SetDefaults_AzureDiskVolumeSource(a.VolumeSource.AzureDisk)
}
if a.VolumeSource.Projected != nil {
v1.SetDefaults_ProjectedVolumeSource(a.VolumeSource.Projected)
for j := range a.VolumeSource.Projected.Sources {
b := &a.VolumeSource.Projected.Sources[j]
if b.DownwardAPI != nil {
for k := range b.DownwardAPI.Items {
c := &b.DownwardAPI.Items[k]
if c.FieldRef != nil {
v1.SetDefaults_ObjectFieldSelector(c.FieldRef)
}
}
}
}
}
}
for i := range in.Spec.Template.Spec.InitContainers {
a := &in.Spec.Template.Spec.InitContainers[i]
......@@ -329,6 +357,20 @@ func SetObjectDefaults_ReplicaSet(in *ReplicaSet) {
if a.VolumeSource.AzureDisk != nil {
v1.SetDefaults_AzureDiskVolumeSource(a.VolumeSource.AzureDisk)
}
if a.VolumeSource.Projected != nil {
v1.SetDefaults_ProjectedVolumeSource(a.VolumeSource.Projected)
for j := range a.VolumeSource.Projected.Sources {
b := &a.VolumeSource.Projected.Sources[j]
if b.DownwardAPI != nil {
for k := range b.DownwardAPI.Items {
c := &b.DownwardAPI.Items[k]
if c.FieldRef != nil {
v1.SetDefaults_ObjectFieldSelector(c.FieldRef)
}
}
}
}
}
}
for i := range in.Spec.Template.Spec.InitContainers {
a := &in.Spec.Template.Spec.InitContainers[i]
......
......@@ -279,6 +279,12 @@ func getSecretNames(pod *v1.Pod) sets.String {
for i := range pod.Spec.Volumes {
if source := pod.Spec.Volumes[i].Secret; source != nil {
result.Insert(source.SecretName)
} else if source := pod.Spec.Volumes[i].Projected; source != nil {
for j := range source.Sources {
if secretVolumeSource := source.Sources[j].Secret; secretVolumeSource != nil {
result.Insert(secretVolumeSource.Name)
}
}
}
}
return result
......
......@@ -61,7 +61,9 @@ func GetAllFSTypesAsSet() sets.String {
string(extensions.VsphereVolume),
string(extensions.Quobyte),
string(extensions.AzureDisk),
string(extensions.PhotonPersistentDisk))
string(extensions.PhotonPersistentDisk),
string(extensions.Projected),
)
return fstypes
}
......@@ -114,6 +116,8 @@ func GetVolumeFSType(v api.Volume) (extensions.FSType, error) {
return extensions.AzureDisk, nil
case v.PhotonPersistentDisk != nil:
return extensions.PhotonPersistentDisk, nil
case v.Projected != nil:
return extensions.Projected, nil
}
return "", fmt.Errorf("unknown volume type for volume: %#v", v)
......
......@@ -107,6 +107,7 @@ filegroup(
"//pkg/volume/iscsi:all-srcs",
"//pkg/volume/nfs:all-srcs",
"//pkg/volume/photon_pd:all-srcs",
"//pkg/volume/projected:all-srcs",
"//pkg/volume/quobyte:all-srcs",
"//pkg/volume/rbd:all-srcs",
"//pkg/volume/secret:all-srcs",
......
......@@ -193,7 +193,7 @@ func (b *configMapVolumeMounter) SetUpAt(dir string, fsGroup *int64) error {
len(configMap.Data),
totalBytes)
payload, err := makePayload(b.source.Items, configMap, b.source.DefaultMode, optional)
payload, err := MakePayload(b.source.Items, configMap, b.source.DefaultMode, optional)
if err != nil {
return err
}
......@@ -220,7 +220,8 @@ func (b *configMapVolumeMounter) SetUpAt(dir string, fsGroup *int64) error {
return nil
}
func makePayload(mappings []v1.KeyToPath, configMap *v1.ConfigMap, defaultMode *int32, optional bool) (map[string]volumeutil.FileProjection, error) {
// Note: this function is exported so that it can be called from the projection volume driver
func MakePayload(mappings []v1.KeyToPath, configMap *v1.ConfigMap, defaultMode *int32, optional bool) (map[string]volumeutil.FileProjection, error) {
if defaultMode == nil {
return nil, fmt.Errorf("No defaultMode used, not even the default value for it")
}
......
......@@ -238,7 +238,7 @@ func TestMakePayload(t *testing.T) {
}
for _, tc := range cases {
actualPayload, err := makePayload(tc.mappings, tc.configMap, &tc.mode, tc.optional)
actualPayload, err := MakePayload(tc.mappings, tc.configMap, &tc.mode, tc.optional)
if err != nil && tc.success {
t.Errorf("%v: unexpected failure making payload: %v", tc.name, err)
continue
......
......@@ -175,7 +175,7 @@ func (b *downwardAPIVolumeMounter) SetUpAt(dir string, fsGroup *int64) error {
return err
}
data, err := b.collectData(b.source.DefaultMode)
data, err := CollectData(b.source.Items, b.pod, b.plugin.host, b.source.DefaultMode)
if err != nil {
glog.Errorf("Error preparing data for downwardAPI volume %v for pod %v/%v: %s", b.volName, b.pod.Namespace, b.pod.Name, err.Error())
return err
......@@ -203,17 +203,19 @@ func (b *downwardAPIVolumeMounter) SetUpAt(dir string, fsGroup *int64) error {
return nil
}
// collectData collects requested downwardAPI in data map.
// CollectData collects requested downwardAPI in data map.
// Map's key is the requested name of file to dump
// Map's value is the (sorted) content of the field to be dumped in the file.
func (d *downwardAPIVolume) collectData(defaultMode *int32) (map[string]volumeutil.FileProjection, error) {
//
// Note: this function is exported so that it can be called from the projection volume driver
func CollectData(items []v1.DownwardAPIVolumeFile, pod *v1.Pod, host volume.VolumeHost, defaultMode *int32) (map[string]volumeutil.FileProjection, error) {
if defaultMode == nil {
return nil, fmt.Errorf("No defaultMode used, not even the default value for it")
}
errlist := []error{}
data := make(map[string]volumeutil.FileProjection)
for _, fileInfo := range d.items {
for _, fileInfo := range items {
var fileProjection volumeutil.FileProjection
fPath := path.Clean(fileInfo.Path)
if fileInfo.Mode != nil {
......@@ -223,7 +225,7 @@ func (d *downwardAPIVolume) collectData(defaultMode *int32) (map[string]volumeut
}
if fileInfo.FieldRef != nil {
// TODO: unify with Kubelet.podFieldSelectorRuntimeValue
if values, err := fieldpath.ExtractFieldPathAsString(d.pod, fileInfo.FieldRef.FieldPath); err != nil {
if values, err := fieldpath.ExtractFieldPathAsString(pod, fileInfo.FieldRef.FieldPath); err != nil {
glog.Errorf("Unable to extract field %s: %s", fileInfo.FieldRef.FieldPath, err.Error())
errlist = append(errlist, err)
} else {
......@@ -231,10 +233,10 @@ func (d *downwardAPIVolume) collectData(defaultMode *int32) (map[string]volumeut
}
} else if fileInfo.ResourceFieldRef != nil {
containerName := fileInfo.ResourceFieldRef.ContainerName
nodeAllocatable, err := d.plugin.host.GetNodeAllocatable()
nodeAllocatable, err := host.GetNodeAllocatable()
if err != nil {
errlist = append(errlist, err)
} else if values, err := fieldpath.ExtractResourceValueByContainerNameAndNodeAllocatable(fileInfo.ResourceFieldRef, d.pod, containerName, nodeAllocatable); err != nil {
} else if values, err := fieldpath.ExtractResourceValueByContainerNameAndNodeAllocatable(fileInfo.ResourceFieldRef, pod, containerName, nodeAllocatable); err != nil {
glog.Errorf("Unable to extract field %s: %s", fileInfo.ResourceFieldRef.Resource, err.Error())
errlist = append(errlist, err)
} else {
......
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_test(
name = "go_default_test",
srcs = ["projected_test.go"],
library = ":go_default_library",
tags = ["automanaged"],
deps = [
"//pkg/api/v1:go_default_library",
"//pkg/client/clientset_generated/clientset:go_default_library",
"//pkg/client/clientset_generated/clientset/fake:go_default_library",
"//pkg/volume:go_default_library",
"//pkg/volume/empty_dir:go_default_library",
"//pkg/volume/testing:go_default_library",
"//pkg/volume/util:go_default_library",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/apimachinery/pkg/types",
],
)
go_library(
name = "go_default_library",
srcs = ["projected.go"],
tags = ["automanaged"],
deps = [
"//pkg/api/v1:go_default_library",
"//pkg/util/strings:go_default_library",
"//pkg/volume:go_default_library",
"//pkg/volume/configmap:go_default_library",
"//pkg/volume/downwardapi:go_default_library",
"//pkg/volume/secret:go_default_library",
"//pkg/volume/util:go_default_library",
"//vendor:github.com/golang/glog",
"//vendor:k8s.io/apimachinery/pkg/api/errors",
"//vendor:k8s.io/apimachinery/pkg/apis/meta/v1",
"//vendor:k8s.io/apimachinery/pkg/types",
"//vendor:k8s.io/apimachinery/pkg/util/errors",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
)
/*
Copyright 2017 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 projected
import (
"fmt"
"sort"
"strings"
"github.com/golang/glog"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
utilerrors "k8s.io/apimachinery/pkg/util/errors"
"k8s.io/kubernetes/pkg/api/v1"
utilstrings "k8s.io/kubernetes/pkg/util/strings"
"k8s.io/kubernetes/pkg/volume"
"k8s.io/kubernetes/pkg/volume/configmap"
"k8s.io/kubernetes/pkg/volume/downwardapi"
"k8s.io/kubernetes/pkg/volume/secret"
volumeutil "k8s.io/kubernetes/pkg/volume/util"
)
// ProbeVolumePlugins is the entry point for plugin detection in a package.
func ProbeVolumePlugins() []volume.VolumePlugin {
return []volume.VolumePlugin{&projectedPlugin{}}
}
const (
projectedPluginName = "kubernetes.io/projected"
)
type projectedPlugin struct {
host volume.VolumeHost
getSecret func(namespace, name string) (*v1.Secret, error)
}
var _ volume.VolumePlugin = &projectedPlugin{}
func wrappedVolumeSpec() volume.Spec {
return volume.Spec{
Volume: &v1.Volume{
VolumeSource: v1.VolumeSource{
EmptyDir: &v1.EmptyDirVolumeSource{Medium: v1.StorageMediumMemory},
},
},
}
}
func getPath(uid types.UID, volName string, host volume.VolumeHost) string {
return host.GetPodVolumeDir(uid, utilstrings.EscapeQualifiedNameForDisk(projectedPluginName), volName)
}
func (plugin *projectedPlugin) Init(host volume.VolumeHost) error {
plugin.host = host
plugin.getSecret = host.GetSecretFunc()
return nil
}
func (plugin *projectedPlugin) GetPluginName() string {
return projectedPluginName
}
func (plugin *projectedPlugin) GetVolumeName(spec *volume.Spec) (string, error) {
_, _, err := getVolumeSource(spec)
if err != nil {
return "", err
}
return spec.Name(), nil
}
func (plugin *projectedPlugin) CanSupport(spec *volume.Spec) bool {
return spec.Volume != nil && spec.Volume.Projected != nil
}
func (plugin *projectedPlugin) RequiresRemount() bool {
return true
}
func (plugin *projectedPlugin) NewMounter(spec *volume.Spec, pod *v1.Pod, opts volume.VolumeOptions) (volume.Mounter, error) {
return &projectedVolumeMounter{
projectedVolume: &projectedVolume{
volName: spec.Name(),
sources: spec.Volume.Projected.Sources,
podUID: pod.UID,
plugin: plugin,
},
source: *spec.Volume.Projected,
pod: pod,
opts: &opts,
}, nil
}
func (plugin *projectedPlugin) NewUnmounter(volName string, podUID types.UID) (volume.Unmounter, error) {
return &projectedVolumeUnmounter{
&projectedVolume{
volName: volName,
podUID: podUID,
plugin: plugin,
},
}, nil
}
func (plugin *projectedPlugin) ConstructVolumeSpec(volumeName, mountPath string) (*volume.Spec, error) {
projectedVolume := &v1.Volume{
Name: volumeName,
VolumeSource: v1.VolumeSource{
Projected: &v1.ProjectedVolumeSource{},
},
}
return volume.NewSpecFromVolume(projectedVolume), nil
}
type projectedVolume struct {
volName string
sources []v1.VolumeProjection
podUID types.UID
plugin *projectedPlugin
volume.MetricsNil
}
var _ volume.Volume = &projectedVolume{}
func (sv *projectedVolume) GetPath() string {
return getPath(sv.podUID, sv.volName, sv.plugin.host)
}
type projectedVolumeMounter struct {
*projectedVolume
source v1.ProjectedVolumeSource
pod *v1.Pod
opts *volume.VolumeOptions
}
var _ volume.Mounter = &projectedVolumeMounter{}
func (sv *projectedVolume) GetAttributes() volume.Attributes {
return volume.Attributes{
ReadOnly: true,
Managed: true,
SupportsSELinux: true,
}
}
// Checks prior to mount operations to verify that the required components (binaries, etc.)
// to mount the volume are available on the underlying node.
// If not, it returns an error
func (s *projectedVolumeMounter) CanMount() error {
return nil
}
func (s *projectedVolumeMounter) SetUp(fsGroup *int64) error {
return s.SetUpAt(s.GetPath(), fsGroup)
}
func (s *projectedVolumeMounter) SetUpAt(dir string, fsGroup *int64) error {
glog.V(3).Infof("Setting up volume %v for pod %v at %v", s.volName, s.pod.UID, dir)
wrapped, err := s.plugin.host.NewWrapperMounter(s.volName, wrappedVolumeSpec(), s.pod, *s.opts)
if err != nil {
return err
}
if err := wrapped.SetUpAt(dir, fsGroup); err != nil {
return err
}
data, err := s.collectData()
if err != nil {
glog.Errorf("Error preparing data for projected volume %v for pod %v/%v: %s", s.volName, s.pod.Namespace, s.pod.Name, err.Error())
}
writerContext := fmt.Sprintf("pod %v/%v volume %v", s.pod.Namespace, s.pod.Name, s.volName)
writer, err := volumeutil.NewAtomicWriter(dir, writerContext)
if err != nil {
glog.Errorf("Error creating atomic writer: %v", err)
return err
}
err = writer.Write(data)
if err != nil {
glog.Errorf("Error writing payload to dir: %v", err)
return err
}
err = volume.SetVolumeOwnership(s, fsGroup)
if err != nil {
glog.Errorf("Error applying volume ownership settings for group: %v", fsGroup)
return err
}
return nil
}
func (s *projectedVolumeMounter) collectData() (map[string]volumeutil.FileProjection, error) {
if s.source.DefaultMode == nil {
return nil, fmt.Errorf("No defaultMode used, not even the default value for it")
}
kubeClient := s.plugin.host.GetKubeClient()
if kubeClient == nil {
return nil, fmt.Errorf("Cannot setup projected volume %v because kube client is not configured", s.volName)
}
errlist := []error{}
payload := make(map[string]volumeutil.FileProjection)
for _, source := range s.source.Sources {
if source.Secret != nil {
optional := source.Secret.Optional != nil && *source.Secret.Optional
secretapi, err := s.plugin.getSecret(s.pod.Namespace, source.Secret.Name)
if err != nil {
if !(errors.IsNotFound(err) && optional) {
glog.Errorf("Couldn't get secret %v/%v", s.pod.Namespace, source.Secret.Name)
errlist = append(errlist, err)
}
secretapi = &v1.Secret{
ObjectMeta: metav1.ObjectMeta{
Namespace: s.pod.Namespace,
Name: source.Secret.Name,
},
}
}
secretPayload, err := secret.MakePayload(source.Secret.Items, secretapi, s.source.DefaultMode, optional)
if err != nil {
glog.Errorf("Couldn't get secret %v/%v: %v", s.pod.Namespace, source.Secret.Name, err)
errlist = append(errlist, err)
continue
}
for k, v := range secretPayload {
payload[k] = v
}
} else if source.ConfigMap != nil {
optional := source.ConfigMap.Optional != nil && *source.ConfigMap.Optional
configMap, err := kubeClient.Core().ConfigMaps(s.pod.Namespace).Get(source.ConfigMap.Name, metav1.GetOptions{})
if err != nil {
if !(errors.IsNotFound(err) && optional) {
glog.Errorf("Couldn't get configMap %v/%v: %v", s.pod.Namespace, source.ConfigMap.Name, err)
errlist = append(errlist, err)
continue
}
configMap = &v1.ConfigMap{
ObjectMeta: metav1.ObjectMeta{
Namespace: s.pod.Namespace,
Name: source.ConfigMap.Name,
},
}
}
configMapPayload, err := configmap.MakePayload(source.ConfigMap.Items, configMap, s.source.DefaultMode, optional)
if err != nil {
errlist = append(errlist, err)
continue
}
for k, v := range configMapPayload {
payload[k] = v
}
} else if source.DownwardAPI != nil {
downwardAPIPayload, err := downwardapi.CollectData(source.DownwardAPI.Items, s.pod, s.plugin.host, s.source.DefaultMode)
if err != nil {
errlist = append(errlist, err)
continue
}
for k, v := range downwardAPIPayload {
payload[k] = v
}
}
}
return payload, utilerrors.NewAggregate(errlist)
}
func sortLines(values string) string {
splitted := strings.Split(values, "\n")
sort.Strings(splitted)
return strings.Join(splitted, "\n")
}
type projectedVolumeUnmounter struct {
*projectedVolume
}
var _ volume.Unmounter = &projectedVolumeUnmounter{}
func (c *projectedVolumeUnmounter) TearDown() error {
return c.TearDownAt(c.GetPath())
}
func (c *projectedVolumeUnmounter) TearDownAt(dir string) error {
glog.V(3).Infof("Tearing down volume %v for pod %v at %v", c.volName, c.podUID, dir)
wrapped, err := c.plugin.host.NewWrapperUnmounter(c.volName, wrappedVolumeSpec(), c.podUID)
if err != nil {
return err
}
return wrapped.TearDownAt(dir)
}
func getVolumeSource(spec *volume.Spec) (*v1.ProjectedVolumeSource, bool, error) {
var readOnly bool
var volumeSource *v1.ProjectedVolumeSource
if spec.Volume != nil && spec.Volume.Projected != nil {
volumeSource = spec.Volume.Projected
readOnly = spec.ReadOnly
}
return volumeSource, readOnly, fmt.Errorf("Spec does not reference a projected volume type")
}
......@@ -208,7 +208,7 @@ func (b *secretVolumeMounter) SetUpAt(dir string, fsGroup *int64) error {
len(secret.Data),
totalBytes)
payload, err := makePayload(b.source.Items, secret, b.source.DefaultMode, optional)
payload, err := MakePayload(b.source.Items, secret, b.source.DefaultMode, optional)
if err != nil {
return err
}
......@@ -235,7 +235,8 @@ func (b *secretVolumeMounter) SetUpAt(dir string, fsGroup *int64) error {
return nil
}
func makePayload(mappings []v1.KeyToPath, secret *v1.Secret, defaultMode *int32, optional bool) (map[string]volumeutil.FileProjection, error) {
// Note: this function is exported so that it can be called from the projection volume driver
func MakePayload(mappings []v1.KeyToPath, secret *v1.Secret, defaultMode *int32, optional bool) (map[string]volumeutil.FileProjection, error) {
if defaultMode == nil {
return nil, fmt.Errorf("No defaultMode used, not even the default value for it")
}
......
......@@ -241,7 +241,7 @@ func TestMakePayload(t *testing.T) {
}
for _, tc := range cases {
actualPayload, err := makePayload(tc.mappings, tc.secret, &tc.mode, tc.optional)
actualPayload, err := MakePayload(tc.mappings, tc.secret, &tc.mode, tc.optional)
if err != nil && tc.success {
t.Errorf("%v: unexpected failure making payload: %v", tc.name, err)
continue
......
......@@ -24,6 +24,7 @@ go_library(
"networking.go",
"pods.go",
"privileged.go",
"projected.go",
"secrets.go",
"sysctl.go",
"util.go",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment