mirror of https://github.com/knative/func.git
feat: `func config envs` - interactive prompt (#396)
Signed-off-by: Zbynek Roubalik <zroubali@redhat.com>
This commit is contained in:
parent
4711638495
commit
83a9ca684f
|
@ -72,14 +72,20 @@ func runConfigCmd(cmd *cobra.Command, args []string) (err error) {
|
|||
case "Add":
|
||||
if answers.SelectedConfig == "Volumes" {
|
||||
err = runAddVolumesPrompt(cmd.Context(), function)
|
||||
} else if answers.SelectedConfig == "Environment values" {
|
||||
err = runAddEnvsPrompt(cmd.Context(), function)
|
||||
}
|
||||
case "Remove":
|
||||
if answers.SelectedConfig == "Volumes" {
|
||||
err = runRemoveVolumesPrompt(function)
|
||||
} else if answers.SelectedConfig == "Environment values" {
|
||||
err = runRemoveEnvsPrompt(function)
|
||||
}
|
||||
case "List":
|
||||
if answers.SelectedConfig == "Volumes" {
|
||||
listVolumes(function)
|
||||
} else if answers.SelectedConfig == "Environment values" {
|
||||
listEnvs(function)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,425 @@
|
|||
package cmd
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/AlecAivazis/survey/v2"
|
||||
"github.com/AlecAivazis/survey/v2/terminal"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
bosonFunc "github.com/boson-project/func"
|
||||
"github.com/boson-project/func/k8s"
|
||||
"github.com/boson-project/func/utils"
|
||||
)
|
||||
|
||||
func init() {
|
||||
configCmd.AddCommand(configEnvsCmd)
|
||||
configEnvsCmd.Flags().StringP("path", "p", cwd(), "Path to the project directory (Env: $FUNC_PATH)")
|
||||
configEnvsCmd.AddCommand(configEnvsAddCmd)
|
||||
configEnvsAddCmd.Flags().StringP("path", "p", cwd(), "Path to the project directory (Env: $FUNC_PATH)")
|
||||
configEnvsCmd.AddCommand(configEnvsRemoveCmd)
|
||||
configEnvsRemoveCmd.Flags().StringP("path", "p", cwd(), "Path to the project directory (Env: $FUNC_PATH)")
|
||||
}
|
||||
|
||||
var configEnvsCmd = &cobra.Command{
|
||||
Use: "envs",
|
||||
Short: "List and manage configured environment variable for a function",
|
||||
Long: `List and manage configured environment variable for a function
|
||||
|
||||
Prints configured Environment variable for a function project present in
|
||||
the current directory or from the directory specified with --path.
|
||||
`,
|
||||
SuggestFor: []string{"ensv", "env"},
|
||||
PreRunE: bindEnv("path"),
|
||||
RunE: func(cmd *cobra.Command, args []string) (err error) {
|
||||
function, err := initConfigCommand(args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
listEnvs(function)
|
||||
|
||||
return
|
||||
},
|
||||
}
|
||||
|
||||
var configEnvsAddCmd = &cobra.Command{
|
||||
Use: "add",
|
||||
Short: "Add environment variable to the function configuration",
|
||||
Long: `Add environment variable to the function configuration
|
||||
|
||||
Interactive prompt to add Environment variables to the function project
|
||||
in the current directory or from the directory specified with --path.
|
||||
|
||||
The environment variable can be set directly from a value,
|
||||
from an environment variable on the local machine or from Secrets and ConfigMaps.
|
||||
`,
|
||||
SuggestFor: []string{"ad", "create", "insert", "append"},
|
||||
PreRunE: bindEnv("path"),
|
||||
RunE: func(cmd *cobra.Command, args []string) (err error) {
|
||||
function, err := initConfigCommand(args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return runAddEnvsPrompt(cmd.Context(), function)
|
||||
},
|
||||
}
|
||||
|
||||
var configEnvsRemoveCmd = &cobra.Command{
|
||||
Use: "remove",
|
||||
Short: "Remove environment variable from the function configuration",
|
||||
Long: `Remove environment variable from the function configuration
|
||||
|
||||
Interactive prompt to remove Environment variables from the function project
|
||||
in the current directory or from the directory specified with --path.
|
||||
`,
|
||||
SuggestFor: []string{"del", "delete", "rmeove"},
|
||||
PreRunE: bindEnv("path"),
|
||||
RunE: func(cmd *cobra.Command, args []string) (err error) {
|
||||
function, err := initConfigCommand(args)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
return runRemoveEnvsPrompt(function)
|
||||
},
|
||||
}
|
||||
|
||||
func listEnvs(f bosonFunc.Function) {
|
||||
if len(f.Envs) == 0 {
|
||||
fmt.Println("There aren't any configured Environment variables")
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println("Configured Environment variables:")
|
||||
for _, e := range f.Envs {
|
||||
fmt.Println(" - ", e.String())
|
||||
}
|
||||
}
|
||||
|
||||
func runAddEnvsPrompt(ctx context.Context, f bosonFunc.Function) (err error) {
|
||||
|
||||
insertToIndex := 0
|
||||
|
||||
// SECTION - if there are some envs already set, let choose the position of the new entry
|
||||
if len(f.Envs) > 0 {
|
||||
options := []string{}
|
||||
for _, e := range f.Envs {
|
||||
options = append(options, fmt.Sprintf("Insert before: %s", e.String()))
|
||||
}
|
||||
options = append(options, "Insert here.")
|
||||
|
||||
selectedEnv := ""
|
||||
prompt := &survey.Select{
|
||||
Message: "Where do you want to add the Environment variable?",
|
||||
Options: options,
|
||||
Default: options[len(options)-1],
|
||||
}
|
||||
err = survey.AskOne(prompt, &selectedEnv)
|
||||
if err != nil {
|
||||
if err == terminal.InterruptErr {
|
||||
return nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
for i, option := range options {
|
||||
if option == selectedEnv {
|
||||
insertToIndex = i
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// SECTION - select the type of Environment variable to be added
|
||||
secrets, err := k8s.ListSecretsNames(ctx, f.Namespace)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
configMaps, err := k8s.ListConfigMapsNames(ctx, f.Namespace)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
selectedOption := ""
|
||||
const (
|
||||
optionEnvValue = "Environment variable with a specified value"
|
||||
optionEnvLocal = "Value from a local environment variable"
|
||||
optionEnvConfigMap = "ConfigMap: all key=value pairs as environment variables"
|
||||
optionEnvConfigMapKey = "ConfigMap: value from a key"
|
||||
optionEnvSecret = "Secret: all key=value pairs as environment variables"
|
||||
optionEnvSecretKey = "Secret: value from a key"
|
||||
)
|
||||
options := []string{optionEnvValue, optionEnvLocal}
|
||||
|
||||
if len(configMaps) > 0 {
|
||||
options = append(options, optionEnvConfigMap)
|
||||
options = append(options, optionEnvConfigMapKey)
|
||||
}
|
||||
if len(secrets) > 0 {
|
||||
options = append(options, optionEnvSecret)
|
||||
options = append(options, optionEnvSecretKey)
|
||||
}
|
||||
|
||||
err = survey.AskOne(&survey.Select{
|
||||
Message: "What type of Environment variable do you want to add?",
|
||||
Options: options,
|
||||
}, &selectedOption)
|
||||
if err != nil {
|
||||
if err == terminal.InterruptErr {
|
||||
return nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
newEnv := bosonFunc.Env{}
|
||||
|
||||
switch selectedOption {
|
||||
// SECTION - add new Environment variable with the specified value
|
||||
case optionEnvValue:
|
||||
qs := []*survey.Question{
|
||||
{
|
||||
Name: "name",
|
||||
Prompt: &survey.Input{Message: "Please specify the Environment variable name:"},
|
||||
Validate: func(val interface{}) error {
|
||||
return utils.ValidateEnvVarName(val.(string))
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "value",
|
||||
Prompt: &survey.Input{Message: "Please specify the Environment variable value:"},
|
||||
},
|
||||
}
|
||||
answers := struct {
|
||||
Name string
|
||||
Value string
|
||||
}{}
|
||||
|
||||
err = survey.Ask(qs, &answers)
|
||||
if err != nil {
|
||||
if err == terminal.InterruptErr {
|
||||
return nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
newEnv.Name = &answers.Name
|
||||
newEnv.Value = &answers.Value
|
||||
|
||||
// SECTION - add new Environment variable with value from a local environment variable
|
||||
case optionEnvLocal:
|
||||
qs := []*survey.Question{
|
||||
{
|
||||
Name: "name",
|
||||
Prompt: &survey.Input{Message: "Please specify the Environment variable name:"},
|
||||
Validate: func(val interface{}) error {
|
||||
return utils.ValidateEnvVarName(val.(string))
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "value",
|
||||
Prompt: &survey.Input{Message: "Please specify the local Environment variable:"},
|
||||
Validate: survey.Required,
|
||||
},
|
||||
}
|
||||
answers := struct {
|
||||
Name string
|
||||
Value string
|
||||
}{}
|
||||
|
||||
err = survey.Ask(qs, &answers)
|
||||
if err != nil {
|
||||
if err == terminal.InterruptErr {
|
||||
return nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if _, ok := os.LookupEnv(answers.Value); !ok {
|
||||
fmt.Printf("Warning: specified local environment variable %q is not set\n", answers.Value)
|
||||
}
|
||||
|
||||
value := fmt.Sprintf("{{ env:%s }}", answers.Value)
|
||||
newEnv.Name = &answers.Name
|
||||
newEnv.Value = &value
|
||||
|
||||
// SECTION - Add all key=value pairs from ConfigMap as environment variables
|
||||
case optionEnvConfigMap:
|
||||
selectedResource := ""
|
||||
err = survey.AskOne(&survey.Select{
|
||||
Message: "Which ConfigMap do you want to use?",
|
||||
Options: configMaps,
|
||||
}, &selectedResource)
|
||||
if err != nil {
|
||||
if err == terminal.InterruptErr {
|
||||
return nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
value := fmt.Sprintf("{{ configMap:%s }}", selectedResource)
|
||||
newEnv.Value = &value
|
||||
|
||||
// SECTION - Environment variable with value from a key from ConfigMap
|
||||
case optionEnvConfigMapKey:
|
||||
qs := []*survey.Question{
|
||||
{
|
||||
Name: "configmap",
|
||||
Prompt: &survey.Select{
|
||||
Message: "Which ConfigMap do you want to use?",
|
||||
Options: configMaps,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "name",
|
||||
Prompt: &survey.Input{Message: "Please specify the Environment variable name:"},
|
||||
Validate: func(val interface{}) error {
|
||||
return utils.ValidateEnvVarName(val.(string))
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "key",
|
||||
Prompt: &survey.Input{Message: "Please specify a key from the selected ConfigMap:"},
|
||||
Validate: survey.Required,
|
||||
},
|
||||
}
|
||||
answers := struct {
|
||||
ConfigMap string
|
||||
Name string
|
||||
Key string
|
||||
}{}
|
||||
|
||||
err = survey.Ask(qs, &answers)
|
||||
if err != nil {
|
||||
if err == terminal.InterruptErr {
|
||||
return nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
value := fmt.Sprintf("{{ configMap:%s:%s }}", answers.ConfigMap, answers.Key)
|
||||
newEnv.Name = &answers.Name
|
||||
newEnv.Value = &value
|
||||
|
||||
// SECTION - Add all key=value pairs from Secret as environment variables
|
||||
case optionEnvSecret:
|
||||
selectedResource := ""
|
||||
err = survey.AskOne(&survey.Select{
|
||||
Message: "Which Secret do you want to use?",
|
||||
Options: secrets,
|
||||
}, &selectedResource)
|
||||
if err != nil {
|
||||
if err == terminal.InterruptErr {
|
||||
return nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
value := fmt.Sprintf("{{ secret:%s }}", selectedResource)
|
||||
newEnv.Value = &value
|
||||
|
||||
// SECTION - Environment variable with value from a key from Secret
|
||||
case optionEnvSecretKey:
|
||||
qs := []*survey.Question{
|
||||
{
|
||||
Name: "secret",
|
||||
Prompt: &survey.Select{
|
||||
Message: "Which Secret do you want to use?",
|
||||
Options: secrets,
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "name",
|
||||
Prompt: &survey.Input{Message: "Please specify the Environment variable name:"},
|
||||
Validate: func(val interface{}) error {
|
||||
return utils.ValidateEnvVarName(val.(string))
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "key",
|
||||
Prompt: &survey.Input{Message: "Please specify a key from the selected Secret:"},
|
||||
Validate: survey.Required,
|
||||
},
|
||||
}
|
||||
answers := struct {
|
||||
Secret string
|
||||
Name string
|
||||
Key string
|
||||
}{}
|
||||
|
||||
err = survey.Ask(qs, &answers)
|
||||
if err != nil {
|
||||
if err == terminal.InterruptErr {
|
||||
return nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
value := fmt.Sprintf("{{ secret:%s:%s }}", answers.Secret, answers.Key)
|
||||
newEnv.Name = &answers.Name
|
||||
newEnv.Value = &value
|
||||
}
|
||||
|
||||
// we have all necessary information -> let's insert the env to the selected position in the list
|
||||
if insertToIndex == len(f.Envs) {
|
||||
f.Envs = append(f.Envs, newEnv)
|
||||
} else {
|
||||
f.Envs = append(f.Envs[:insertToIndex+1], f.Envs[insertToIndex:]...)
|
||||
f.Envs[insertToIndex] = newEnv
|
||||
}
|
||||
|
||||
err = f.WriteConfig()
|
||||
if err == nil {
|
||||
fmt.Println("Environment variable entry was added to the function configuration")
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
func runRemoveEnvsPrompt(f bosonFunc.Function) (err error) {
|
||||
if len(f.Envs) == 0 {
|
||||
fmt.Println("There aren't any configured Environment variables")
|
||||
return
|
||||
}
|
||||
|
||||
options := []string{}
|
||||
for _, e := range f.Envs {
|
||||
options = append(options, e.String())
|
||||
}
|
||||
|
||||
selectedEnv := ""
|
||||
prompt := &survey.Select{
|
||||
Message: "Which Environment variables do you want to remove?",
|
||||
Options: options,
|
||||
}
|
||||
err = survey.AskOne(prompt, &selectedEnv)
|
||||
if err != nil {
|
||||
if err == terminal.InterruptErr {
|
||||
return nil
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var newEnvs bosonFunc.Envs
|
||||
removed := false
|
||||
for i, e := range f.Envs {
|
||||
if e.String() == selectedEnv {
|
||||
newEnvs = append(f.Envs[:i], f.Envs[i+1:]...)
|
||||
removed = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if removed {
|
||||
f.Envs = newEnvs
|
||||
err = f.WriteConfig()
|
||||
if err == nil {
|
||||
fmt.Println("Environment variable entry was removed from the function configuration")
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
|
@ -53,8 +53,7 @@ Interactive prompt to add Secrets and ConfigMaps as Volume mounts to the functio
|
|||
in the current directory or from the directory specified with --path.
|
||||
`,
|
||||
SuggestFor: []string{"ad", "create", "insert", "append"},
|
||||
//ValidArgsFunction: CompleteFunctionList,
|
||||
PreRunE: bindEnv("path"),
|
||||
PreRunE: bindEnv("path"),
|
||||
RunE: func(cmd *cobra.Command, args []string) (err error) {
|
||||
function, err := initConfigCommand(args)
|
||||
if err != nil {
|
||||
|
@ -192,10 +191,10 @@ func runAddVolumesPrompt(ctx context.Context, f bosonFunc.Function) (err error)
|
|||
}
|
||||
|
||||
f.Volumes = append(f.Volumes, newVolume)
|
||||
|
||||
|
||||
err = f.WriteConfig()
|
||||
if err == nil {
|
||||
fmt.Println("Volume was added to the function configuration")
|
||||
fmt.Println("Volume entry was added to the function configuration")
|
||||
}
|
||||
|
||||
return
|
||||
|
@ -239,7 +238,7 @@ func runRemoveVolumesPrompt(f bosonFunc.Function) (err error) {
|
|||
f.Volumes = newVolumes
|
||||
err = f.WriteConfig()
|
||||
if err == nil {
|
||||
fmt.Println("Volume was removed from the function configuration")
|
||||
fmt.Println("Volume entry was removed from the function configuration")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
29
config.go
29
config.go
|
@ -47,6 +47,35 @@ type Env struct {
|
|||
Value *string `yaml:"value"`
|
||||
}
|
||||
|
||||
func (e Env) String() string {
|
||||
if e.Name == nil && e.Value != nil {
|
||||
match := regWholeSecret.FindStringSubmatch(*e.Value)
|
||||
if len(match) == 2 {
|
||||
return fmt.Sprintf("All key=value pairs from Secret \"%s\"", match[1])
|
||||
}
|
||||
match = regWholeConfigMap.FindStringSubmatch(*e.Value)
|
||||
if len(match) == 2 {
|
||||
return fmt.Sprintf("All key=value pairs from ConfigMap \"%s\"", match[1])
|
||||
}
|
||||
} else if e.Name != nil && e.Value != nil {
|
||||
match := regKeyFromSecret.FindStringSubmatch(*e.Value)
|
||||
if len(match) == 3 {
|
||||
return fmt.Sprintf("Env \"%s\" with value set from key \"%s\" from Secret \"%s\"", *e.Name, match[2], match[1])
|
||||
}
|
||||
match = regKeyFromConfigMap.FindStringSubmatch(*e.Value)
|
||||
if len(match) == 3 {
|
||||
return fmt.Sprintf("Env \"%s\" with value set from key \"%s\" from ConfigMap \"%s\"", *e.Name, match[2], match[1])
|
||||
}
|
||||
match = regLocalEnv.FindStringSubmatch(*e.Value)
|
||||
if len(match) == 2 {
|
||||
return fmt.Sprintf("Env \"%s\" with value set from local env variable \"%s\"", *e.Name, match[1])
|
||||
}
|
||||
|
||||
return fmt.Sprintf("Env \"%s\" with value \"%s\"", *e.Name, *e.Value)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type Options struct {
|
||||
Scale *ScaleOptions `yaml:"scale,omitempty"`
|
||||
}
|
||||
|
|
|
@ -185,17 +185,36 @@ Configured Volumes mounts:
|
|||
- ConfigMap "mycm" mounted at path: "/workspace/configmap"
|
||||
```
|
||||
|
||||
### `config envs`
|
||||
|
||||
This command lists configured Environment variables:
|
||||
```console
|
||||
func config envs [-p <path>]
|
||||
```
|
||||
|
||||
Invokes interactive prompt to add Environment variables to the function configuration
|
||||
```console
|
||||
func config envs add [-p <path>]
|
||||
```
|
||||
|
||||
Invokes interactive prompt to remove Environment variables from the function configuration
|
||||
```console
|
||||
func config envs remove [-p <path>]
|
||||
```
|
||||
|
||||
### `config volumes`
|
||||
|
||||
This command lists configured Volumes:
|
||||
```console
|
||||
func config volumes [-p <path>]
|
||||
```
|
||||
|
||||
Invokes interactive prompt that allows addind Volumes to the function configuration
|
||||
Invokes interactive prompt to add Volumes to the function configuration
|
||||
```console
|
||||
func config volumes add [-p <path>]
|
||||
```
|
||||
|
||||
Invokes interactive prompt that allows removing Volumes from the function configuration
|
||||
Invokes interactive prompt to remove Volumes from the function configuration
|
||||
```console
|
||||
func config volumes remove [-p <path>]
|
||||
```
|
||||
```
|
||||
|
|
Loading…
Reference in New Issue