feat: add noninteractive flow to volume config (#2883)

This commit is contained in:
Luke Kingland 2025-06-27 16:10:14 +09:00 committed by GitHub
parent 347a901c16
commit a384d6e728
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 189 additions and 8 deletions

View File

@ -66,19 +66,49 @@ func NewConfigVolumesAddCmd() *cobra.Command {
Interactive prompt to add Secrets and ConfigMaps as Volume mounts to the function project Interactive prompt to add Secrets and ConfigMaps as Volume mounts to the function project
in the current directory or from the directory specified with --path. in the current directory or from the directory specified with --path.
For non-interactive usage, use flags to specify the volume type and configuration.
`, `,
Example: `# Add a ConfigMap volume
{{rootCmdUse}} config volumes add --type=configmap --source=my-config --path=/etc/config
# Add a Secret volume
{{rootCmdUse}} config volumes add --type=secret --source=my-secret --path=/etc/secret
# Add a PersistentVolumeClaim volume
{{rootCmdUse}} config volumes add --type=pvc --source=my-pvc --path=/data
{{rootCmdUse}} config volumes add --type=pvc --source=my-pvc --path=/data --read-only
# Add an EmptyDir volume
{{rootCmdUse}} config volumes add --type=emptydir --path=/tmp/cache
{{rootCmdUse}} config volumes add --type=emptydir --path=/tmp/cache --size=1Gi --medium=Memory`,
SuggestFor: []string{"ad", "create", "insert", "append"}, SuggestFor: []string{"ad", "create", "insert", "append"},
PreRunE: bindEnv("path", "verbose"), PreRunE: bindEnv("path", "verbose", "type", "source", "mount-path", "read-only", "size", "medium"),
RunE: func(cmd *cobra.Command, args []string) (err error) { RunE: func(cmd *cobra.Command, args []string) (err error) {
function, err := initConfigCommand(defaultLoaderSaver) function, err := initConfigCommand(defaultLoaderSaver)
if err != nil { if err != nil {
return return
} }
// Check if flags are provided for non-interactive mode
volumeType, _ := cmd.Flags().GetString("type")
if volumeType != "" {
return runAddVolume(cmd, function)
}
// Fall back to interactive mode
return runAddVolumesPrompt(cmd.Context(), function) return runAddVolumesPrompt(cmd.Context(), function)
}, },
} }
// Add flags for non-interactive mode
cmd.Flags().StringP("type", "t", "", "Volume type: configmap, secret, pvc, or emptydir")
cmd.Flags().StringP("source", "s", "", "Name of the ConfigMap, Secret, or PVC to mount (not used for emptydir)")
cmd.Flags().StringP("mount-path", "m", "", "Path where the volume should be mounted in the container")
cmd.Flags().BoolP("read-only", "r", false, "Mount volume as read-only (only for PVC)")
cmd.Flags().StringP("size", "", "", "Maximum size limit for EmptyDir volume (e.g., 1Gi)")
cmd.Flags().StringP("medium", "", "", "Storage medium for EmptyDir volume: 'Memory' or '' (default)")
return cmd return cmd
} }
@ -90,20 +120,34 @@ func NewConfigVolumesRemoveCmd() *cobra.Command {
Interactive prompt to remove Volume mounts from the function project Interactive prompt to remove Volume mounts from the function project
in the current directory or from the directory specified with --path. in the current directory or from the directory specified with --path.
For non-interactive usage, use the --mount-path flag to specify which volume to remove.
`, `,
Example: `# Remove a volume by its mount path
{{rootCmdUse}} config volumes remove --mount-path=/etc/config`,
Aliases: []string{"rm"}, Aliases: []string{"rm"},
SuggestFor: []string{"del", "delete", "rmeove"}, SuggestFor: []string{"del", "delete", "rmeove"},
PreRunE: bindEnv("path", "verbose"), PreRunE: bindEnv("path", "verbose", "mount-path"),
RunE: func(cmd *cobra.Command, args []string) (err error) { RunE: func(cmd *cobra.Command, args []string) (err error) {
function, err := initConfigCommand(defaultLoaderSaver) function, err := initConfigCommand(defaultLoaderSaver)
if err != nil { if err != nil {
return return
} }
// Check if mount-path flag is provided for non-interactive mode
mountPath, _ := cmd.Flags().GetString("mount-path")
if mountPath != "" {
return runRemoveVolume(cmd, function, mountPath)
}
// Fall back to interactive mode
return runRemoveVolumesPrompt(function) return runRemoveVolumesPrompt(function)
}, },
} }
// Add flag for non-interactive mode
cmd.Flags().StringP("mount-path", "m", "", "Path of the volume mount to remove")
return cmd return cmd
} }
@ -286,3 +330,104 @@ func runRemoveVolumesPrompt(f fn.Function) (err error) {
return return
} }
// runAddVolume handles adding volumes using command line flags
func runAddVolume(cmd *cobra.Command, f fn.Function) error {
var (
volumeType, _ = cmd.Flags().GetString("type")
source, _ = cmd.Flags().GetString("source")
mountPath, _ = cmd.Flags().GetString("mount-path")
readOnly, _ = cmd.Flags().GetBool("read-only")
sizeLimit, _ = cmd.Flags().GetString("size")
medium, _ = cmd.Flags().GetString("medium")
)
// Validate mount path
if mountPath == "" {
return fmt.Errorf("--mount-path is required")
}
if !strings.HasPrefix(mountPath, "/") {
return fmt.Errorf("mount path must be an absolute path (start with /)")
}
// Create the volume based on type
newVolume := fn.Volume{Path: &mountPath}
// All volumeTypes except emptydir require a source
if volumeType != "emptydir" && source == "" {
return fmt.Errorf("--source is required for %s volumes", volumeType)
}
switch volumeType {
case "configmap":
newVolume.ConfigMap = &source
case "secret":
newVolume.Secret = &source
case "pvc":
newVolume.PersistentVolumeClaim = &fn.PersistentVolumeClaim{
ClaimName: &source,
ReadOnly: readOnly,
}
if readOnly {
fmt.Fprintf(cmd.OutOrStderr(), "PersistentVolumeClaim will be mounted as read-only")
}
fmt.Fprintf(cmd.OutOrStderr(), "Please ensure the PersistentVolumeClaim extension flag is enabled:\nhttps://knative.dev/docs/serving/configuration/feature-flags/\n")
case "emptydir":
emptyDir := &fn.EmptyDir{}
if sizeLimit != "" {
emptyDir.SizeLimit = &sizeLimit
}
if medium != "" {
if medium != fn.StorageMediumMemory && medium != fn.StorageMediumDefault {
return fmt.Errorf("invalid medium: must be 'Memory' or empty")
}
emptyDir.Medium = medium
}
newVolume.EmptyDir = emptyDir
fmt.Fprintf(cmd.OutOrStderr(), "Please make sure to enable the EmptyDir extension flag:\nhttps://knative.dev/docs/serving/configuration/feature-flags/\n")
default:
return fmt.Errorf("invalid volume type: %s (must be one of: configmap, secret, pvc, emptydir)", volumeType)
}
// Add the volume to the function
f.Run.Volumes = append(f.Run.Volumes, newVolume)
// Save the function
err := f.Write()
if err == nil {
fmt.Printf("Volume entry was added to the function configuration\n")
fmt.Printf("Added: %s\n", newVolume.String())
}
return err
}
// runRemoveVolume handles removing volumes by mount path
func runRemoveVolume(cmd *cobra.Command, f fn.Function, mountPath string) error {
if !strings.HasPrefix(mountPath, "/") {
return fmt.Errorf("mount path must be an absolute path (start with /)")
}
// Find and remove the volume with the specified path
var newVolumes []fn.Volume
removed := false
for _, v := range f.Run.Volumes {
if v.Path != nil && *v.Path == mountPath {
removed = true
} else {
newVolumes = append(newVolumes, v)
}
}
if !removed {
return fmt.Errorf("no volume found with mount path: %s", mountPath)
}
f.Run.Volumes = newVolumes
err := f.Write()
if err == nil {
fmt.Fprintf(cmd.OutOrStderr(), "Volume entry was removed from the function configuration\n")
fmt.Fprintf(cmd.OutOrStderr(), "Removed volume at path: %s\n", mountPath)
}
return err
}

View File

@ -9,17 +9,43 @@ Add volume to the function configuration
Interactive prompt to add Secrets and ConfigMaps as Volume mounts to the function project Interactive prompt to add Secrets and ConfigMaps as Volume mounts to the function project
in the current directory or from the directory specified with --path. in the current directory or from the directory specified with --path.
For non-interactive usage, use flags to specify the volume type and configuration.
``` ```
func config volumes add func config volumes add
``` ```
### Examples
```
# Add a ConfigMap volume
func config volumes add --type=configmap --source=my-config --path=/etc/config
# Add a Secret volume
func config volumes add --type=secret --source=my-secret --path=/etc/secret
# Add a PersistentVolumeClaim volume
func config volumes add --type=pvc --source=my-pvc --path=/data
func config volumes add --type=pvc --source=my-pvc --path=/data --read-only
# Add an EmptyDir volume
func config volumes add --type=emptydir --path=/tmp/cache
func config volumes add --type=emptydir --path=/tmp/cache --size=1Gi --medium=Memory
```
### Options ### Options
``` ```
-h, --help help for add -h, --help help for add
-p, --path string Path to the function. Default is current directory ($FUNC_PATH) --medium string Storage medium for EmptyDir volume: 'Memory' or '' (default)
-v, --verbose Print verbose logs ($FUNC_VERBOSE) -m, --mount-path string Path where the volume should be mounted in the container
-p, --path string Path to the function. Default is current directory ($FUNC_PATH)
-r, --read-only Mount volume as read-only (only for PVC)
--size string Maximum size limit for EmptyDir volume (e.g., 1Gi)
-s, --source string Name of the ConfigMap, Secret, or PVC to mount (not used for emptydir)
-t, --type string Volume type: configmap, secret, pvc, or emptydir
-v, --verbose Print verbose logs ($FUNC_VERBOSE)
``` ```
### SEE ALSO ### SEE ALSO

View File

@ -9,17 +9,27 @@ Remove volume from the function configuration
Interactive prompt to remove Volume mounts from the function project Interactive prompt to remove Volume mounts from the function project
in the current directory or from the directory specified with --path. in the current directory or from the directory specified with --path.
For non-interactive usage, use the --mount-path flag to specify which volume to remove.
``` ```
func config volumes remove func config volumes remove
``` ```
### Examples
```
# Remove a volume by its mount path
func config volumes remove --mount-path=/etc/config
```
### Options ### Options
``` ```
-h, --help help for remove -h, --help help for remove
-p, --path string Path to the function. Default is current directory ($FUNC_PATH) -m, --mount-path string Path of the volume mount to remove
-v, --verbose Print verbose logs ($FUNC_VERBOSE) -p, --path string Path to the function. Default is current directory ($FUNC_PATH)
-v, --verbose Print verbose logs ($FUNC_VERBOSE)
``` ```
### SEE ALSO ### SEE ALSO