Skip to content

Commit

Permalink
feat: reference Secrets in envs and volumes sections in config (#369
Browse files Browse the repository at this point in the history
)

* feat: reference Secrets in `envs` and `volumes` sections in config

Signed-off-by: Zbynek Roubalik <zroubali@redhat.com>
  • Loading branch information
zroubalik committed Jun 2, 2021
1 parent 4f0641f commit 9d7fd34
Show file tree
Hide file tree
Showing 13 changed files with 1,124 additions and 122 deletions.
2 changes: 1 addition & 1 deletion cmd/delete_test.go
Expand Up @@ -51,7 +51,7 @@ trigger: http
builder: quay.io/boson/faas-go-builder
builderMap:
default: quay.io/boson/faas-go-builder
env: {}
envs: []
annotations: {}
`
tmpDir, err := ioutil.TempDir("", "bar")
Expand Down
34 changes: 26 additions & 8 deletions cmd/deploy.go
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/pkg/errors"
"github.com/spf13/cobra"
"golang.org/x/term"
"knative.dev/client/pkg/util"

bosonFunc "github.com/boson-project/func"
"github.com/boson-project/func/buildpacks"
Expand All @@ -25,8 +26,8 @@ import (
func init() {
root.AddCommand(deployCmd)
deployCmd.Flags().BoolP("confirm", "c", false, "Prompt to confirm all configuration options (Env: $FUNC_CONFIRM)")
deployCmd.Flags().StringArrayP("env", "e", []string{}, "Environment variable to set in the form NAME=VALUE. " +
"You may provide this flag multiple times for setting multiple environment variables. " +
deployCmd.Flags().StringArrayP("env", "e", []string{}, "Environment variable to set in the form NAME=VALUE. "+
"You may provide this flag multiple times for setting multiple environment variables. "+
"To unset, specify the environment variable name followed by a \"-\" (e.g., NAME-).")
deployCmd.Flags().StringP("image", "i", "", "Full image name in the form [registry]/[namespace]/[name]:[tag] (optional). This option takes precedence over --registry (Env: $FUNC_IMAGE")
deployCmd.Flags().StringP("namespace", "n", "", "Namespace of the function to undeploy. By default, the namespace in func.yaml is used or the actual active namespace if not set in the configuration. (Env: $FUNC_NAMESPACE)")
Expand Down Expand Up @@ -66,14 +67,21 @@ kn func deploy --image quay.io/myuser/myfunc -n myns

func runDeploy(cmd *cobra.Command, _ []string) (err error) {

config := newDeployConfig(cmd).Prompt()
config, err := newDeployConfig(cmd)
if err != nil {
return err
}
config = config.Prompt()

function, err := functionWithOverrides(config.Path, functionOverrides{Namespace: config.Namespace, Image: config.Image})
if err != nil {
return
}

function.Env = mergeEnvMaps(function.Env, config.Env)
function.Envs, err = mergeEnvs(function.Envs, config.EnvToUpdate, config.EnvToRemove)
if err != nil {
return
}

// Check if the Function has been initialized
if !function.Initialized() {
Expand Down Expand Up @@ -260,21 +268,31 @@ type deployConfig struct {
// Build the associated Function before deploying.
Build bool

Env map[string]string
// Envs passed via cmd to be added/updated
EnvToUpdate *util.OrderedMap

// Envs passed via cmd to removed
EnvToRemove []string
}

// newDeployConfig creates a buildConfig populated from command flags and
// environment variables; in that precedence.
func newDeployConfig(cmd *cobra.Command) deployConfig {
func newDeployConfig(cmd *cobra.Command) (deployConfig, error) {
envToUpdate, envToRemove, err := envFromCmd(cmd)
if err != nil {
return deployConfig{}, err
}

return deployConfig{
buildConfig: newBuildConfig(),
Namespace: viper.GetString("namespace"),
Path: viper.GetString("path"),
Verbose: viper.GetBool("verbose"), // defined on root
Confirm: viper.GetBool("confirm"),
Build: viper.GetBool("build"),
Env: envFromCmd(cmd),
}
EnvToUpdate: envToUpdate,
EnvToRemove: envToRemove,
}, nil
}

// Prompt the user with value of config members, allowing for interaractive changes.
Expand Down
62 changes: 37 additions & 25 deletions cmd/root.go
Expand Up @@ -10,6 +10,8 @@ import (
"github.com/mitchellh/go-homedir"
"github.com/ory/viper"
"github.com/spf13/cobra"
"k8s.io/apimachinery/pkg/util/sets"
"knative.dev/client/pkg/util"

bosonFunc "github.com/boson-project/func"
)
Expand Down Expand Up @@ -251,42 +253,52 @@ func deriveImage(explicitImage, defaultRegistry, path string) string {
return derivedValue // Use the func system's derivation logic.
}

func envFromCmd(cmd *cobra.Command) map[string]string {
envM := make(map[string]string)
func envFromCmd(cmd *cobra.Command) (*util.OrderedMap, []string, error) {
if cmd.Flags().Changed("env") {
envA, err := cmd.Flags().GetStringArray("env")
if err == nil {
for _, s := range envA {
kvp := strings.Split(s, "=")
if len(kvp) == 2 && kvp[0] != "" {
envM[kvp[0]] = kvp[1]
} else if len(kvp) == 1 && kvp[0] != "" {
envM[kvp[0]] = ""
}
}
env, err := cmd.Flags().GetStringArray("env")
if err != nil {
return nil, []string{}, fmt.Errorf("Invalid --env: %w", err)
}
return util.OrderedMapAndRemovalListFromArray(env, "=")
}
return envM
return util.NewOrderedMap(), []string{}, nil
}

func mergeEnvMaps(dest, src map[string]string) map[string]string {
result := make(map[string]string, len(dest)+len(src))
func mergeEnvs(envs bosonFunc.Envs, envToUpdate *util.OrderedMap, envToRemove []string) (bosonFunc.Envs, error) {
updated := sets.NewString()

for name, value := range dest {
if strings.HasSuffix(name, "-") {
if _, ok := src[strings.TrimSuffix(name, "-")]; !ok {
result[name] = value
for i := range envs {
if envs[i].Name != nil {
value, present := envToUpdate.GetString(*envs[i].Name)
if present {
envs[i].Value = &value
updated.Insert(*envs[i].Name)
}
} else {
if _, ok := src[name+"-"]; !ok {
result[name] = value
}
}

it := envToUpdate.Iterator()
for name, value, ok := it.NextString(); ok; name, value, ok = it.NextString() {
if !updated.Has(name) {
n := name
v := value
envs = append(envs, bosonFunc.Env{Name: &n, Value: &v})
}
}

for _, name := range envToRemove {
for i, envVar := range envs {
if *envVar.Name == name {
envs = append(envs[:i], envs[i+1:]...)
break
}
}
}

for name, value := range src {
result[name] = value
errMsg := bosonFunc.ValidateEnvs(envs)
if len(errMsg) > 0 {
return bosonFunc.Envs{}, fmt.Errorf(strings.Join(errMsg, "\n"))
}

return result
return envs, nil
}
97 changes: 79 additions & 18 deletions cmd/root_test.go
@@ -1,57 +1,118 @@
package cmd

import (
"fmt"
"reflect"
"testing"

"knative.dev/client/pkg/util"

bosonFunc "github.com/boson-project/func"
)

func Test_mergeEnvMaps(t *testing.T) {

a := "A"
b := "B"
v1 := "x"
v2 := "y"

type args struct {
dest map[string]string
src map[string]string
envs bosonFunc.Envs
toUpdate *util.OrderedMap
toRemove []string
}
tests := []struct {
name string
args args
want map[string]string
want bosonFunc.Envs
}{
{
"add new var to empty list",
args{
bosonFunc.Envs{},
util.NewOrderedMapWithKVStrings([][]string{{a, v1}}),
[]string{},
},
bosonFunc.Envs{bosonFunc.Env{Name: &a, Value: &v1}},
},
{
"add new var",
args{
map[string]string{"A": "1"},
map[string]string{"B": "2"},
bosonFunc.Envs{bosonFunc.Env{Name: &b, Value: &v2}},
util.NewOrderedMapWithKVStrings([][]string{{a, v1}}),
[]string{},
},
map[string]string{"A": "1", "B": "2"},
bosonFunc.Envs{bosonFunc.Env{Name: &b, Value: &v2}, bosonFunc.Env{Name: &a, Value: &v1}},
},
{
"update var",
args{
map[string]string{"A": "1"},
map[string]string{"A": "2"},
bosonFunc.Envs{bosonFunc.Env{Name: &a, Value: &v1}},
util.NewOrderedMapWithKVStrings([][]string{{a, v2}}),
[]string{},
},
bosonFunc.Envs{bosonFunc.Env{Name: &a, Value: &v2}},
},
{
"update multiple vars",
args{
bosonFunc.Envs{bosonFunc.Env{Name: &a, Value: &v1}, bosonFunc.Env{Name: &b, Value: &v2}},
util.NewOrderedMapWithKVStrings([][]string{{a, v2}, {b, v1}}),
[]string{},
},
map[string]string{"A": "2"},
bosonFunc.Envs{bosonFunc.Env{Name: &a, Value: &v2}, bosonFunc.Env{Name: &b, Value: &v1}},
},
{
"remove var",
args{
map[string]string{"A": "1"},
map[string]string{"A-": ""},
bosonFunc.Envs{bosonFunc.Env{Name: &a, Value: &v1}},
util.NewOrderedMap(),
[]string{a},
},
bosonFunc.Envs{},
},
{
"remove multiple vars",
args{
bosonFunc.Envs{bosonFunc.Env{Name: &a, Value: &v1}, bosonFunc.Env{Name: &b, Value: &v2}},
util.NewOrderedMap(),
[]string{a, b},
},
map[string]string{"A-": ""},
bosonFunc.Envs{},
},
{
"re-add var",
"update and remove vars",
args{
map[string]string{"A-": ""},
map[string]string{"A": "1"},
bosonFunc.Envs{bosonFunc.Env{Name: &a, Value: &v1}, bosonFunc.Env{Name: &b, Value: &v2}},
util.NewOrderedMapWithKVStrings([][]string{{a, v2}}),
[]string{b},
},
map[string]string{"A": "1"},
bosonFunc.Envs{bosonFunc.Env{Name: &a, Value: &v2}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := mergeEnvMaps(tt.args.dest, tt.args.src); !reflect.DeepEqual(got, tt.want) {
t.Errorf("mergeEnvMaps() = %v, want %v", got, tt.want)
got, err := mergeEnvs(tt.args.envs, tt.args.toUpdate, tt.args.toRemove)
if err != nil {
t.Errorf("mergeEnvs() for initial vars %v and toUpdate %v and toRemove %v got error %v",
tt.args.envs, tt.args.toUpdate, tt.args.toRemove, err)
}
if !reflect.DeepEqual(got, tt.want) {

gotString := "{ "
for _, e := range got {
gotString += fmt.Sprintf("{ %s: %s } ", *e.Name, *e.Value)
}
gotString += "}"

wantString := "{ "
for _, e := range tt.want {
wantString += fmt.Sprintf("{ %s: %s } ", *e.Name, *e.Value)
}
wantString += "}"

t.Errorf("mergeEnvs() = got: %s, want %s", gotString, wantString)
}
})
}
Expand Down
37 changes: 27 additions & 10 deletions cmd/run.go
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/ory/viper"
"github.com/spf13/cobra"
"knative.dev/client/pkg/util"

bosonFunc "github.com/boson-project/func"
"github.com/boson-project/func/docker"
Expand All @@ -13,8 +14,8 @@ import (
func init() {
// Add the run command as a subcommand of root.
root.AddCommand(runCmd)
runCmd.Flags().StringArrayP("env", "e", []string{}, "Environment variable to set in the form NAME=VALUE. " +
"You may provide this flag multiple times for setting multiple environment variables. " +
runCmd.Flags().StringArrayP("env", "e", []string{}, "Environment variable to set in the form NAME=VALUE. "+
"You may provide this flag multiple times for setting multiple environment variables. "+
"To unset, specify the environment variable name followed by a \"-\" (e.g., NAME-).")
runCmd.Flags().StringP("path", "p", cwd(), "Path to the project directory (Env: $FUNC_PATH)")
}
Expand All @@ -40,14 +41,20 @@ kn func run
}

func runRun(cmd *cobra.Command, args []string) (err error) {
config := newRunConfig(cmd)
config, err := newRunConfig(cmd)
if err != nil {
return
}

function, err := bosonFunc.NewFunction(config.Path)
if err != nil {
return
}

function.Env = mergeEnvMaps(function.Env, config.Env)
function.Envs, err = mergeEnvs(function.Envs, config.EnvToUpdate, config.EnvToRemove)
if err != nil {
return
}

err = function.WriteConfig()
if err != nil {
Expand Down Expand Up @@ -78,13 +85,23 @@ type runConfig struct {
// Verbose logging.
Verbose bool

Env map[string]string
// Envs passed via cmd to be added/updated
EnvToUpdate *util.OrderedMap

// Envs passed via cmd to removed
EnvToRemove []string
}

func newRunConfig(cmd *cobra.Command) runConfig {
return runConfig{
Path: viper.GetString("path"),
Verbose: viper.GetBool("verbose"), // defined on root
Env: envFromCmd(cmd),
func newRunConfig(cmd *cobra.Command) (runConfig, error) {
envToUpdate, envToRemove, err := envFromCmd(cmd)
if err != nil {
return runConfig{}, err
}

return runConfig{
Path: viper.GetString("path"),
Verbose: viper.GetBool("verbose"), // defined on root
EnvToUpdate: envToUpdate,
EnvToRemove: envToRemove,
}, nil
}

0 comments on commit 9d7fd34

Please sign in to comment.