|
|
@@ -9,6 +9,7 @@ import (
|
|
|
api "github.com/porter-dev/porter/api/client"
|
|
|
apiTypes "github.com/porter-dev/porter/api/types"
|
|
|
"github.com/porter-dev/porter/cli/cmd/config"
|
|
|
+ "gopkg.in/yaml.v3"
|
|
|
)
|
|
|
|
|
|
const (
|
|
|
@@ -21,7 +22,7 @@ type PreviewApplier struct {
|
|
|
apiClient *api.Client
|
|
|
rawBytes []byte
|
|
|
namespace string
|
|
|
- // parsed *types.ParsedPorterYAML
|
|
|
+ parsed *PorterYAML
|
|
|
|
|
|
variablesMap map[string]string
|
|
|
osEnv map[string]string
|
|
|
@@ -29,11 +30,14 @@ type PreviewApplier struct {
|
|
|
}
|
|
|
|
|
|
func NewApplier(client *api.Client, raw []byte, namespace string) (*PreviewApplier, error) {
|
|
|
- // parsed, err := parser.ParseRawBytes(raw)
|
|
|
+ parsed := &PorterYAML{}
|
|
|
|
|
|
- // if err != nil {
|
|
|
- // return nil, err
|
|
|
- // }
|
|
|
+ err := yaml.Unmarshal(raw, parsed)
|
|
|
+
|
|
|
+ if err != nil {
|
|
|
+ errMsg := composePreviewMessage("error parsing porter.yaml", Error)
|
|
|
+ return nil, fmt.Errorf("%s: %w", errMsg, err)
|
|
|
+ }
|
|
|
|
|
|
// err = validator.ValidatePorterYAML(parsed)
|
|
|
|
|
|
@@ -41,10 +45,10 @@ func NewApplier(client *api.Client, raw []byte, namespace string) (*PreviewAppli
|
|
|
// return nil, err
|
|
|
// }
|
|
|
|
|
|
- err := validateCLIEnvironment(namespace)
|
|
|
+ err = validateCLIEnvironment(namespace)
|
|
|
|
|
|
if err != nil {
|
|
|
- errMsg := ComposePreviewMessage(fmt.Sprintf("porter CLI is not configured correctly"), Error)
|
|
|
+ errMsg := composePreviewMessage("porter CLI is not configured correctly", Error)
|
|
|
return nil, fmt.Errorf("%s: %w", errMsg, err)
|
|
|
}
|
|
|
|
|
|
@@ -52,7 +56,7 @@ func NewApplier(client *api.Client, raw []byte, namespace string) (*PreviewAppli
|
|
|
apiClient: client,
|
|
|
rawBytes: raw,
|
|
|
namespace: namespace,
|
|
|
- // parsed: parsed,
|
|
|
+ parsed: parsed,
|
|
|
}, nil
|
|
|
}
|
|
|
|
|
|
@@ -88,7 +92,7 @@ func (a *PreviewApplier) Apply() error {
|
|
|
)
|
|
|
|
|
|
if err != nil {
|
|
|
- errMsg := ComposePreviewMessage(fmt.Sprintf("error listing namespaces for project '%d', cluster '%d'",
|
|
|
+ errMsg := composePreviewMessage(fmt.Sprintf("error listing namespaces for project '%d', cluster '%d'",
|
|
|
config.GetCLIConfig().Project, config.GetCLIConfig().Cluster), Error)
|
|
|
return fmt.Errorf("%s: %w", errMsg, err)
|
|
|
}
|
|
|
@@ -104,12 +108,12 @@ func (a *PreviewApplier) Apply() error {
|
|
|
}
|
|
|
|
|
|
if !nsFound {
|
|
|
- errMsg := ComposePreviewMessage(fmt.Sprintf("namespace '%s' does not exist in project '%d', cluster '%d'",
|
|
|
+ errMsg := composePreviewMessage(fmt.Sprintf("namespace '%s' does not exist in project '%d', cluster '%d'",
|
|
|
a.namespace, config.GetCLIConfig().Project, config.GetCLIConfig().Cluster), Error)
|
|
|
return fmt.Errorf("%s: %w", errMsg, err)
|
|
|
}
|
|
|
|
|
|
- PrintInfoMessage(fmt.Sprintf("Applying porter.yaml with the following attributes:\n"+
|
|
|
+ printInfoMessage(fmt.Sprintf("Applying porter.yaml with the following attributes:\n"+
|
|
|
"\tHost: %s\n\tProject ID: %d\n\tCluster ID: %d\n\tNamespace: %s",
|
|
|
config.GetCLIConfig().Host,
|
|
|
config.GetCLIConfig().Project,
|
|
|
@@ -120,7 +124,7 @@ func (a *PreviewApplier) Apply() error {
|
|
|
err = a.readOSEnv()
|
|
|
|
|
|
if err != nil {
|
|
|
- errMsg := ComposePreviewMessage("error reading OS environment variables", Error)
|
|
|
+ errMsg := composePreviewMessage("error reading OS environment variables", Error)
|
|
|
return fmt.Errorf("%s: %w", errMsg, err)
|
|
|
}
|
|
|
|
|
|
@@ -128,7 +132,7 @@ func (a *PreviewApplier) Apply() error {
|
|
|
}
|
|
|
|
|
|
func (a *PreviewApplier) readOSEnv() error {
|
|
|
- PrintInfoMessage("Reading OS environment variables")
|
|
|
+ printInfoMessage("Reading OS environment variables")
|
|
|
|
|
|
env := os.Environ()
|
|
|
osEnv := make(map[string]string)
|
|
|
@@ -144,7 +148,7 @@ func (a *PreviewApplier) readOSEnv() error {
|
|
|
}
|
|
|
|
|
|
if k == "" {
|
|
|
- PrintWarningMessage(fmt.Sprintf("Ignoring invalid OS environment variable '%s'", kCopy))
|
|
|
+ printWarningMessage(fmt.Sprintf("Ignoring invalid OS environment variable '%s'", kCopy))
|
|
|
}
|
|
|
|
|
|
osEnv[k] = v
|
|
|
@@ -156,102 +160,173 @@ func (a *PreviewApplier) readOSEnv() error {
|
|
|
return nil
|
|
|
}
|
|
|
|
|
|
-// func (a *PreviewApplier) processVariables() error {
|
|
|
-// PrintInfoMessage("Processing variables")
|
|
|
-
|
|
|
-// constantsMap := make(map[string]string)
|
|
|
-// variablesMap := make(map[string]string)
|
|
|
-
|
|
|
-// for _, v := range a.parsed.PorterYAML.Variables.GetValue() {
|
|
|
-// if v.Once.GetValue() {
|
|
|
-// // a constant which should be stored in the env group on first run
|
|
|
-// if exists, err := a.constantExistsInEnvGroup(v.Name.GetValue()); err == nil {
|
|
|
-// if exists == nil {
|
|
|
-// // this should not happen
|
|
|
-// return fmt.Errorf("internal error: please let the Porter team know about this and quote the following " +
|
|
|
-// "error:\n-----\nERROR: checking for constant existence in env group returned nil with no error")
|
|
|
-// }
|
|
|
-
|
|
|
-// val := *exists
|
|
|
-
|
|
|
-// if !val {
|
|
|
-// // create the constant in the env group
|
|
|
-// if v.Value.GetValue() != "" {
|
|
|
-// constantsMap[v.Name.GetValue()] = v.Value.GetValue()
|
|
|
-// } else if v.Random.GetValue() {
|
|
|
-// constantsMap[v.Name.GetValue()] = randomString(v.Length.GetValue(), defaultCharset)
|
|
|
-// } else {
|
|
|
-// // this should not happen
|
|
|
-// return fmt.Errorf("internal error: please let the Porter team know about this and quote the following "+
|
|
|
-// "error:\n-----\nERROR: for variable '%s', random is false and value is empty", v.Name.GetValue())
|
|
|
-// }
|
|
|
-// }
|
|
|
-// } else {
|
|
|
-// return fmt.Errorf("error checking for existence of constant %s: %w", v.Name.GetValue(), err)
|
|
|
-// }
|
|
|
-// } else {
|
|
|
-// if v.Value.GetValue() != "" {
|
|
|
-// variablesMap[v.Name.GetValue()] = v.Value.GetValue()
|
|
|
-// } else if v.Random.GetValue() {
|
|
|
-// variablesMap[v.Name.GetValue()] = randomString(v.Length.GetValue(), defaultCharset)
|
|
|
-// } else {
|
|
|
-// // this should not happen
|
|
|
-// return fmt.Errorf("internal error: please let the Porter team know about this and quote the following "+
|
|
|
-// "error:\n-----\nERROR: for variable '%s', random is false and value is empty", v.Name.GetValue())
|
|
|
-// }
|
|
|
-// }
|
|
|
-// }
|
|
|
-
|
|
|
-// if len(constantsMap) > 0 {
|
|
|
-// // we need to create these constants in the env group
|
|
|
-// _, err := a.apiClient.CreateEnvGroup(
|
|
|
-// context.Background(),
|
|
|
-// config.GetCLIConfig().Project,
|
|
|
-// config.GetCLIConfig().Cluster,
|
|
|
-// a.namespace,
|
|
|
-// &apiTypes.CreateEnvGroupRequest{
|
|
|
-// Name: constantsEnvGroup,
|
|
|
-// Variables: constantsMap,
|
|
|
-// },
|
|
|
-// )
|
|
|
-
|
|
|
-// if err != nil {
|
|
|
-// return fmt.Errorf("error creating constants (variables with once set to true) in env group: %w", err)
|
|
|
-// }
|
|
|
-
|
|
|
-// for k, v := range constantsMap {
|
|
|
-// variablesMap[k] = v
|
|
|
-// }
|
|
|
-// }
|
|
|
-
|
|
|
-// a.variablesMap = variablesMap
|
|
|
-
|
|
|
-// return nil
|
|
|
-// }
|
|
|
-
|
|
|
-// func (a *PreviewApplier) constantExistsInEnvGroup(name string) (*bool, error) {
|
|
|
-// apiResponse, err := a.apiClient.GetEnvGroup(
|
|
|
-// context.Background(),
|
|
|
-// config.GetCLIConfig().Project,
|
|
|
-// config.GetCLIConfig().Cluster,
|
|
|
-// a.namespace,
|
|
|
-// &apiTypes.GetEnvGroupRequest{
|
|
|
-// Name: constantsEnvGroup,
|
|
|
-// // we do not care about the version because it always needs to be the latest
|
|
|
-// },
|
|
|
-// )
|
|
|
-
|
|
|
-// if err != nil {
|
|
|
-// if strings.Contains(err.Error(), "env group not found") {
|
|
|
-// return boolean(false), nil
|
|
|
-// }
|
|
|
-
|
|
|
-// return nil, err
|
|
|
-// }
|
|
|
-
|
|
|
-// if _, ok := apiResponse.Variables[name]; ok {
|
|
|
-// return boolean(true), nil
|
|
|
-// }
|
|
|
-
|
|
|
-// return boolean(false), nil
|
|
|
-// }
|
|
|
+func (a *PreviewApplier) processVariables() error {
|
|
|
+ printInfoMessage("Processing variables")
|
|
|
+
|
|
|
+ constantsMap := make(map[string]string)
|
|
|
+ variablesMap := make(map[string]string)
|
|
|
+
|
|
|
+ for _, v := range a.parsed.Variables {
|
|
|
+ if v == nil {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ if v.Once != nil && *v.Once {
|
|
|
+ // a constant which should be stored in the env group on first run
|
|
|
+ if exists, err := a.constantExistsInEnvGroup(*v.Name); err == nil {
|
|
|
+ if exists == nil {
|
|
|
+ // this should not happen
|
|
|
+ return fmt.Errorf("internal error: please let the Porter team know about this and quote the following " +
|
|
|
+ "error:\n-----\nERROR: checking for constant existence in env group returned nil with no error")
|
|
|
+ }
|
|
|
+
|
|
|
+ val := *exists
|
|
|
+
|
|
|
+ if !val {
|
|
|
+ // create the constant in the env group
|
|
|
+ if *v.Value != "" {
|
|
|
+ constantsMap[*v.Name] = *v.Value
|
|
|
+ } else if v.Random != nil && *v.Random {
|
|
|
+ constantsMap[*v.Name] = randomString(*v.Length, defaultCharset)
|
|
|
+ } else {
|
|
|
+ // this should not happen
|
|
|
+ return fmt.Errorf("internal error: please let the Porter team know about this and quote the following "+
|
|
|
+ "error:\n-----\nERROR: for variable '%s', random is false and value is empty", *v.Name)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ return fmt.Errorf("error checking for existence of constant %s: %w", *v.Name, err)
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ if v.Value != nil && *v.Value != "" {
|
|
|
+ variablesMap[*v.Name] = *v.Value
|
|
|
+ } else if v.Random != nil && *v.Random {
|
|
|
+ variablesMap[*v.Name] = randomString(*v.Length, defaultCharset)
|
|
|
+ } else {
|
|
|
+ // this should not happen
|
|
|
+ return fmt.Errorf("internal error: please let the Porter team know about this and quote the following "+
|
|
|
+ "error:\n-----\nERROR: for variable '%s', random is false and value is empty", *v.Name)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if len(constantsMap) > 0 {
|
|
|
+ // we need to create these constants in the env group
|
|
|
+ _, err := a.apiClient.CreateEnvGroup(
|
|
|
+ context.Background(),
|
|
|
+ config.GetCLIConfig().Project,
|
|
|
+ config.GetCLIConfig().Cluster,
|
|
|
+ a.namespace,
|
|
|
+ &apiTypes.CreateEnvGroupRequest{
|
|
|
+ Name: constantsEnvGroup,
|
|
|
+ Variables: constantsMap,
|
|
|
+ },
|
|
|
+ )
|
|
|
+
|
|
|
+ if err != nil {
|
|
|
+ return fmt.Errorf("error creating constants (variables with once set to true) in env group: %w", err)
|
|
|
+ }
|
|
|
+
|
|
|
+ for k, v := range constantsMap {
|
|
|
+ variablesMap[k] = v
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ a.variablesMap = variablesMap
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
+func (a *PreviewApplier) constantExistsInEnvGroup(name string) (*bool, error) {
|
|
|
+ apiResponse, err := a.apiClient.GetEnvGroup(
|
|
|
+ context.Background(),
|
|
|
+ config.GetCLIConfig().Project,
|
|
|
+ config.GetCLIConfig().Cluster,
|
|
|
+ a.namespace,
|
|
|
+ &apiTypes.GetEnvGroupRequest{
|
|
|
+ Name: constantsEnvGroup,
|
|
|
+ // we do not care about the version because it always needs to be the latest
|
|
|
+ },
|
|
|
+ )
|
|
|
+
|
|
|
+ if err != nil {
|
|
|
+ if strings.Contains(err.Error(), "env group not found") {
|
|
|
+ return booleanptr(false), nil
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+
|
|
|
+ if _, ok := apiResponse.Variables[name]; ok {
|
|
|
+ return booleanptr(true), nil
|
|
|
+ }
|
|
|
+
|
|
|
+ return booleanptr(false), nil
|
|
|
+}
|
|
|
+
|
|
|
+func (a *PreviewApplier) processEnvGroups() error {
|
|
|
+ printInfoMessage("Processing env groups")
|
|
|
+
|
|
|
+ for _, eg := range a.parsed.EnvGroups {
|
|
|
+ if eg == nil {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ if eg.Name == nil || *eg.Name == "" {
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ envGroup, err := a.apiClient.GetEnvGroup(
|
|
|
+ context.Background(),
|
|
|
+ config.GetCLIConfig().Project,
|
|
|
+ config.GetCLIConfig().Cluster,
|
|
|
+ a.namespace,
|
|
|
+ &apiTypes.GetEnvGroupRequest{
|
|
|
+ Name: *eg.Name,
|
|
|
+ },
|
|
|
+ )
|
|
|
+
|
|
|
+ if err != nil && strings.Contains(err.Error(), "env group not found") {
|
|
|
+ if eg.CloneFrom == nil {
|
|
|
+ return fmt.Errorf(composePreviewMessage(fmt.Sprintf("empty clone_from for env group '%s'", *eg.Name), Error))
|
|
|
+ }
|
|
|
+
|
|
|
+ egNS, egName, found := strings.Cut(*eg.CloneFrom, "/")
|
|
|
+
|
|
|
+ if !found {
|
|
|
+ return fmt.Errorf("error parsing clone_from for env group '%s': invalid format", *eg.Name)
|
|
|
+ }
|
|
|
+
|
|
|
+ // clone the env group
|
|
|
+ envGroup, err := a.apiClient.CloneEnvGroup(
|
|
|
+ context.Background(),
|
|
|
+ config.GetCLIConfig().Project,
|
|
|
+ config.GetCLIConfig().Cluster,
|
|
|
+ egNS,
|
|
|
+ &apiTypes.CloneEnvGroupRequest{
|
|
|
+ SourceName: egName,
|
|
|
+ TargetNamespace: a.namespace,
|
|
|
+ TargetName: *eg.Name,
|
|
|
+ },
|
|
|
+ )
|
|
|
+
|
|
|
+ if err != nil {
|
|
|
+ return fmt.Errorf("error cloning env group '%s' from '%s': %w", egName, egNS, err)
|
|
|
+ }
|
|
|
+
|
|
|
+ a.envGroups[*eg.Name] = &apiTypes.EnvGroup{
|
|
|
+ Name: envGroup.Name,
|
|
|
+ Variables: envGroup.Variables,
|
|
|
+ }
|
|
|
+ } else if err != nil {
|
|
|
+ return fmt.Errorf("error checking for env group '%s': %w", *eg.Name, err)
|
|
|
+ } else {
|
|
|
+ a.envGroups[*eg.Name] = &apiTypes.EnvGroup{
|
|
|
+ Name: envGroup.Name,
|
|
|
+ Variables: envGroup.Variables,
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return nil
|
|
|
+}
|