Skip to content

Commit

Permalink
Support dashes - in the tenant, environment and stage names (cloudp…
Browse files Browse the repository at this point in the history
…osse#143)

* Updates

* Updates

* Updates

* Updates
  • Loading branch information
aknysh authored Apr 22, 2022
1 parent a562a02 commit ae7272f
Show file tree
Hide file tree
Showing 7 changed files with 101 additions and 113 deletions.
27 changes: 27 additions & 0 deletions examples/complete/stacks/tenant1/ue2/test1.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import:
- globals/tenant1-globals
- globals/ue2-globals
- catalog/terraform/top-level-component1
- catalog/terraform/test-component
- catalog/terraform/test-component-override
- catalog/terraform/test-component-override-2
- catalog/terraform/test-component-override-3
- catalog/terraform/vpc
- catalog/helmfile/echo-server
- catalog/helmfile/infra-server
- catalog/helmfile/infra-server-override

vars:
stage: test-1

terraform:
vars: {}

helmfile:
vars: {}

components:
terraform:
"infra/vpc":
vars:
cidr_block: 10.11.0.0/18
97 changes: 27 additions & 70 deletions internal/exec/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -259,13 +259,6 @@ func ProcessStacks(configAndStacksInfo c.ConfigAndStacksInfo, checkStack bool) (
}
}

if len(c.Config.Stacks.NamePattern) < 1 {
return configAndStacksInfo,
errors.New("stack name pattern must be provided in 'stacks.name_pattern' config or 'ATMOS_STACKS_NAME_PATTERN' ENV variable")
}

stackNamePatternParts := strings.Split(c.Config.Stacks.NamePattern, "-")

// Check and process stacks
if c.ProcessedConfig.StackType == "Directory" {
configAndStacksInfo.ComponentSection,
Expand All @@ -284,35 +277,21 @@ func ProcessStacks(configAndStacksInfo c.ConfigAndStacksInfo, checkStack bool) (
}

configAndStacksInfo.ComponentEnvList = convertEnvVars(configAndStacksInfo.ComponentEnvSection)

// Process context
configAndStacksInfo.Context = c.GetContextFromVars(configAndStacksInfo.ComponentVarsSection)
configAndStacksInfo.Context.Component = configAndStacksInfo.ComponentFromArg
configAndStacksInfo.Context.BaseComponent = configAndStacksInfo.BaseComponentPath
configAndStacksInfo.ContextPrefix, err = c.GetContextPrefix(configAndStacksInfo.Stack, configAndStacksInfo.Context, c.Config.Stacks.NamePattern)
if err != nil {
return configAndStacksInfo, err
}
} else {
if g.LogVerbose {
color.Cyan("Searching for stack config where the component '%s' is defined\n", configAndStacksInfo.ComponentFromArg)
}

stackParts := strings.Split(configAndStacksInfo.Stack, "-")
if len(stackParts) != len(stackNamePatternParts) {
return configAndStacksInfo,
errors.New(fmt.Sprintf("Stack '%s' does not match the stack name pattern '%s'",
configAndStacksInfo.Stack,
c.Config.Stacks.NamePattern))
}

var tenant string
var environment string
var stage string
var tenantFound bool
var environmentFound bool
var stageFound bool

for i, part := range stackNamePatternParts {
if part == "{tenant}" {
tenant = stackParts[i]
} else if part == "{environment}" {
environment = stackParts[i]
} else if part == "{stage}" {
stage = stackParts[i]
}
}
stackFound := false

for stackName := range stacksMap {
configAndStacksInfo.ComponentSection,
Expand All @@ -332,43 +311,30 @@ func ProcessStacks(configAndStacksInfo c.ConfigAndStacksInfo, checkStack bool) (

configAndStacksInfo.ComponentEnvList = convertEnvVars(configAndStacksInfo.ComponentEnvSection)

tenantFound = true
environmentFound = true
stageFound = true

// Search for tenant in stack
if len(tenant) > 0 {
if tenantInStack, ok := configAndStacksInfo.ComponentVarsSection["tenant"].(string); !ok || tenantInStack != tenant {
tenantFound = false
}
}

// Search for environment in stack
if len(environment) > 0 {
if environmentInStack, ok := configAndStacksInfo.ComponentVarsSection["environment"].(string); !ok || environmentInStack != environment {
environmentFound = false
}
}

// Search for stage in stack
if len(stage) > 0 {
if stageInStack, ok := configAndStacksInfo.ComponentVarsSection["stage"].(string); !ok || stageInStack != stage {
stageFound = false
}
// Process context
configAndStacksInfo.Context = c.GetContextFromVars(configAndStacksInfo.ComponentVarsSection)
configAndStacksInfo.Context.Component = configAndStacksInfo.ComponentFromArg
configAndStacksInfo.Context.BaseComponent = configAndStacksInfo.BaseComponentPath
configAndStacksInfo.ContextPrefix, err = c.GetContextPrefix(configAndStacksInfo.Stack, configAndStacksInfo.Context, c.Config.Stacks.NamePattern)
if err != nil {
return configAndStacksInfo, err
}

if tenantFound == true && environmentFound == true && stageFound == true {
if g.LogVerbose {
color.Green("Found stack config for the component '%s' in the stack '%s'\n\n", configAndStacksInfo.ComponentFromArg, stackName)
}
configAndStacksInfo.Stack = stackName
// Check if we've found the stack
if configAndStacksInfo.Stack == configAndStacksInfo.ContextPrefix {
stackFound = true
color.Cyan("Found config for the component '%s' for the stack '%s' in the file '%s'\n",
configAndStacksInfo.ComponentFromArg,
configAndStacksInfo.Stack,
stackName,
)
break
}
}

if tenantFound == false || environmentFound == false || stageFound == false {
if !stackFound {
return configAndStacksInfo,
errors.New(fmt.Sprintf("\nCould not find config for the component '%s' in the stack '%s'.\n"+
errors.New(fmt.Sprintf("\nSearched all stack files, but could not find config for the component '%s' in the stack '%s'.\n"+
"Check that all attributes in the stack name pattern '%s' are defined in the stack config files.\n"+
"Are the component and stack names correct? Did you forget an import?",
configAndStacksInfo.ComponentFromArg,
Expand Down Expand Up @@ -415,15 +381,6 @@ func ProcessStacks(configAndStacksInfo c.ConfigAndStacksInfo, checkStack bool) (
configAndStacksInfo.FinalComponent = configAndStacksInfo.Component
}

// Process context
configAndStacksInfo.Context = c.GetContextFromVars(configAndStacksInfo.ComponentVarsSection)
configAndStacksInfo.Context.Component = configAndStacksInfo.ComponentFromArg
configAndStacksInfo.Context.BaseComponent = configAndStacksInfo.BaseComponentPath
configAndStacksInfo.ContextPrefix, err = c.GetContextPrefix(configAndStacksInfo.Stack, configAndStacksInfo.Context, c.Config.Stacks.NamePattern)
if err != nil {
return configAndStacksInfo, err
}

// workspace
workspace, err := BuildTerraformWorkspace(
configAndStacksInfo.Stack,
Expand Down
17 changes: 16 additions & 1 deletion pkg/component/component_processor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -114,12 +114,27 @@ func TestComponentProcessor(t *testing.T) {
stage = "dev"
tenant1Ue2DevTestTestComponentOverrideComponent2, err = ProcessComponentFromContext(component, tenant, environment, stage)
assert.Nil(t, err)
tenant1Ue2DevTestTestComponentOverrideComponent2Backend := tenant1Ue2DevTestTestComponentOverrideComponent2["backend"].(map[interface{}]interface{})
tenant1Ue2DevTestTestComponentOverrideComponent2Workspace := tenant1Ue2DevTestTestComponentOverrideComponent2["workspace"].(string)
tenant1Ue2DevTestTestComponentOverrideComponent2WorkspaceKeyPrefix := tenant1Ue2DevTestTestComponentOverrideComponentBackend["workspace_key_prefix"].(string)
tenant1Ue2DevTestTestComponentOverrideComponent2WorkspaceKeyPrefix := tenant1Ue2DevTestTestComponentOverrideComponent2Backend["workspace_key_prefix"].(string)
assert.Equal(t, "tenant1-ue2-dev-test-test-component-override-2", tenant1Ue2DevTestTestComponentOverrideComponent2Workspace)
assert.Equal(t, "test-test-component", tenant1Ue2DevTestTestComponentOverrideComponent2WorkspaceKeyPrefix)

yamlConfig, err = yaml.Marshal(tenant1Ue2DevTestTestComponentOverrideComponent2)
assert.Nil(t, err)
t.Log(string(yamlConfig))

// Test having a dash `-` in the stage name
var tenant1Ue2Test1TestTestComponentOverrideComponent2 map[string]interface{}
component = "test/test-component-override-2"
tenant = "tenant1"
environment = "ue2"
stage = "test-1"
tenant1Ue2Test1TestTestComponentOverrideComponent2, err = ProcessComponentFromContext(component, tenant, environment, stage)
assert.Nil(t, err)
tenant1Ue2Test1TestTestComponentOverrideComponent2Backend := tenant1Ue2DevTestTestComponentOverrideComponent2["backend"].(map[interface{}]interface{})
tenant1Ue2Test1TestTestComponentOverrideComponent2Workspace := tenant1Ue2Test1TestTestComponentOverrideComponent2["workspace"].(string)
tenant1Ue2Test1TestTestComponentOverrideComponent2WorkspaceKeyPrefix := tenant1Ue2Test1TestTestComponentOverrideComponent2Backend["workspace_key_prefix"].(string)
assert.Equal(t, "tenant1-ue2-test-1-test-test-component-override-2", tenant1Ue2Test1TestTestComponentOverrideComponent2Workspace)
assert.Equal(t, "test-test-component", tenant1Ue2Test1TestTestComponentOverrideComponent2WorkspaceKeyPrefix)
}
47 changes: 10 additions & 37 deletions pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import (
"path"
"path/filepath"
"runtime"
"strings"
)

var (
Expand Down Expand Up @@ -240,43 +239,17 @@ func ProcessConfig(configAndStacksInfo ConfigAndStacksInfo, checkStack bool) err
ProcessedConfig.StackConfigFilesAbsolutePaths = stackConfigFilesAbsolutePaths
ProcessedConfig.StackConfigFilesRelativePaths = stackConfigFilesRelativePaths

if checkStack {
if stackIsPhysicalPath == true {
if g.LogVerbose {
color.Cyan(fmt.Sprintf("\nThe stack '%s' matches the stack config file %s\n",
configAndStacksInfo.Stack,
stackConfigFilesRelativePaths[0]),
)
}
ProcessedConfig.StackType = "Directory"
} else {
// The stack is a logical name
// Check if it matches the pattern specified in 'StackNamePattern'
if len(Config.Stacks.NamePattern) == 0 {
errorMessage := "\nStack name pattern must be provided and must not be empty. Check the CLI config in 'atmos.yaml'"
return errors.New(errorMessage)
}

stackParts := strings.Split(configAndStacksInfo.Stack, "-")
stackNamePatternParts := strings.Split(Config.Stacks.NamePattern, "-")

if len(stackParts) == len(stackNamePatternParts) {
if g.LogVerbose {
color.Cyan(fmt.Sprintf("\nThe stack '%s' matches the stack name pattern '%s'",
configAndStacksInfo.Stack,
Config.Stacks.NamePattern),
)
}
ProcessedConfig.StackType = "Logical"
} else {
errorMessage := fmt.Sprintf("\nThe stack '%s' does not exist in the config directories, "+
"and it does not match the stack name pattern '%s'",
configAndStacksInfo.Stack,
Config.Stacks.NamePattern,
)
return errors.New(errorMessage)
}
if stackIsPhysicalPath == true {
if g.LogVerbose {
color.Cyan(fmt.Sprintf("\nThe stack '%s' matches the stack config file %s\n",
configAndStacksInfo.Stack,
stackConfigFilesRelativePaths[0]),
)
}
ProcessedConfig.StackType = "Directory"
} else {
// The stack is a logical name
ProcessedConfig.StackType = "Logical"
}

if g.LogVerbose {
Expand Down
2 changes: 1 addition & 1 deletion pkg/config/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ func GetContextFromVars(vars map[interface{}]interface{}) Context {
func GetContextPrefix(stack string, context Context, stackNamePattern string) (string, error) {
if len(stackNamePattern) == 0 {
return "",
errors.New(fmt.Sprintf("Stack name pattern must be provided"))
errors.New("stack name pattern must be provided in 'stacks.name_pattern' config or 'ATMOS_STACKS_NAME_PATTERN' ENV variable")
}

contextPrefix := ""
Expand Down
18 changes: 16 additions & 2 deletions pkg/spacelift/spacelift_stack_processor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ func TestSpaceliftStackProcessor(t *testing.T) {

var spaceliftStacks, err = CreateSpaceliftStacks("", nil, processStackDeps, processComponentDeps, processImports, stackConfigPathTemplate)
assert.Nil(t, err)
assert.Equal(t, 30, len(spaceliftStacks))
assert.Equal(t, 35, len(spaceliftStacks))

tenant1Ue2DevInfraVpcStack := spaceliftStacks["tenant1-ue2-dev-infra-vpc"].(map[string]interface{})
tenant1Ue2DevInfraVpcStackInfrastructureStackName := tenant1Ue2DevInfraVpcStack["stack"].(string)
Expand All @@ -24,6 +24,14 @@ func TestSpaceliftStackProcessor(t *testing.T) {
assert.Equal(t, "tenant1-ue2-dev", tenant1Ue2DevInfraVpcStackInfrastructureStackName)
assert.Equal(t, "infra-vpc", tenant1Ue2DevInfraVpcStackBackendWorkspaceKeyPrefix)

// Test having a dash `-` in tenant/environment/stage names
tenant1Ue2Test1InfraVpcStack := spaceliftStacks["tenant1-ue2-test-1-infra-vpc"].(map[string]interface{})
tenant1Ue2Test1InfraVpcStackInfrastructureStackName := tenant1Ue2Test1InfraVpcStack["stack"].(string)
tenant1Ue2Test1InfraVpcStackBackend := tenant1Ue2Test1InfraVpcStack["backend"].(map[interface{}]interface{})
tenant1Ue2Test1InfraVpcStackBackendWorkspaceKeyPrefix := tenant1Ue2Test1InfraVpcStackBackend["workspace_key_prefix"].(string)
assert.Equal(t, "tenant1-ue2-test-1", tenant1Ue2Test1InfraVpcStackInfrastructureStackName)
assert.Equal(t, "infra-vpc", tenant1Ue2Test1InfraVpcStackBackendWorkspaceKeyPrefix)

tenant1Ue2DevTestTestComponentOverrideComponent := spaceliftStacks["tenant1-ue2-dev-test-test-component-override"].(map[string]interface{})
tenant1Ue2DevTestTestComponentOverrideComponentInfrastructureStackName := tenant1Ue2DevTestTestComponentOverrideComponent["stack"].(string)
tenant1Ue2DevTestTestComponentOverrideComponentBackend := tenant1Ue2DevTestTestComponentOverrideComponent["backend"].(map[interface{}]interface{})
Expand Down Expand Up @@ -70,6 +78,11 @@ func TestSpaceliftStackProcessor(t *testing.T) {
newTenant1Ue2DevTestTestComponentOverrideComponent2InfrastructureStackName := newTenant1Ue2DevTestTestComponentOverrideComponent2["stack"].(string)
assert.Equal(t, "tenant1-ue2-dev", newTenant1Ue2DevTestTestComponentOverrideComponent2InfrastructureStackName)

// Test having a dash `-` in tenant/environment/stage names
newTenant1Ue2Test1TestTestComponentOverrideComponent2 := spaceliftStacks["tenant1-ue2-test-1-new-component"].(map[string]interface{})
newTenant1Ue2Test1TestTestComponentOverrideComponent2InfrastructureStackName := newTenant1Ue2Test1TestTestComponentOverrideComponent2["stack"].(string)
assert.Equal(t, "tenant1-ue2-test-1", newTenant1Ue2Test1TestTestComponentOverrideComponent2InfrastructureStackName)

yamlSpaceliftStacks, err := yaml.Marshal(spaceliftStacks)
assert.Nil(t, err)
t.Log(string(yamlSpaceliftStacks))
Expand All @@ -82,6 +95,7 @@ func TestLegacySpaceliftStackProcessor(t *testing.T) {
"../../examples/complete/stacks/tenant1/ue2/dev.yaml",
"../../examples/complete/stacks/tenant1/ue2/prod.yaml",
"../../examples/complete/stacks/tenant1/ue2/staging.yaml",
"../../examples/complete/stacks/tenant1/ue2/test1.yaml",
"../../examples/complete/stacks/tenant2/ue2/dev.yaml",
"../../examples/complete/stacks/tenant2/ue2/prod.yaml",
"../../examples/complete/stacks/tenant2/ue2/staging.yaml",
Expand All @@ -94,7 +108,7 @@ func TestLegacySpaceliftStackProcessor(t *testing.T) {

var spaceliftStacks, err = CreateSpaceliftStacks(basePath, filePaths, processStackDeps, processComponentDeps, processImports, stackConfigPathTemplate)
assert.Nil(t, err)
assert.Equal(t, 30, len(spaceliftStacks))
assert.Equal(t, 35, len(spaceliftStacks))

tenant1Ue2DevInfraVpcStack := spaceliftStacks["tenant1-ue2-dev-infra-vpc"].(map[string]interface{})
tenant1Ue2DevInfraVpcStackBackend := tenant1Ue2DevInfraVpcStack["backend"].(map[interface{}]interface{})
Expand Down
6 changes: 4 additions & 2 deletions pkg/stack/stack_processor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,22 @@ func TestStackProcessor(t *testing.T) {
"../../examples/complete/stacks/tenant1/ue2/dev.yaml",
"../../examples/complete/stacks/tenant1/ue2/prod.yaml",
"../../examples/complete/stacks/tenant1/ue2/staging.yaml",
"../../examples/complete/stacks/tenant1/ue2/test1.yaml",
}

processStackDeps := true
processComponentDeps := true

var listResult, mapResult, err = ProcessYAMLConfigFiles(basePath, filePaths, processStackDeps, processComponentDeps)
assert.Nil(t, err)
assert.Equal(t, 3, len(listResult))
assert.Equal(t, 3, len(mapResult))
assert.Equal(t, 4, len(listResult))
assert.Equal(t, 4, len(mapResult))

mapResultKeys := u.StringKeysFromMap(mapResult)
assert.Equal(t, "tenant1/ue2/dev", mapResultKeys[0])
assert.Equal(t, "tenant1/ue2/prod", mapResultKeys[1])
assert.Equal(t, "tenant1/ue2/staging", mapResultKeys[2])
assert.Equal(t, "tenant1/ue2/test1", mapResultKeys[3])

mapConfig1, err := c.YAMLToMapOfInterfaces(listResult[0])
assert.Nil(t, err)
Expand Down

0 comments on commit ae7272f

Please sign in to comment.