Skip to content

Commit

Permalink
add the --set-value flag to the add command
Browse files Browse the repository at this point in the history
  • Loading branch information
Remi Calizzano committed Aug 3, 2022
1 parent 0902a41 commit 3a02ca5
Show file tree
Hide file tree
Showing 6 changed files with 133 additions and 91 deletions.
18 changes: 0 additions & 18 deletions cmd/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,11 @@ limitations under the License.
package cmd

import (
"fmt"
"strings"
"time"

"github.com/spf13/cobra"
"gitlab.com/openlizz/lizz/internal/flags"
"helm.sh/helm/v3/pkg/strvals"
)

var addCmd = &cobra.Command{
Expand Down Expand Up @@ -101,19 +99,3 @@ func mapTeamSlice(s []string, defaultPermission string) map[string]string {
}
return m
}

func parseValues(values []string) (map[string]interface{}, error) {
base := map[string]interface{}{}
for _, value := range values {
if err := strvals.ParseInto(value, base); err != nil {
return nil, fmt.Errorf("failed parsing --set-value data: %w", err)
}
}
// check that there is no two levels values which is not expected
for _, value := range base {
if _, ok := value.(string); !ok {
return nil, fmt.Errorf("a two level value is passed in --set-value which is not expected. The two level value is %v", value)
}
}
return base, nil
}
17 changes: 11 additions & 6 deletions cmd/add_git.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,12 +105,17 @@ func addGitCmdRun(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
err = applicationRepo.RenderApplicationConfig(clusterRepo.Config(), &repo.CloneOptions{
Username: addGitArgs.username,
Password: addGitArgs.password,
PrivateKeyFile: addGitArgs.privateKeyFile,
Timeout: rootArgs.timeout,
}, status)
err = applicationRepo.RenderApplicationConfig(
addArgs.values,
clusterRepo.Config(),
&repo.CloneOptions{
Username: addGitArgs.username,
Password: addGitArgs.password,
PrivateKeyFile: addGitArgs.privateKeyFile,
Timeout: rootArgs.timeout,
},
status,
)
if err != nil {
return err
}
Expand Down
27 changes: 16 additions & 11 deletions cmd/add_gitlab.go
Original file line number Diff line number Diff line change
Expand Up @@ -163,17 +163,22 @@ func addGitlabCmdRun(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
err = applicationRepo.RenderApplicationConfig(clusterRepo.Config(), &repo.CloneOptions{
Username: addGitlabArgs.owner,
Password: glToken,
Timeout: rootArgs.timeout,
Personal: addGitlabArgs.personal,
Reconcile: addGitlabArgs.reconcile,
Teams: mapTeamSlice(addGitlabArgs.teams, gitlab.DefaultPermission),
CaBundle: caBundle,
SshHostname: addArgs.sshHostname,
Provider: providerClient,
}, status)
err = applicationRepo.RenderApplicationConfig(
addArgs.values,
clusterRepo.Config(),
&repo.CloneOptions{
Username: addGitlabArgs.owner,
Password: glToken,
Timeout: rootArgs.timeout,
Personal: addGitlabArgs.personal,
Reconcile: addGitlabArgs.reconcile,
Teams: mapTeamSlice(addGitlabArgs.teams, gitlab.DefaultPermission),
CaBundle: caBundle,
SshHostname: addArgs.sshHostname,
Provider: providerClient,
},
status,
)
if err != nil {
return err
}
Expand Down
46 changes: 20 additions & 26 deletions internal/repo/application.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package repo

import (
"bytes"
"encoding/base64"
"fmt"
"html/template"
"os"
Expand All @@ -13,7 +12,6 @@ import (

"github.com/Masterminds/sprig/v3"
ignore "github.com/sabhiram/go-gitignore"
"github.com/sethvargo/go-password/password"
"gitlab.com/openlizz/lizz/internal/git/gogit"
"gitlab.com/openlizz/lizz/internal/logger/cli"
"gitlab.com/openlizz/lizz/internal/yaml"
Expand Down Expand Up @@ -58,11 +56,12 @@ func (r *ApplicationRepo) OpenApplicationConfig() error {
return nil
}

func (r *ApplicationRepo) RenderApplicationConfig(clusterConfig *ClusterConfig, cloneOptions *CloneOptions, status *cli.Status) error {
func (r *ApplicationRepo) RenderApplicationConfig(values []string, clusterConfig *ClusterConfig, cloneOptions *CloneOptions, status *cli.Status) error {
status.Start("Render the application configuration ")
defer status.End(false)
c, err := RenderApplicationConfig(
filepath.Join(r.git.Path(), "config.yaml"),
values,
clusterConfig,
cloneOptions,
status,
Expand Down Expand Up @@ -107,7 +106,7 @@ func (r *ApplicationRepo) Render(destinationRepo *Repository, username, pwd stri
for _, v := range r.config.Values.ApplicationDependencies {
for k := range tv {
if v.Name == k {
return fmt.Errorf("application value name already taken. '%s' already has the value: '%s'. Please use another name.", k, tv[k])
return fmt.Errorf("value name already taken. '%s' already has the value: '%s'. Please use another name.", k, tv[k])
}
}
tv[v.Name] = v.Value
Expand All @@ -118,45 +117,40 @@ func (r *ApplicationRepo) Render(destinationRepo *Repository, username, pwd stri
for _, v := range r.config.Values.ApplicationValues {
for k := range tv {
if v.Name == k {
return fmt.Errorf("application value name already taken. '%s' already has the value: '%s'. Please use another name.", k, tv[k])
return fmt.Errorf("value name already taken. '%s' already has the value: '%s'. Please use another name.", k, tv[k])
}
}
tv[v.Name] = v.Value
}
for _, v := range r.config.Values.UserValues {
for k := range tv {
if v.Name == k {
return fmt.Errorf("value name already taken. '%s' already has the value: '%s'. Please use another name.", k, tv[k])
}
}
tv[v.Name] = v.Value
}
for _, v := range r.config.Values.ClusterValues {
for k := range tv {
if v.Name == k {
return fmt.Errorf("application value name already taken. '%s' already has the value: '%s'. Please use another name.", k, tv[k])
return fmt.Errorf("value name already taken. '%s' already has the value: '%s'. Please use another name.", k, tv[k])
}
}
tv[v.Name] = v.Value
if v.Print == true {
status.PrintValue(v.Name, v.Description, tv[v.Name])
}
}
for _, pwd := range r.config.Values.Passwords {
res, err := password.Generate(
pwd.Lenght,
pwd.NumDigits,
pwd.NumSymbols,
pwd.NoUpper,
pwd.AllowRepeat,
)
if err != nil {
return err
}
if pwd.Print == true {
status.PrintValue(pwd.Name, pwd.Description, res)
}
if pwd.Base64 == true {
res = base64.StdEncoding.EncodeToString([]byte(res))
}
for _, v := range r.config.Values.Passwords {
for k := range tv {
if pwd.Name == k {
return fmt.Errorf("application value name already taken. '%s' already has the value: '%s'. Please use another name.", k, tv[k])
if v.Name == k {
return fmt.Errorf("value name already taken. '%s' already has the value: '%s'. Please use another name.", k, tv[k])
}
}
tv[pwd.Name] = res
tv[v.Name] = v.Value
if v.Print == true {
status.PrintValue(v.Name, v.Description, tv[v.Name])
}
}
var fps []string
err := filepath.Walk(r.git.Path(), func(path string, info os.FileInfo, err error) error {
Expand Down
116 changes: 86 additions & 30 deletions internal/repo/config_application.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package repo

import (
"bytes"
"encoding/base64"
"fmt"
"html/template"
"net/url"
Expand All @@ -12,8 +13,10 @@ import (

"github.com/Masterminds/sprig/v3"
"github.com/fluxcd/pkg/apis/meta"
"github.com/sethvargo/go-password/password"
"gitlab.com/openlizz/lizz/internal/logger/cli"
yaml2 "gopkg.in/yaml.v2"
"helm.sh/helm/v3/pkg/strvals"
"sigs.k8s.io/yaml"
)

Expand All @@ -27,19 +30,18 @@ type ApplicationDependency struct {
}

type UserValue struct {
Name string `json:"name"`
Required bool `json:"required,omitempty"`
Encryption bool `json:"encryption,omitempty"`
Value string `json:"value,omitempty"`
Name string `json:"name"`
Required bool `json:"required,omitempty"`
Value interface{} `json:"value,omitempty"`
}

type ClusterValue struct {
Name string `json:"name"`
Required bool `json:"required,omitempty"`
Description string `json:"description,omitempty"`
Print bool `json:"print,omitempty"`
Template string `json:"template,omitempty"`
Value string `json:"value,omitempty"`
Name string `json:"name"`
Required bool `json:"required,omitempty"`
Description string `json:"description,omitempty"`
Print bool `json:"print,omitempty"`
Template string `json:"template,omitempty"`
Value interface{} `json:"value,omitempty"`
}

type ApplicationValue struct {
Expand All @@ -59,19 +61,21 @@ type ApplicationSecret struct {
}

type Password struct {
Name string `json:"name"`
Description string `json:"description,omitempty"`
Print bool `json:"print,omitempty"`
Lenght int `json:"length,omitempty"`
NumDigits int `json:"numDigits,omitempty"`
NumSymbols int `json:"numSymbols,omitempty"`
NoUpper bool `json:"noUpper,omitempty"`
AllowRepeat bool `json:"allowRepeat,omitempty"`
Base64 bool `json:"base64,omitempty"`
Name string `json:"name"`
Description string `json:"description,omitempty"`
Print bool `json:"print,omitempty"`
Lenght int `json:"length,omitempty"`
NumDigits int `json:"numDigits,omitempty"`
NumSymbols int `json:"numSymbols,omitempty"`
NoUpper bool `json:"noUpper,omitempty"`
AllowRepeat bool `json:"allowRepeat,omitempty"`
Base64 bool `json:"base64,omitempty"`
Value interface{} `json:"value,omitempty"`
}

type Values struct {
ApplicationDependencies []ApplicationDependency `json:"applicationDependencies,omitempty"`
UserValues []UserValue `json:"userValues,omitempty"`
ClusterValues []ClusterValue `json:"clusterValues,omitempty"`
ApplicationValues []ApplicationValue `json:"applicationValues,omitempty"`
ApplicationSecrets []ApplicationSecret `json:"applicationSecrets,omitempty"`
Expand Down Expand Up @@ -148,6 +152,7 @@ func GetValueFromMap(obj map[interface{}]interface{}, keys []string) (interface{

func RenderApplicationConfig(
path string,
values []string,
clusterConfig *ClusterConfig,
cloneOptions *CloneOptions,
status *cli.Status,
Expand All @@ -169,6 +174,10 @@ func RenderApplicationConfig(
}
}
tv := make(map[string]interface{})
setValues, err := parseValues(values)
if err != nil {
return &ApplicationConfig{}, err
}
// render application dependencies
for idx, ad := range v.ApplicationDependencies {
tv[ad.Name] = false
Expand All @@ -184,19 +193,22 @@ func RenderApplicationConfig(
}
}
// render user values
// for idx, userValue := range v.UserValues {
// value := xxx[userValue.Name]
// if userValue.Required == true && value == "" {
// return &ApplicationConfig{}, fmt.Errorf(
// "user value with name '%s' and template '%s' cannot be resolved and is required for the application",
// userValue.Name,
// userValue.Template,
// )
// }
// v.userValues[idx].Value = tpl.String()
// tv[userValue.Name] = tpl.String()
for idx, userValue := range v.UserValues {
value := setValues[userValue.Name]
if userValue.Required == true && value == "" {
return &ApplicationConfig{}, fmt.Errorf("user value with name '%s' is not set using `--set-value` and is required for the application", userValue.Name)
}
v.UserValues[idx].Value = value
tv[userValue.Name] = value
}
// render cluster values
for idx, clusterValue := range v.ClusterValues {
// if value is overwrite by the --set-value flag
if value, ok := setValues[clusterValue.Name]; ok {
v.ClusterValues[idx].Value = value
tv[clusterValue.Name] = value
continue
}
t := template.Must(template.New("clusterValue").Funcs(sprig.FuncMap()).Parse(clusterValue.Template))
var tpl bytes.Buffer
err := t.Execute(&tpl, clusterConfig)
Expand All @@ -219,6 +231,12 @@ func RenderApplicationConfig(
}
// render application values
for idx, applicationValue := range v.ApplicationValues {
// if value is overwrite by the --set-value flag
if value, ok := setValues[applicationValue.Name]; ok {
v.ApplicationValues[idx].Value = value
tv[applicationValue.Name] = value
continue
}
var repository Repository
for _, application := range clusterConfig.Applications {
if application.Configuration.Repository == applicationValue.Repository {
Expand Down Expand Up @@ -248,6 +266,34 @@ func RenderApplicationConfig(
v.ApplicationValues[idx].Value = value
tv[applicationValue.Name] = value
}
// render passwords
for idx, pwd := range v.Passwords {
// if value is overwrite by the --set-value flag
if value, ok := setValues[pwd.Name]; ok {
v.Passwords[idx].Value = value
tv[pwd.Name] = value
continue
}
value, err := password.Generate(
pwd.Lenght,
pwd.NumDigits,
pwd.NumSymbols,
pwd.NoUpper,
pwd.AllowRepeat,
)
if err != nil {
return &ApplicationConfig{}, fmt.Errorf(
"error in the password with name %s: %w",
pwd.Name,
err,
)
}
if pwd.Base64 == true {
value = base64.StdEncoding.EncodeToString([]byte(value))
}
v.Passwords[idx].Value = value
tv[pwd.Name] = value
}
// render the application configuration (without the values) with the template values
t := template.Must(template.New("applicationConfig").Funcs(sprig.FuncMap()).Parse(strings.ReplaceAll(string(y), vy, "")))
var tpl bytes.Buffer
Expand Down Expand Up @@ -336,6 +382,16 @@ func (c *ApplicationConfig) Save(path string) error {
return nil
}

func parseValues(values []string) (map[string]interface{}, error) {
base := map[string]interface{}{}
for _, value := range values {
if err := strvals.ParseInto(value, base); err != nil {
return nil, fmt.Errorf("failed parsing --set-value data: %w", err)
}
}
return base, nil
}

func extractValuesFromYaml(config string) string {
startIndex := strings.Index(config, "values:")
if startIndex == -1 {
Expand Down
Binary file modified lizz
Binary file not shown.

0 comments on commit 3a02ca5

Please sign in to comment.