Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minor refactoring of code around expressions #1042

Merged
merged 1 commit into from
Mar 20, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 5 additions & 21 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ import (
const (
expectedVarFormat string = "$(vars.var_name) or $(module_id.output_name)"
expectedModFormat string = "$(module_id) or $(group_id.module_id)"
matchLabelExp string = `^[\p{Ll}\p{Lo}\p{N}_-]{1,63}$`
)

var errorMessages = map[string]string{
Expand Down Expand Up @@ -632,20 +631,15 @@ func (dc *DeploymentConfig) SetBackendConfig(cliBEConfigVars []string) error {

// IsLiteralVariable returns true if string matches variable ((ctx.name))
func IsLiteralVariable(str string) bool {
match, err := regexp.MatchString(literalExp, str)
if err != nil {
log.Fatalf("Failed checking if variable is a literal: %v", err)
}
return match
return literalExp.MatchString(str)
}

// IdentifyLiteralVariable returns
// string: variable source (e.g. global "vars" or module "modname")
// string: variable name (e.g. "project_id")
// bool: true/false reflecting success
func IdentifyLiteralVariable(str string) (string, string, bool) {
re := regexp.MustCompile(literalSplitExp)
contents := re.FindStringSubmatch(str)
contents := literalSplitExp.FindStringSubmatch(str)
if len(contents) != 3 {
return "", "", false
}
Expand All @@ -655,8 +649,7 @@ func IdentifyLiteralVariable(str string) (string, string, bool) {

// HandleLiteralVariable is exported for use in modulewriter as well
func HandleLiteralVariable(str string) string {
re := regexp.MustCompile(literalExp)
contents := re.FindStringSubmatch(str)
contents := literalExp.FindStringSubmatch(str)
if len(contents) != 2 {
log.Fatalf("Incorrectly formatted literal variable: %s", str)
}
Expand Down Expand Up @@ -742,22 +735,13 @@ func (err *InputValueError) Error() string {
return fmt.Sprintf("%v input error, cause: %v", err.inputKey, err.cause)
}

// ResolveGlobalVariables will resolve literal variables "((var.*))" in the
// provided map to their corresponding value in the global variables of the
// Blueprint.
func (b Blueprint) ResolveGlobalVariables(ctyVars map[string]cty.Value) error {
origin, err := ConvertMapToCty(b.Vars)
if err != nil {
return fmt.Errorf("error converting deployment variables to cty: %w", err)
}
return ResolveVariables(ctyVars, origin)
}
var matchLabelExp *regexp.Regexp = regexp.MustCompile(`^[\p{Ll}\p{Lo}\p{N}_-]{1,63}$`)

// isValidLabelValue checks if a string is a valid value for a GCP label.
// For more information on valid label values, see the docs at:
// https://cloud.google.com/resource-manager/docs/creating-managing-labels#requirements
func isValidLabelValue(value string) bool {
return regexp.MustCompile(matchLabelExp).MatchString(value)
return matchLabelExp.MatchString(value)
}

// DeploymentName returns the deployment_name from the config and does approperate checks.
Expand Down
51 changes: 0 additions & 51 deletions pkg/config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -926,57 +926,6 @@ func (s *MySuite) TestConvertMapToCty(c *C) {
c.Assert(found, Equals, false)
}

func (s *MySuite) TestResolveGlobalVariables(c *C) {
var err error
var testkey1 = "testkey1"
var testkey2 = "testkey2"
var testkey3 = "testkey3"
dc := getDeploymentConfigForTest()
ctyMap := make(map[string]cty.Value)
err = dc.Config.ResolveGlobalVariables(ctyMap)
c.Assert(err, IsNil)

// confirm plain string is unchanged and does not error
testCtyString := cty.StringVal("testval")
ctyMap[testkey1] = testCtyString
err = dc.Config.ResolveGlobalVariables(ctyMap)
c.Assert(err, IsNil)
c.Assert(ctyMap[testkey1], Equals, testCtyString)

// confirm literal, non-global, variable is unchanged and does not error
testCtyString = cty.StringVal("((module.testval))")
ctyMap[testkey1] = testCtyString
err = dc.Config.ResolveGlobalVariables(ctyMap)
c.Assert(err, IsNil)
c.Assert(ctyMap[testkey1], Equals, testCtyString)

// confirm failed resolution of a literal global
testCtyString = cty.StringVal("((var.test_global_var))")
ctyMap[testkey1] = testCtyString
err = dc.Config.ResolveGlobalVariables(ctyMap)
c.Assert(err, NotNil)
c.Assert(err.Error(), Matches, ".*Unsupported attribute;.*")

// confirm successful resolution of literal globals in presence of other strings
testGlobalVarString := "test_global_string"
testGlobalValString := "testval"
testGlobalVarBool := "test_global_bool"
testGlobalValBool := "testval"
testPlainString := "plain-string"
dc.Config.Vars[testGlobalVarString] = testGlobalValString
dc.Config.Vars[testGlobalVarBool] = testGlobalValBool
testCtyString = cty.StringVal(fmt.Sprintf("((var.%s))", testGlobalVarString))
testCtyBool := cty.StringVal(fmt.Sprintf("((var.%s))", testGlobalVarBool))
ctyMap[testkey1] = testCtyString
ctyMap[testkey2] = testCtyBool
ctyMap[testkey3] = cty.StringVal(testPlainString)
err = dc.Config.ResolveGlobalVariables(ctyMap)
c.Assert(err, IsNil)
c.Assert(ctyMap[testkey1], Equals, cty.StringVal(testGlobalValString))
c.Assert(ctyMap[testkey2], Equals, cty.StringVal(testGlobalValBool))
c.Assert(ctyMap[testkey3], Equals, cty.StringVal(testPlainString))
}

func (s *MySuite) TestCheckMovedModules(c *C) {

dc := DeploymentConfig{
Expand Down
44 changes: 16 additions & 28 deletions pkg/config/expand.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,21 +29,24 @@ import (
)

const (
blueprintLabel string = "ghpc_blueprint"
deploymentLabel string = "ghpc_deployment"
roleLabel string = "ghpc_role"
simpleVariableExp string = `^\$\((.*)\)$`
deploymentVariableExp string = `^\$\(vars\.(.*)\)$`
blueprintLabel string = "ghpc_blueprint"
deploymentLabel string = "ghpc_deployment"
roleLabel string = "ghpc_role"
)

var (
// Checks if a variable exists only as a substring, ex:
// Matches: "a$(vars.example)", "word $(vars.example)", "word$(vars.example)", "$(vars.example)"
// Doesn't match: "\$(vars.example)", "no variable in this string"
anyVariableExp string = `(^|[^\\])\$\((.*?)\)`
literalExp string = `^\(\((.*)\)\)$`
anyVariableExp *regexp.Regexp = regexp.MustCompile(`(^|[^\\])\$\((.*?)\)`)
literalExp *regexp.Regexp = regexp.MustCompile(`^\(\((.*)\)\)$`)
simpleVariableExp *regexp.Regexp = regexp.MustCompile(`^\$\((.*)\)$`)
// the greediness and non-greediness of expression below is important
// consume all whitespace at beginning and end
// consume only up to first period to get variable source
// consume only up to whitespace to get variable name
literalSplitExp string = `^\(\([[:space:]]*(.*?)\.(.*?)[[:space:]]*\)\)$`
literalSplitExp *regexp.Regexp = regexp.MustCompile(`^\(\([[:space:]]*(.*?)\.(.*?)[[:space:]]*\)\)$`)
deploymentVariableExp *regexp.Regexp = regexp.MustCompile(`^\$\(vars\.(.*)\)$`)
)

// expand expands variables and strings in the yaml config. Used directly by
Expand Down Expand Up @@ -720,10 +723,8 @@ func (ref *varReference) validate(depGroups []DeploymentGroup, vars map[string]i

// Needs DeploymentGroups, variable string, current group,
func expandSimpleVariable(context varContext) (string, error) {

// Get variable contents
re := regexp.MustCompile(simpleVariableExp)
contents := re.FindStringSubmatch(context.varString)
contents := simpleVariableExp.FindStringSubmatch(context.varString)
if len(contents) != 2 { // Should always be (match, contents) here
err := fmt.Errorf("%s %s, failed to extract contents: %v",
errorMessages["invalidVar"], context.varString, contents)
Expand Down Expand Up @@ -781,8 +782,7 @@ func expandSimpleVariable(context varContext) (string, error) {
}

func expandVariable(context varContext) (string, error) {
re := regexp.MustCompile(anyVariableExp)
matchall := re.FindAllString(context.varString, -1)
matchall := anyVariableExp.FindAllString(context.varString, -1)
errHint := ""
for _, element := range matchall {
// the regex match will include the first matching character
Expand All @@ -800,29 +800,17 @@ func expandVariable(context varContext) (string, error) {

// isDeploymentVariable checks if the entire string is just a single deployment variable
func isDeploymentVariable(str string) bool {
matched, err := regexp.MatchString(deploymentVariableExp, str)
if err != nil {
log.Fatalf("isDeploymentVariable(%s): %v", str, err)
}
return matched
return deploymentVariableExp.MatchString(str)
}

// isSimpleVariable checks if the entire string is just a single variable
func isSimpleVariable(str string) bool {
matched, err := regexp.MatchString(simpleVariableExp, str)
if err != nil {
log.Fatalf("isSimpleVariable(%s): %v", str, err)
}
return matched
return simpleVariableExp.MatchString(str)
}

// hasVariable checks to see if any variable exists in a string
func hasVariable(str string) bool {
matched, err := regexp.MatchString(anyVariableExp, str)
if err != nil {
log.Fatalf("hasVariable(%s): %v", str, err)
}
return matched
return anyVariableExp.MatchString(str)
}

func handleVariable(prim interface{}, context varContext) (interface{}, error) {
Expand Down