diff --git a/docs/cmd/kn_container_add.md b/docs/cmd/kn_container_add.md index be61871c5..208d47693 100644 --- a/docs/cmd/kn_container_add.md +++ b/docs/cmd/kn_container_add.md @@ -38,7 +38,7 @@ kn container add NAME -h, --help help for add --image string Image to run. --limit strings The resource requirement limits for this Service. For example, 'cpu=100m,memory=256Mi'. You can use this flag multiple times. To unset a resource limit, append "-" to the resource name, e.g. '--limit memory-'. - --mount stringArray Mount a ConfigMap (prefix cm: or config-map:), a Secret (prefix secret: or sc:), or an existing Volume (without any prefix) on the specified directory. Example: --mount /mydir=cm:myconfigmap, --mount /mydir=secret:mysecret, or --mount /mydir=myvolume. When a configmap or a secret is specified, a corresponding volume is automatically generated. You can specify a volume subpath by following the volume name with slash separated path. Example: --mount /mydir=cm:myconfigmap/subpath/to/be/mounted. You can use this flag multiple times. For unmounting a directory, append "-", e.g. --mount /mydir-, which also removes any auto-generated volume. + --mount stringArray Mount a ConfigMap (prefix cm: or config-map:), a Secret (prefix secret: or sc:), an EmptyDir (prefix ed: or emptyDir:)or an existing Volume (without any prefix) on the specified directory. Example: --mount /mydir=cm:myconfigmap, --mount /mydir=secret:mysecret, --mount /mydir=emptyDir:myvol or --mount /mydir=myvolume. When a configmap or a secret is specified, a corresponding volume is automatically generated. You can specify a volume subpath by following the volume name with slash separated path. Example: --mount /mydir=cm:myconfigmap/subpath/to/be/mounted. You can use this flag multiple times. For unmounting a directory, append "-", e.g. --mount /mydir-, which also removes any auto-generated volume. -p, --port string The port where application listens on, in the format 'NAME:PORT', where 'NAME' is optional. Examples: '--port h2c:8080' , '--port 8080'. --pull-policy string Image pull policy. Valid values (case insensitive): Always | Never | IfNotPresent --pull-secret string Image pull secret to set. An empty argument ("") clears the pull secret. The referenced secret must exist in the service's namespace. diff --git a/docs/cmd/kn_service_apply.md b/docs/cmd/kn_service_apply.md index 73a222d2a..9dde83c6e 100644 --- a/docs/cmd/kn_service_apply.md +++ b/docs/cmd/kn_service_apply.md @@ -50,7 +50,7 @@ kn service apply s0 --filename my-svc.yml --label-service stringArray Service label to set. name=value; you may provide this flag any number of times to set multiple labels. To unset, specify the label name followed by a "-" (e.g., name-). This flag takes precedence over the "label" flag. --limit strings The resource requirement limits for this Service. For example, 'cpu=100m,memory=256Mi'. You can use this flag multiple times. To unset a resource limit, append "-" to the resource name, e.g. '--limit memory-'. --lock-to-digest Keep the running image for the service constant when not explicitly specifying the image. (--no-lock-to-digest pulls the image tag afresh with each new revision) (default true) - --mount stringArray Mount a ConfigMap (prefix cm: or config-map:), a Secret (prefix secret: or sc:), or an existing Volume (without any prefix) on the specified directory. Example: --mount /mydir=cm:myconfigmap, --mount /mydir=secret:mysecret, or --mount /mydir=myvolume. When a configmap or a secret is specified, a corresponding volume is automatically generated. You can specify a volume subpath by following the volume name with slash separated path. Example: --mount /mydir=cm:myconfigmap/subpath/to/be/mounted. You can use this flag multiple times. For unmounting a directory, append "-", e.g. --mount /mydir-, which also removes any auto-generated volume. + --mount stringArray Mount a ConfigMap (prefix cm: or config-map:), a Secret (prefix secret: or sc:), an EmptyDir (prefix ed: or emptyDir:)or an existing Volume (without any prefix) on the specified directory. Example: --mount /mydir=cm:myconfigmap, --mount /mydir=secret:mysecret, --mount /mydir=emptyDir:myvol or --mount /mydir=myvolume. When a configmap or a secret is specified, a corresponding volume is automatically generated. You can specify a volume subpath by following the volume name with slash separated path. Example: --mount /mydir=cm:myconfigmap/subpath/to/be/mounted. You can use this flag multiple times. For unmounting a directory, append "-", e.g. --mount /mydir-, which also removes any auto-generated volume. -n, --namespace string Specify the namespace to operate in. --no-cluster-local Do not specify that the service be private. (--no-cluster-local will make the service publicly available) (default true) --no-lock-to-digest Do not keep the running image for the service constant when not explicitly specifying the image. (--no-lock-to-digest pulls the image tag afresh with each new revision) @@ -71,7 +71,7 @@ kn service apply s0 --filename my-svc.yml --service-account string Service account name to set. An empty argument ("") clears the service account. The referenced service account must exist in the service's namespace. --timeout int Duration in seconds that the request routing layer will wait for a request delivered to a container to begin replying (default 300) --user int The user ID to run the container (e.g., 1001). - --volume stringArray Add a volume from a ConfigMap (prefix cm: or config-map:) or a Secret (prefix secret: or sc:). Example: --volume myvolume=cm:myconfigmap or --volume myvolume=secret:mysecret. You can use this flag multiple times. To unset a ConfigMap/Secret reference, append "-" to the name, e.g. --volume myvolume-. + --volume stringArray Add a volume from a ConfigMap (prefix cm: or config-map:) a Secret (prefix secret: or sc:), or an EmptyDir (prefix ed: or emptyDir:). Example: --volume myvolume=cm:myconfigmap, --volume myvolume=secret:mysecret or --volume emptyDir:myvol:size=1Gi,type=Memory. You can use this flag multiple times. To unset a ConfigMap/Secret reference, append "-" to the name, e.g. --volume myvolume-. --wait Wait for 'service apply' operation to be completed. (default true) --wait-timeout int Seconds to wait before giving up on waiting for service to be ready. (default 600) --wait-window int Seconds to wait for service to be ready after a false ready condition is returned (default 2) diff --git a/docs/cmd/kn_service_create.md b/docs/cmd/kn_service_create.md index 5dce7e296..db5cb8310 100644 --- a/docs/cmd/kn_service_create.md +++ b/docs/cmd/kn_service_create.md @@ -75,7 +75,7 @@ kn service create NAME --image IMAGE --label-service stringArray Service label to set. name=value; you may provide this flag any number of times to set multiple labels. To unset, specify the label name followed by a "-" (e.g., name-). This flag takes precedence over the "label" flag. --limit strings The resource requirement limits for this Service. For example, 'cpu=100m,memory=256Mi'. You can use this flag multiple times. To unset a resource limit, append "-" to the resource name, e.g. '--limit memory-'. --lock-to-digest Keep the running image for the service constant when not explicitly specifying the image. (--no-lock-to-digest pulls the image tag afresh with each new revision) (default true) - --mount stringArray Mount a ConfigMap (prefix cm: or config-map:), a Secret (prefix secret: or sc:), or an existing Volume (without any prefix) on the specified directory. Example: --mount /mydir=cm:myconfigmap, --mount /mydir=secret:mysecret, or --mount /mydir=myvolume. When a configmap or a secret is specified, a corresponding volume is automatically generated. You can specify a volume subpath by following the volume name with slash separated path. Example: --mount /mydir=cm:myconfigmap/subpath/to/be/mounted. You can use this flag multiple times. For unmounting a directory, append "-", e.g. --mount /mydir-, which also removes any auto-generated volume. + --mount stringArray Mount a ConfigMap (prefix cm: or config-map:), a Secret (prefix secret: or sc:), an EmptyDir (prefix ed: or emptyDir:)or an existing Volume (without any prefix) on the specified directory. Example: --mount /mydir=cm:myconfigmap, --mount /mydir=secret:mysecret, --mount /mydir=emptyDir:myvol or --mount /mydir=myvolume. When a configmap or a secret is specified, a corresponding volume is automatically generated. You can specify a volume subpath by following the volume name with slash separated path. Example: --mount /mydir=cm:myconfigmap/subpath/to/be/mounted. You can use this flag multiple times. For unmounting a directory, append "-", e.g. --mount /mydir-, which also removes any auto-generated volume. -n, --namespace string Specify the namespace to operate in. --no-cluster-local Do not specify that the service be private. (--no-cluster-local will make the service publicly available) (default true) --no-lock-to-digest Do not keep the running image for the service constant when not explicitly specifying the image. (--no-lock-to-digest pulls the image tag afresh with each new revision) @@ -98,7 +98,7 @@ kn service create NAME --image IMAGE --target string Work on local directory instead of a remote cluster (experimental) --timeout int Duration in seconds that the request routing layer will wait for a request delivered to a container to begin replying (default 300) --user int The user ID to run the container (e.g., 1001). - --volume stringArray Add a volume from a ConfigMap (prefix cm: or config-map:) or a Secret (prefix secret: or sc:). Example: --volume myvolume=cm:myconfigmap or --volume myvolume=secret:mysecret. You can use this flag multiple times. To unset a ConfigMap/Secret reference, append "-" to the name, e.g. --volume myvolume-. + --volume stringArray Add a volume from a ConfigMap (prefix cm: or config-map:) a Secret (prefix secret: or sc:), or an EmptyDir (prefix ed: or emptyDir:). Example: --volume myvolume=cm:myconfigmap, --volume myvolume=secret:mysecret or --volume emptyDir:myvol:size=1Gi,type=Memory. You can use this flag multiple times. To unset a ConfigMap/Secret reference, append "-" to the name, e.g. --volume myvolume-. --wait Wait for 'service create' operation to be completed. (default true) --wait-timeout int Seconds to wait before giving up on waiting for service to be ready. (default 600) --wait-window int Seconds to wait for service to be ready after a false ready condition is returned (default 2) diff --git a/docs/cmd/kn_service_update.md b/docs/cmd/kn_service_update.md index cc747559e..8d602b617 100644 --- a/docs/cmd/kn_service_update.md +++ b/docs/cmd/kn_service_update.md @@ -62,7 +62,7 @@ kn service update NAME --label-service stringArray Service label to set. name=value; you may provide this flag any number of times to set multiple labels. To unset, specify the label name followed by a "-" (e.g., name-). This flag takes precedence over the "label" flag. --limit strings The resource requirement limits for this Service. For example, 'cpu=100m,memory=256Mi'. You can use this flag multiple times. To unset a resource limit, append "-" to the resource name, e.g. '--limit memory-'. --lock-to-digest Keep the running image for the service constant when not explicitly specifying the image. (--no-lock-to-digest pulls the image tag afresh with each new revision) (default true) - --mount stringArray Mount a ConfigMap (prefix cm: or config-map:), a Secret (prefix secret: or sc:), or an existing Volume (without any prefix) on the specified directory. Example: --mount /mydir=cm:myconfigmap, --mount /mydir=secret:mysecret, or --mount /mydir=myvolume. When a configmap or a secret is specified, a corresponding volume is automatically generated. You can specify a volume subpath by following the volume name with slash separated path. Example: --mount /mydir=cm:myconfigmap/subpath/to/be/mounted. You can use this flag multiple times. For unmounting a directory, append "-", e.g. --mount /mydir-, which also removes any auto-generated volume. + --mount stringArray Mount a ConfigMap (prefix cm: or config-map:), a Secret (prefix secret: or sc:), an EmptyDir (prefix ed: or emptyDir:)or an existing Volume (without any prefix) on the specified directory. Example: --mount /mydir=cm:myconfigmap, --mount /mydir=secret:mysecret, --mount /mydir=emptyDir:myvol or --mount /mydir=myvolume. When a configmap or a secret is specified, a corresponding volume is automatically generated. You can specify a volume subpath by following the volume name with slash separated path. Example: --mount /mydir=cm:myconfigmap/subpath/to/be/mounted. You can use this flag multiple times. For unmounting a directory, append "-", e.g. --mount /mydir-, which also removes any auto-generated volume. -n, --namespace string Specify the namespace to operate in. --no-cluster-local Do not specify that the service be private. (--no-cluster-local will make the service publicly available) (default true) --no-lock-to-digest Do not keep the running image for the service constant when not explicitly specifying the image. (--no-lock-to-digest pulls the image tag afresh with each new revision) @@ -87,7 +87,7 @@ kn service update NAME --traffic strings Set traffic distribution (format: --traffic revisionRef=percent) where revisionRef can be a revision or a tag or '@latest' string representing latest ready revision. This flag can be given multiple times with percent summing up to 100%. --untag strings Untag revision (format: --untag tagName). This flag can be specified multiple times. --user int The user ID to run the container (e.g., 1001). - --volume stringArray Add a volume from a ConfigMap (prefix cm: or config-map:) or a Secret (prefix secret: or sc:). Example: --volume myvolume=cm:myconfigmap or --volume myvolume=secret:mysecret. You can use this flag multiple times. To unset a ConfigMap/Secret reference, append "-" to the name, e.g. --volume myvolume-. + --volume stringArray Add a volume from a ConfigMap (prefix cm: or config-map:) a Secret (prefix secret: or sc:), or an EmptyDir (prefix ed: or emptyDir:). Example: --volume myvolume=cm:myconfigmap, --volume myvolume=secret:mysecret or --volume emptyDir:myvol:size=1Gi,type=Memory. You can use this flag multiple times. To unset a ConfigMap/Secret reference, append "-" to the name, e.g. --volume myvolume-. --wait Wait for 'service update' operation to be completed. (default true) --wait-timeout int Seconds to wait before giving up on waiting for service to be ready. (default 600) --wait-window int Seconds to wait for service to be ready after a false ready condition is returned (default 2) diff --git a/docs/cmd/kn_source_container_create.md b/docs/cmd/kn_source_container_create.md index fdaa3658b..f21e1ce71 100644 --- a/docs/cmd/kn_source_container_create.md +++ b/docs/cmd/kn_source_container_create.md @@ -27,7 +27,7 @@ kn source container create NAME --image IMAGE --sink SINK -h, --help help for create --image string Image to run. --limit strings The resource requirement limits for this Service. For example, 'cpu=100m,memory=256Mi'. You can use this flag multiple times. To unset a resource limit, append "-" to the resource name, e.g. '--limit memory-'. - --mount stringArray Mount a ConfigMap (prefix cm: or config-map:), a Secret (prefix secret: or sc:), or an existing Volume (without any prefix) on the specified directory. Example: --mount /mydir=cm:myconfigmap, --mount /mydir=secret:mysecret, or --mount /mydir=myvolume. When a configmap or a secret is specified, a corresponding volume is automatically generated. You can specify a volume subpath by following the volume name with slash separated path. Example: --mount /mydir=cm:myconfigmap/subpath/to/be/mounted. You can use this flag multiple times. For unmounting a directory, append "-", e.g. --mount /mydir-, which also removes any auto-generated volume. + --mount stringArray Mount a ConfigMap (prefix cm: or config-map:), a Secret (prefix secret: or sc:), an EmptyDir (prefix ed: or emptyDir:)or an existing Volume (without any prefix) on the specified directory. Example: --mount /mydir=cm:myconfigmap, --mount /mydir=secret:mysecret, --mount /mydir=emptyDir:myvol or --mount /mydir=myvolume. When a configmap or a secret is specified, a corresponding volume is automatically generated. You can specify a volume subpath by following the volume name with slash separated path. Example: --mount /mydir=cm:myconfigmap/subpath/to/be/mounted. You can use this flag multiple times. For unmounting a directory, append "-", e.g. --mount /mydir-, which also removes any auto-generated volume. -n, --namespace string Specify the namespace to operate in. -p, --port string The port where application listens on, in the format 'NAME:PORT', where 'NAME' is optional. Examples: '--port h2c:8080' , '--port 8080'. --pull-policy string Image pull policy. Valid values (case insensitive): Always | Never | IfNotPresent @@ -36,7 +36,7 @@ kn source container create NAME --image IMAGE --sink SINK --service-account string Service account name to set. An empty argument ("") clears the service account. The referenced service account must exist in the service's namespace. -s, --sink string Addressable sink for events. You can specify a broker, channel, Knative service or URI. Examples: '--sink broker:nest' for a broker 'nest', '--sink channel:pipe' for a channel 'pipe', '--sink ksvc:mysvc:mynamespace' for a Knative service 'mysvc' in another namespace 'mynamespace', '--sink https://event.receiver.uri' for an URI with an 'http://' or 'https://' schema, '--sink ksvc:receiver' or simply '--sink receiver' for a Knative service 'receiver' in the current namespace. If a prefix is not provided, it is considered as a Knative service in the current namespace. If referring to a Knative service in another namespace, 'ksvc:name:namespace' combination must be provided explicitly. --user int The user ID to run the container (e.g., 1001). - --volume stringArray Add a volume from a ConfigMap (prefix cm: or config-map:) or a Secret (prefix secret: or sc:). Example: --volume myvolume=cm:myconfigmap or --volume myvolume=secret:mysecret. You can use this flag multiple times. To unset a ConfigMap/Secret reference, append "-" to the name, e.g. --volume myvolume-. + --volume stringArray Add a volume from a ConfigMap (prefix cm: or config-map:) a Secret (prefix secret: or sc:), or an EmptyDir (prefix ed: or emptyDir:). Example: --volume myvolume=cm:myconfigmap, --volume myvolume=secret:mysecret or --volume emptyDir:myvol:size=1Gi,type=Memory. You can use this flag multiple times. To unset a ConfigMap/Secret reference, append "-" to the name, e.g. --volume myvolume-. ``` ### Options inherited from parent commands diff --git a/docs/cmd/kn_source_container_update.md b/docs/cmd/kn_source_container_update.md index 322e605a2..d41305d62 100644 --- a/docs/cmd/kn_source_container_update.md +++ b/docs/cmd/kn_source_container_update.md @@ -27,7 +27,7 @@ kn source container update NAME --image IMAGE -h, --help help for update --image string Image to run. --limit strings The resource requirement limits for this Service. For example, 'cpu=100m,memory=256Mi'. You can use this flag multiple times. To unset a resource limit, append "-" to the resource name, e.g. '--limit memory-'. - --mount stringArray Mount a ConfigMap (prefix cm: or config-map:), a Secret (prefix secret: or sc:), or an existing Volume (without any prefix) on the specified directory. Example: --mount /mydir=cm:myconfigmap, --mount /mydir=secret:mysecret, or --mount /mydir=myvolume. When a configmap or a secret is specified, a corresponding volume is automatically generated. You can specify a volume subpath by following the volume name with slash separated path. Example: --mount /mydir=cm:myconfigmap/subpath/to/be/mounted. You can use this flag multiple times. For unmounting a directory, append "-", e.g. --mount /mydir-, which also removes any auto-generated volume. + --mount stringArray Mount a ConfigMap (prefix cm: or config-map:), a Secret (prefix secret: or sc:), an EmptyDir (prefix ed: or emptyDir:)or an existing Volume (without any prefix) on the specified directory. Example: --mount /mydir=cm:myconfigmap, --mount /mydir=secret:mysecret, --mount /mydir=emptyDir:myvol or --mount /mydir=myvolume. When a configmap or a secret is specified, a corresponding volume is automatically generated. You can specify a volume subpath by following the volume name with slash separated path. Example: --mount /mydir=cm:myconfigmap/subpath/to/be/mounted. You can use this flag multiple times. For unmounting a directory, append "-", e.g. --mount /mydir-, which also removes any auto-generated volume. -n, --namespace string Specify the namespace to operate in. -p, --port string The port where application listens on, in the format 'NAME:PORT', where 'NAME' is optional. Examples: '--port h2c:8080' , '--port 8080'. --pull-policy string Image pull policy. Valid values (case insensitive): Always | Never | IfNotPresent @@ -36,7 +36,7 @@ kn source container update NAME --image IMAGE --service-account string Service account name to set. An empty argument ("") clears the service account. The referenced service account must exist in the service's namespace. -s, --sink string Addressable sink for events. You can specify a broker, channel, Knative service or URI. Examples: '--sink broker:nest' for a broker 'nest', '--sink channel:pipe' for a channel 'pipe', '--sink ksvc:mysvc:mynamespace' for a Knative service 'mysvc' in another namespace 'mynamespace', '--sink https://event.receiver.uri' for an URI with an 'http://' or 'https://' schema, '--sink ksvc:receiver' or simply '--sink receiver' for a Knative service 'receiver' in the current namespace. If a prefix is not provided, it is considered as a Knative service in the current namespace. If referring to a Knative service in another namespace, 'ksvc:name:namespace' combination must be provided explicitly. --user int The user ID to run the container (e.g., 1001). - --volume stringArray Add a volume from a ConfigMap (prefix cm: or config-map:) or a Secret (prefix secret: or sc:). Example: --volume myvolume=cm:myconfigmap or --volume myvolume=secret:mysecret. You can use this flag multiple times. To unset a ConfigMap/Secret reference, append "-" to the name, e.g. --volume myvolume-. + --volume stringArray Add a volume from a ConfigMap (prefix cm: or config-map:) a Secret (prefix secret: or sc:), or an EmptyDir (prefix ed: or emptyDir:). Example: --volume myvolume=cm:myconfigmap, --volume myvolume=secret:mysecret or --volume emptyDir:myvol:size=1Gi,type=Memory. You can use this flag multiple times. To unset a ConfigMap/Secret reference, append "-" to the name, e.g. --volume myvolume-. ``` ### Options inherited from parent commands diff --git a/pkg/kn/flags/podspec.go b/pkg/kn/flags/podspec.go index f79efab06..a07f426c4 100644 --- a/pkg/kn/flags/podspec.go +++ b/pkg/kn/flags/podspec.go @@ -137,18 +137,20 @@ func (p *PodSpecFlags) AddFlags(flagset *pflag.FlagSet) []string { flagNames = append(flagNames, "env-file") flagset.StringArrayVarP(&p.Mount, "mount", "", []string{}, - "Mount a ConfigMap (prefix cm: or config-map:), a Secret (prefix secret: or sc:), or an existing Volume (without any prefix) on the specified directory. "+ - "Example: --mount /mydir=cm:myconfigmap, --mount /mydir=secret:mysecret, or --mount /mydir=myvolume. "+ - "When a configmap or a secret is specified, a corresponding volume is automatically generated. "+ - "You can specify a volume subpath by following the volume name with slash separated path. "+ + "Mount a ConfigMap (prefix cm: or config-map:), a Secret (prefix secret: or sc:), an EmptyDir (prefix ed: or emptyDir:)"+ + "or an existing Volume (without any prefix) on the specified directory. "+ + "Example: --mount /mydir=cm:myconfigmap, --mount /mydir=secret:mysecret, --mount /mydir=emptyDir:myvol "+ + "or --mount /mydir=myvolume. When a configmap or a secret is specified, a corresponding volume is "+ + "automatically generated. You can specify a volume subpath by following the volume name with slash separated path. "+ "Example: --mount /mydir=cm:myconfigmap/subpath/to/be/mounted. "+ "You can use this flag multiple times. "+ "For unmounting a directory, append \"-\", e.g. --mount /mydir-, which also removes any auto-generated volume.") flagNames = append(flagNames, "mount") flagset.StringArrayVarP(&p.Volume, "volume", "", []string{}, - "Add a volume from a ConfigMap (prefix cm: or config-map:) or a Secret (prefix secret: or sc:). "+ - "Example: --volume myvolume=cm:myconfigmap or --volume myvolume=secret:mysecret. "+ + "Add a volume from a ConfigMap (prefix cm: or config-map:) a Secret (prefix secret: or sc:), or "+ + "an EmptyDir (prefix ed: or emptyDir:). "+ + "Example: --volume myvolume=cm:myconfigmap, --volume myvolume=secret:mysecret or --volume emptyDir:myvol:size=1Gi,type=Memory. "+ "You can use this flag multiple times. "+ "To unset a ConfigMap/Secret reference, append \"-\" to the name, e.g. --volume myvolume-.") flagNames = append(flagNames, "volume") diff --git a/pkg/kn/flags/podspec_helper.go b/pkg/kn/flags/podspec_helper.go index e45824049..c71e1e221 100644 --- a/pkg/kn/flags/podspec_helper.go +++ b/pkg/kn/flags/podspec_helper.go @@ -20,6 +20,7 @@ import ( "strconv" "strings" + "k8s.io/apimachinery/pkg/api/resource" "k8s.io/apimachinery/pkg/util/yaml" corev1 "k8s.io/api/core/v1" @@ -35,6 +36,7 @@ type VolumeSourceType int const ( ConfigMapVolumeSourceType VolumeSourceType = iota SecretVolumeSourceType + EmptyDirVolumeSourceType PortFormatErr = "the port specification '%s' is not valid. Please provide in the format 'NAME:PORT', where 'NAME' is optional. Examples: '--port h2c:8080' , '--port 8080'." ) @@ -466,6 +468,8 @@ func updateVolume(volume *corev1.Volume, info *volumeSourceInfo) error { case SecretVolumeSourceType: volume.ConfigMap = nil volume.Secret = &corev1.SecretVolumeSource{SecretName: info.volumeSourceName} + case EmptyDirVolumeSourceType: + volume.EmptyDir = &corev1.EmptyDirVolumeSource{Medium: corev1.StorageMedium(info.emptyDirMemoryType), SizeLimit: info.emptyDirSize} default: return fmt.Errorf("Invalid VolumeSourceType") } @@ -486,8 +490,7 @@ func updateVolumeMountsFromMap(volumeMounts []corev1.VolumeMount, toUpdate *util if !existsVolumeNameInVolumes(name, volumes) { return nil, fmt.Errorf("There is no volume matched with %q", name) } - - volumeMount.ReadOnly = true + volumeMount.ReadOnly = isReadOnlyVolume(name, volumes) volumeMount.Name = name volumeMount.SubPath = volumeMountInfo.SubPath set[volumeMount.MountPath] = true @@ -501,7 +504,7 @@ func updateVolumeMountsFromMap(volumeMounts []corev1.VolumeMount, toUpdate *util if !set[mountPath] { volumeMounts = append(volumeMounts, corev1.VolumeMount{ Name: name, - ReadOnly: true, + ReadOnly: isReadOnlyVolume(name, volumes), MountPath: mountPath, SubPath: volumeMountInfo.SubPath, }) @@ -579,38 +582,65 @@ func removeVolumes(volumes []corev1.Volume, toRemove []string, volumeMounts []co // ======================================================================================= type volumeSourceInfo struct { - volumeSourceType VolumeSourceType - volumeSourceName string + volumeSourceType VolumeSourceType + volumeSourceName string + emptyDirMemoryType string + emptyDirSize *resource.Quantity } func newVolumeSourceInfoWithSpecString(spec string) (*volumeSourceInfo, error) { - slices := strings.SplitN(spec, ":", 2) - if len(slices) != 2 { - return nil, fmt.Errorf("argument requires a value that contains the : character; got %q", spec) + slices := strings.SplitN(spec, ":", 3) + if len(slices) < 2 { + return nil, fmt.Errorf("argument requires a value that contains the : character; got %q, %q", spec, slices) } - var volumeSourceType VolumeSourceType + if len(slices) == 2 { + var volumeSourceType VolumeSourceType - typeString := strings.TrimSpace(slices[0]) - volumeSourceName := strings.TrimSpace(slices[1]) + typeString := strings.TrimSpace(slices[0]) + volumeSourceName := strings.TrimSpace(slices[1]) + + switch typeString { + case "config-map", "cm": + volumeSourceType = ConfigMapVolumeSourceType + case "secret", "sc": + volumeSourceType = SecretVolumeSourceType + case "emptyDir", "ed": + volumeSourceType = EmptyDirVolumeSourceType + default: + return nil, fmt.Errorf("unsupported volume source type \"%q\"; supported volume source types are \"config-map\" and \"secret\"", slices[0]) + } + + if len(volumeSourceName) == 0 { + return nil, fmt.Errorf("the name of %s cannot be an empty string", volumeSourceType) + } + + return &volumeSourceInfo{ + volumeSourceType: volumeSourceType, + volumeSourceName: volumeSourceName, + }, nil + } else { + typeString := strings.TrimSpace(slices[0]) + switch typeString { + case "config-map", "cm", "secret", "sc": + return nil, fmt.Errorf("incorrect mount details for type %q", typeString) + case "emptyDir", "ed": + volName := slices[1] + edType, edSize, err := getEmptyDirTypeAndSize(slices[2]) + if err != nil { + return nil, err + } + return &volumeSourceInfo{ + volumeSourceType: EmptyDirVolumeSourceType, + volumeSourceName: volName, + emptyDirMemoryType: edType, + emptyDirSize: edSize, + }, nil + default: + return nil, fmt.Errorf("unsupported volume type \"%q\"; supported volume types are \"config-map or cm\", \"secret or sc\", \"volume or vo\", and \"emptyDir or ed\"", slices[0]) + } - switch typeString { - case "config-map", "cm": - volumeSourceType = ConfigMapVolumeSourceType - case "secret", "sc": - volumeSourceType = SecretVolumeSourceType - default: - return nil, fmt.Errorf("unsupported volume source type \"%q\"; supported volume source types are \"config-map\" and \"secret\"", slices[0]) } - - if len(volumeSourceName) == 0 { - return nil, fmt.Errorf("the name of %s cannot be an empty string", volumeSourceType) - } - - return &volumeSourceInfo{ - volumeSourceType: volumeSourceType, - volumeSourceName: volumeSourceName, - }, nil } func (vol *volumeSourceInfo) getCanonicalName() string { @@ -649,6 +679,15 @@ func (vol *volumeSourceInfo) createEnvFromSource() *corev1.EnvFromSource { // ======================================================================================= +func isReadOnlyVolume(volumeName string, volumes []corev1.Volume) bool { + for _, volume := range volumes { + if volume.Name == volumeName { + return volume.EmptyDir == nil + } + } + return true +} + func existsVolumeNameInVolumes(volumeName string, volumes []corev1.Volume) bool { for _, volume := range volumes { if volume.Name == volumeName { @@ -714,9 +753,18 @@ func reviseVolumeInfoAndMountsToUpdate(mountsToUpdate *util.OrderedMap, volumesT }) mountInfo.VolumeName = generatedName mountsToUpdateRevised.Set(path, mountInfo) - + case "emptyDir", "ed": + generatedName := util.GenerateVolumeName(path) + mountInfo := getMountInfo(slices[1]) + volumeSourceInfoByName.Set(generatedName, &volumeSourceInfo{ + volumeSourceType: EmptyDirVolumeSourceType, + volumeSourceName: slices[1], + emptyDirMemoryType: "", + }) + mountInfo.VolumeName = generatedName + mountsToUpdateRevised.Set(path, mountInfo) default: - return nil, nil, fmt.Errorf("unsupported volume type \"%q\"; supported volume types are \"config-map or cm\", \"secret or sc\", and \"volume or vo\"", slices[0]) + return nil, nil, fmt.Errorf("unsupported volume type \"%q\"; supported volume types are \"config-map or cm\", \"secret or sc\", \"volume or vo\", and \"emptyDir or ed\"", slices[0]) } } } @@ -733,6 +781,61 @@ func reviseVolumeInfoAndMountsToUpdate(mountsToUpdate *util.OrderedMap, volumesT return volumeSourceInfoByName, mountsToUpdateRevised, nil } +func getEmptyDirTypeAndSize(value string) (string, *resource.Quantity, error) { + slices := strings.SplitN(value, ",", 2) + formatErr := fmt.Errorf("incorrect format to specify emptyDir type") + repeatErrStr := "cannot repeat the key %q" + var dirType string + var size *resource.Quantity + switch len(slices) { + case 0: + return "", nil, nil + case 1: + typeSizeSlices := strings.SplitN(slices[0], "=", 2) + if len(typeSizeSlices) < 2 { + return "", nil, formatErr + } + switch strings.ToLower(typeSizeSlices[0]) { + case "type": + dirType = typeSizeSlices[1] + case "size": + quantity, err := resource.ParseQuantity(typeSizeSlices[1]) + if err != nil { + return "", nil, formatErr + } + size = &quantity + default: + return "", nil, formatErr + } + case 2: + for _, slice := range slices { + typeSizeSlices := strings.SplitN(slice, "=", 2) + if len(typeSizeSlices) < 2 { + return "", nil, formatErr + } + switch strings.ToLower(typeSizeSlices[0]) { + case "type": + if dirType != "" { + return "", nil, fmt.Errorf(repeatErrStr, "type") + } + dirType = typeSizeSlices[1] + case "size": + if size != nil { + return "", nil, fmt.Errorf(repeatErrStr, "size") + } + quantity, err := resource.ParseQuantity(typeSizeSlices[1]) + if err != nil { + return "", nil, formatErr + } + size = &quantity + default: + return "", nil, formatErr + } + } + } + return dirType, size, nil +} + func reviseVolumesToRemove(volumeMounts []corev1.VolumeMount, volumesToRemove []string, mountsToRemove []string) []string { for _, pathToRemove := range mountsToRemove { for _, volumeMount := range volumeMounts { diff --git a/pkg/kn/flags/podspec_helper_test.go b/pkg/kn/flags/podspec_helper_test.go index 04ce49ceb..68acdd38d 100644 --- a/pkg/kn/flags/podspec_helper_test.go +++ b/pkg/kn/flags/podspec_helper_test.go @@ -21,8 +21,10 @@ import ( "io/ioutil" "os" "path/filepath" + "strings" "testing" + "k8s.io/apimachinery/pkg/api/resource" "knative.dev/client/lib/test" "gotest.tools/v3/assert" @@ -228,6 +230,7 @@ func TestUpdateEnvFrom(t *testing.T) { } func TestUpdateVolumeMountsAndVolumes(t *testing.T) { + quantity := resource.MustParse("10Gi") spec, container := getPodSpec() spec.Volumes = append(spec.Volumes, corev1.Volume{ @@ -255,7 +258,41 @@ func TestUpdateVolumeMountsAndVolumes(t *testing.T) { VolumeSource: corev1.VolumeSource{ Secret: &corev1.SecretVolumeSource{ SecretName: "existing-secret-2", - }}}) + }}}, + corev1.Volume{ + Name: "new-empty-dir-volume-name-1", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{ + Medium: "", + SizeLimit: nil, + }, + }, + }, + corev1.Volume{ + Name: "new-empty-dir-volume-name-2", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{ + Medium: "Memory", + SizeLimit: &quantity, + }, + }, + }, + corev1.Volume{ + Name: "new-empty-dir-volume-name-3", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{ + Medium: "Memory", + }, + }, + }, + corev1.Volume{ + Name: "new-empty-dir-volume-name-4", + VolumeSource: corev1.VolumeSource{ + EmptyDir: &corev1.EmptyDirVolumeSource{ + SizeLimit: &quantity, + }, + }, + }) container.VolumeMounts = append(container.VolumeMounts, corev1.VolumeMount{ @@ -278,6 +315,31 @@ func TestUpdateVolumeMountsAndVolumes(t *testing.T) { ReadOnly: true, MountPath: "/existing-secret-2/mount/path", }, + corev1.VolumeMount{ + Name: "new-empty-dir-volume-name-1", + ReadOnly: false, + MountPath: "/empty-dir-1/mount/path", + }, + corev1.VolumeMount{ + Name: "new-empty-dir-volume-name-2", + ReadOnly: false, + MountPath: "/empty-dir-2/mount/path", + }, + corev1.VolumeMount{ + Name: "new-empty-dir-volume-name-3", + ReadOnly: false, + MountPath: "/empty-dir-3/mount/path", + }, + corev1.VolumeMount{ + Name: "new-empty-dir-volume-name-4", + ReadOnly: false, + MountPath: "/empty-dir-4/mount/path", + }, + corev1.VolumeMount{ + Name: "new-empty-dir-volume-name-5", + ReadOnly: false, + MountPath: "/empty-dir-5/mount/path", + }, ) err := UpdateVolumeMountsAndVolumes(spec, @@ -310,29 +372,87 @@ func TestUpdateVolumeMountsAndVolumes(t *testing.T) { "existing-secret-volume-name-1"}) assert.NilError(t, err) - assert.Equal(t, len(spec.Volumes), 4) - assert.Equal(t, len(container.VolumeMounts), 6) + err = UpdateVolumeMountsAndVolumes(spec, + util.NewOrderedMapWithKVStrings([][]string{{"/empty-dir-1/mount/path", "new-empty-dir-volume-name-1"}}), + []string{}, + util.NewOrderedMapWithKVStrings([][]string{{"new-empty-dir-volume-name-1", "emptyDir:new-empty-dir-volume-name-1"}}), + []string{}) + assert.NilError(t, err) + + err = UpdateVolumeMountsAndVolumes(spec, + util.NewOrderedMapWithKVStrings([][]string{{"/empty-dir-2/mount/path", "new-empty-dir-volume-name-2"}}), + []string{}, + util.NewOrderedMapWithKVStrings([][]string{{"new-empty-dir-volume-name-2", "emptyDir:new-empty-dir-volume-name-2:type=Memory,size=10Gi"}}), + []string{}) + assert.NilError(t, err) + + err = UpdateVolumeMountsAndVolumes(spec, + util.NewOrderedMapWithKVStrings([][]string{{"/empty-dir-3/mount/path", "new-empty-dir-volume-name-3"}}), + []string{}, + util.NewOrderedMapWithKVStrings([][]string{{"new-empty-dir-volume-name-3", "emptyDir:new-empty-dir-volume-name-3:type=Memory"}}), + []string{}) + assert.NilError(t, err) + + err = UpdateVolumeMountsAndVolumes(spec, + util.NewOrderedMapWithKVStrings([][]string{{"/empty-dir-4/mount/path", "new-empty-dir-volume-name-4"}}), + []string{}, + util.NewOrderedMapWithKVStrings([][]string{{"new-empty-dir-volume-name-4", "emptyDir:new-empty-dir-volume-name-4:size=10Gi"}}), + []string{}) + assert.NilError(t, err) + + err = UpdateVolumeMountsAndVolumes(spec, + util.NewOrderedMapWithKVStrings([][]string{{"/empty-dir-5/mount/path", "emptyDir:new-empty-dir-volume-name-5"}}), + []string{}, + util.NewOrderedMap(), + []string{}) + assert.NilError(t, err) + + assert.Equal(t, len(spec.Volumes), 9) + assert.Equal(t, len(container.VolumeMounts), 11) + assert.Equal(t, spec.Volumes[0].Name, "existing-config-map-volume-name-2") assert.Equal(t, spec.Volumes[0].ConfigMap.Name, "updated-config-map") assert.Equal(t, spec.Volumes[1].Name, "existing-secret-volume-name-2") assert.Equal(t, spec.Volumes[1].Secret.SecretName, "updated-secret") - assert.Equal(t, spec.Volumes[2].Name, "new-config-map-volume-name") - assert.Equal(t, spec.Volumes[2].ConfigMap.Name, "new-config-map") - assert.Equal(t, spec.Volumes[3].Name, "new-secret-volume-name") - assert.Equal(t, spec.Volumes[3].Secret.SecretName, "new-secret") + assert.Equal(t, spec.Volumes[2].Name, "new-empty-dir-volume-name-1") + assert.Equal(t, spec.Volumes[2].EmptyDir.Medium, corev1.StorageMediumDefault) + assert.Assert(t, spec.Volumes[2].EmptyDir.SizeLimit == nil) + assert.Equal(t, spec.Volumes[3].Name, "new-empty-dir-volume-name-2") + assert.Equal(t, spec.Volumes[3].EmptyDir.Medium, corev1.StorageMediumMemory) + assert.DeepEqual(t, spec.Volumes[3].EmptyDir.SizeLimit, &quantity) + assert.Equal(t, spec.Volumes[4].Name, "new-empty-dir-volume-name-3") + assert.Equal(t, spec.Volumes[4].EmptyDir.Medium, corev1.StorageMediumMemory) + assert.Equal(t, spec.Volumes[5].Name, "new-empty-dir-volume-name-4") + assert.DeepEqual(t, spec.Volumes[5].EmptyDir.SizeLimit, &quantity) + assert.Equal(t, spec.Volumes[6].Name, "new-config-map-volume-name") + assert.Equal(t, spec.Volumes[6].ConfigMap.Name, "new-config-map") + assert.Equal(t, spec.Volumes[7].Name, "new-secret-volume-name") + assert.Equal(t, spec.Volumes[7].Secret.SecretName, "new-secret") + assert.Assert(t, strings.Contains(spec.Volumes[8].Name, "empty-dir-5")) + assert.Equal(t, spec.Volumes[8].EmptyDir.Medium, corev1.StorageMediumDefault) + assert.Assert(t, spec.Volumes[8].EmptyDir.SizeLimit == nil) assert.Equal(t, container.VolumeMounts[0].Name, "existing-config-map-volume-name-2") assert.Equal(t, container.VolumeMounts[0].MountPath, "/existing-config-map-2/mount/path") assert.Equal(t, container.VolumeMounts[1].Name, "existing-secret-volume-name-2") assert.Equal(t, container.VolumeMounts[1].MountPath, "/existing-secret-2/mount/path") - assert.Equal(t, container.VolumeMounts[2].Name, "new-config-map-volume-name") - assert.Equal(t, container.VolumeMounts[2].MountPath, "/new-config-map/mount/path") - assert.Equal(t, container.VolumeMounts[3].Name, "existing-config-map-volume-name-2") - assert.Equal(t, container.VolumeMounts[3].MountPath, "/updated-config-map/mount/path") - assert.Equal(t, container.VolumeMounts[4].Name, "new-secret-volume-name") - assert.Equal(t, container.VolumeMounts[4].MountPath, "/new-secret/mount/path") - assert.Equal(t, container.VolumeMounts[5].Name, "existing-secret-volume-name-2") - assert.Equal(t, container.VolumeMounts[5].MountPath, "/updated-secret/mount/path") + assert.Equal(t, container.VolumeMounts[2].Name, "new-empty-dir-volume-name-1") + assert.Equal(t, container.VolumeMounts[2].MountPath, "/empty-dir-1/mount/path") + assert.Equal(t, container.VolumeMounts[3].Name, "new-empty-dir-volume-name-2") + assert.Equal(t, container.VolumeMounts[3].MountPath, "/empty-dir-2/mount/path") + assert.Equal(t, container.VolumeMounts[4].Name, "new-empty-dir-volume-name-3") + assert.Equal(t, container.VolumeMounts[4].MountPath, "/empty-dir-3/mount/path") + assert.Equal(t, container.VolumeMounts[5].Name, "new-empty-dir-volume-name-4") + assert.Equal(t, container.VolumeMounts[5].MountPath, "/empty-dir-4/mount/path") + assert.Equal(t, container.VolumeMounts[6].MountPath, "/empty-dir-5/mount/path") + assert.Equal(t, container.VolumeMounts[7].Name, "new-config-map-volume-name") + assert.Equal(t, container.VolumeMounts[7].MountPath, "/new-config-map/mount/path") + assert.Equal(t, container.VolumeMounts[8].Name, "existing-config-map-volume-name-2") + assert.Equal(t, container.VolumeMounts[8].MountPath, "/updated-config-map/mount/path") + assert.Equal(t, container.VolumeMounts[9].Name, "new-secret-volume-name") + assert.Equal(t, container.VolumeMounts[9].MountPath, "/new-secret/mount/path") + assert.Equal(t, container.VolumeMounts[10].Name, "existing-secret-volume-name-2") + assert.Equal(t, container.VolumeMounts[10].MountPath, "/updated-secret/mount/path") } func TestUpdateContainerImage(t *testing.T) {