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

feat: add support for organization environment variables #406

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
9 changes: 8 additions & 1 deletion cmd/config_fastly.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ func FastlyConfigGeneration(debug bool, domain string) (lagoon.Fastly, error) {
if err != nil {
return lagoon.Fastly{}, fmt.Errorf("error reading fastly-service-id flag: %v", err)
}
organizationVariables, err := rootCmd.PersistentFlags().GetString("organization-variables")
if err != nil {
return lagoon.Fastly{}, fmt.Errorf("error reading organization-variables flag: %v", err)
}
projectVariables, err := rootCmd.PersistentFlags().GetString("project-variables")
if err != nil {
return lagoon.Fastly{}, fmt.Errorf("error reading project-variables flag: %v", err)
Expand All @@ -53,15 +57,18 @@ func FastlyConfigGeneration(debug bool, domain string) (lagoon.Fastly, error) {
fastlyServiceID = helpers.GetEnv("ROUTE_FASTLY_SERVICE_ID", fastlyServiceID, debug)

// get the project and environment variables
organizationVariables = helpers.GetEnv("LAGOON_ORGANIZATION_VARIABLES", organizationVariables, debug)
projectVariables = helpers.GetEnv("LAGOON_PROJECT_VARIABLES", projectVariables, debug)
environmentVariables = helpers.GetEnv("LAGOON_ENVIRONMENT_VARIABLES", environmentVariables, debug)

// unmarshal and then merge the two so there is only 1 set of variables to iterate over
orgVars := []lagoon.EnvironmentVariable{}
projectVars := []lagoon.EnvironmentVariable{}
envVars := []lagoon.EnvironmentVariable{}
json.Unmarshal([]byte(organizationVariables), &orgVars)
json.Unmarshal([]byte(projectVariables), &projectVars)
json.Unmarshal([]byte(environmentVariables), &envVars)
lagoonEnvVars := lagoon.MergeVariables(projectVars, envVars)
lagoonEnvVars := lagoon.MergeVariables(orgVars, projectVars, envVars, []lagoon.EnvironmentVariable{})

// generate the fastly configuration from the provided flags/variables
f := &lagoon.Fastly{}
Expand Down
20 changes: 20 additions & 0 deletions cmd/identify_feature_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,26 @@ func TestIdentifyFeatureFlag(t *testing.T) {
},
want: "enabled",
},
{
name: "test7 check if flag is defined in lagoon organization variables",
varName: "ROOTLESS_WORKLOAD",
args: testdata.GetSeedData(
testdata.TestData{
ProjectName: "example-project",
EnvironmentName: "main",
Branch: "main",
LagoonYAML: "internal/testdata/node/lagoon.yml",
OrganizationVariables: []lagoon.EnvironmentVariable{
{
Name: "LAGOON_FEATURE_FLAG_ROOTLESS_WORKLOAD",
Value: "enabled",
Scope: "build",
},
},
}, true),
templatePath: "testoutput",
want: "enabled",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down
2 changes: 2 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@ func init() {
"The pullrequest base branch")
rootCmd.PersistentFlags().StringP("lagoon-version", "L", "",
"The lagoon version")
rootCmd.PersistentFlags().StringP("organization-variables", "", "",
"The JSON payload for organization scope variables")
rootCmd.PersistentFlags().StringP("project-variables", "", "",
"The JSON payload for project scope variables")
rootCmd.PersistentFlags().StringP("environment-variables", "", "",
Expand Down
1 change: 1 addition & 0 deletions docs/buildrequirements.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ These are variables that are injected into a build pod by `remote-controller`, s
* `PROMOTION_SOURCE_ENVIRONMENT` contains the source environment name if this is a promotion type build

#### Environment Variables
* `LAGOON_ORGANIZATION_VARIABLES` contains any organization specific environment variables
* `LAGOON_PROJECT_VARIABLES` contains any project specific environment variables
* `LAGOON_ENVIRONMENT_VARIABLES` contains any environment specific environment variables

Expand Down
9 changes: 5 additions & 4 deletions internal/generator/generator.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type GeneratorInput struct {
EnvironmentType string
ActiveEnvironment string
StandbyEnvironment string
OrganizationVariables string
ProjectVariables string
EnvironmentVariables string
BuildType string
Expand Down Expand Up @@ -139,6 +140,7 @@ func NewGenerator(
buildValues.Backup.K8upVersion = helpers.GetEnv("K8UP_VERSION", generator.BackupConfiguration.K8upVersion, generator.Debug)

// get the project and environment variables
organizationVariables := helpers.GetEnv("LAGOON_ORGANIZATION_VARIABLES", generator.OrganizationVariables, generator.Debug)
projectVariables := helpers.GetEnv("LAGOON_PROJECT_VARIABLES", generator.ProjectVariables, generator.Debug)
environmentVariables := helpers.GetEnv("LAGOON_ENVIRONMENT_VARIABLES", generator.EnvironmentVariables, generator.Debug)

Expand Down Expand Up @@ -245,16 +247,15 @@ func NewGenerator(
}

// unmarshal and then merge the two so there is only 1 set of variables to iterate over
orgVars := []lagoon.EnvironmentVariable{}
projectVars := []lagoon.EnvironmentVariable{}
envVars := []lagoon.EnvironmentVariable{}
json.Unmarshal([]byte(organizationVariables), &orgVars)
json.Unmarshal([]byte(projectVariables), &projectVars)
json.Unmarshal([]byte(environmentVariables), &envVars)
mergedVariables := lagoon.MergeVariables(projectVars, envVars)
// collect a bunch of the default LAGOON_X based build variables that are injected into `lagoon-env` and make them available
configVars := collectBuildVariables(buildValues)
// add the calculated build runtime variables into the existing variable slice
// this will later be used to add `runtime|global` scope into the `lagoon-env` configmap
buildValues.EnvironmentVariables = lagoon.MergeVariables(mergedVariables, configVars)
buildValues.EnvironmentVariables = lagoon.MergeVariables(orgVars, projectVars, envVars, configVars)

// if the core version is provided from the API, set the buildvalues LagoonVersion to this instead
lagoonCoreVersion, _ := lagoon.GetLagoonVariable("LAGOON_SYSTEM_CORE_VERSION", []string{"internal_system"}, buildValues.EnvironmentVariables)
Expand Down
1 change: 1 addition & 0 deletions internal/helpers/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,7 @@ func UnsetEnvVars(localVars []EnvironmentVariable) {
"ACTIVE_ENVIRONMENT",
"STANDBY_ENVIRONMENT",
"LAGOON_FASTLY_NOCACHE_SERVICE_ID",
"LAGOON_ORGANIZATION_VARIABLES",
"LAGOON_PROJECT_VARIABLES",
"LAGOON_ENVIRONMENT_VARIABLES",
"LAGOON_VERSION",
Expand Down
72 changes: 40 additions & 32 deletions internal/lagoon/variables.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package lagoon

import (
"fmt"
"slices"

"github.com/uselagoon/build-deploy-tool/internal/helpers"
)
Expand All @@ -14,44 +15,51 @@ type EnvironmentVariable struct {
}

// MergeVariables merges lagoon environment variables.
func MergeVariables(project, environment []EnvironmentVariable) []EnvironmentVariable {
allVars := []EnvironmentVariable{}
existsInEnvironment := false
// replace any variables from the project with ones from the environment
// this only modifies ones that exist in project
for _, pVar := range project {
add := EnvironmentVariable{}
for _, eVar := range environment {
// internal_system scoped variables are only added to the projects variabled during a build
// this make sure that any that may exist in the environment variables are not merged
// and also makes sure that internal_system variables are not replaced by other scopes
if eVar.Name == pVar.Name && pVar.Scope != "internal_system" && eVar.Scope != "internal_system" {
existsInEnvironment = true
add = eVar
}
func MergeVariables(organization, project, environment, config []EnvironmentVariable) []EnvironmentVariable {

// Helper function to compare environment variable names.
findByName := func(name string) func(EnvironmentVariable) bool {
return func(eVar EnvironmentVariable) bool { return eVar.Name == name }
}

// Start with config variables since they are most specific.
allVars := make([]EnvironmentVariable, len(config))
copy(allVars, config)

for _, eVar := range environment {
idx := slices.IndexFunc(allVars, findByName(eVar.Name))

// Append environment variables that are distinct.
if idx == -1 {
allVars = append(allVars, eVar)
}
if existsInEnvironment {
allVars = append(allVars, add)
existsInEnvironment = false
} else {
}

for _, pVar := range project {
idx := slices.IndexFunc(allVars, findByName(pVar.Name))

// Append project variables that are distinct.
if idx == -1 {
allVars = append(allVars, pVar)
continue
}
}
// add any that exist in the environment only to the final variables list
existsInProject := false
for _, eVar := range environment {
add := eVar
for _, aVar := range allVars {
if eVar.Name == aVar.Name {
existsInProject = true
}

// Overwrite environment variables if they are suppossed to be internally
// scoped.
if pVar.Scope == "internal_system" {
allVars[idx] = pVar
}
if existsInProject {
existsInProject = false
} else {
allVars = append(allVars, add)
}

for _, oVar := range organization {
idx := slices.IndexFunc(allVars, findByName(oVar.Name))

// Append organization variables that are distinct.
if idx == -1 {
allVars = append(allVars, oVar)
}
}

return allVars
}

Expand Down
Loading
Loading