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(harness): add stackrun variables support to terraform #251

Merged
merged 4 commits into from
Aug 22, 2024
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
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ require (
github.com/open-policy-agent/gatekeeper/v3 v3.15.1
github.com/orcaman/concurrent-map/v2 v2.0.1
github.com/pkg/errors v0.9.1
github.com/pluralsh/console/go/client v1.8.0
github.com/pluralsh/console/go/client v1.12.0
github.com/pluralsh/controller-reconcile-helper v0.0.4
github.com/pluralsh/gophoenix v0.1.3-0.20231201014135-dff1b4309e34
github.com/pluralsh/polly v0.1.10
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -641,8 +641,8 @@ github.com/phayes/freeport v0.0.0-20220201140144-74d24b5ae9f5/go.mod h1:iIss55rK
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pluralsh/console/go/client v1.8.0 h1:iFMb8mNExuko0ffKReUzqaplgfcL3CI/lAgaWiVyCUE=
github.com/pluralsh/console/go/client v1.8.0/go.mod h1:lpoWASYsM9keNePS3dpFiEisUHEfObIVlSL3tzpKn8k=
github.com/pluralsh/console/go/client v1.12.0 h1:1djVBV9GMEe1I6yKv0bWu2Qx8dnsVgGzhntGSY+KLCw=
github.com/pluralsh/console/go/client v1.12.0/go.mod h1:lpoWASYsM9keNePS3dpFiEisUHEfObIVlSL3tzpKn8k=
github.com/pluralsh/controller-reconcile-helper v0.0.4 h1:1o+7qYSyoeqKFjx+WgQTxDz4Q2VMpzprJIIKShxqG0E=
github.com/pluralsh/controller-reconcile-helper v0.0.4/go.mod h1:AfY0gtteD6veBjmB6jiRx/aR4yevEf6K0M13/pGan/s=
github.com/pluralsh/gophoenix v0.1.3-0.20231201014135-dff1b4309e34 h1:ab2PN+6if/Aq3/sJM0AVdy1SYuMAnq4g20VaKhTm/Bw=
Expand Down
10 changes: 9 additions & 1 deletion internal/helpers/env.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package helpers

import (
"fmt"
"io"
"os"
"strconv"
"strings"

"k8s.io/klog/v2"

Expand Down Expand Up @@ -61,12 +63,18 @@ func EnsureDirOrDie(dir string) {
klog.V(log.LogLevelDebug).Infof("created directory: %s", dir)
}

func EnsureFileOrDie(file string) string {
func EnsureFileOrDie(file string, content *string) string {
f, err := os.Create(file)
if err != nil && !os.IsExist(err) {
panic(fmt.Errorf("could not create file: %w", err))
}

if content != nil {
if _, err = io.Copy(f, strings.NewReader(*content)); err != nil {
panic(fmt.Errorf("could not copy content: %w", err))
}
}

klog.V(log.LogLevelDebug).Infof("created file: %s", file)
return f.Name()
}
Expand Down
7 changes: 6 additions & 1 deletion pkg/harness/controller/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,12 @@ func (in *stackRunController) prepare() error {
return err
}

in.tool = tool.New(in.stackRun.Type, in.dir, in.execWorkDir())
variables, err := in.stackRun.Vars()
if err != nil {
return err
}

in.tool = tool.New(in.stackRun.Type, in.dir, in.execWorkDir(), variables)

return nil
}
Expand Down
13 changes: 13 additions & 0 deletions pkg/harness/stackrun/v1/types.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package v1

import (
"encoding/json"
"fmt"

gqlclient "github.com/pluralsh/console/go/client"
Expand All @@ -21,6 +22,7 @@ type StackRun struct {
ManageState bool
Creds *gqlclient.StackRunBaseFragment_PluralCreds
StateUrls *gqlclient.StackRunBaseFragment_StateUrls
Variables map[string]interface{}
}

func (in *StackRun) FromStackRunBaseFragment(fragment *gqlclient.StackRunBaseFragment) *StackRun {
Expand All @@ -38,6 +40,7 @@ func (in *StackRun) FromStackRunBaseFragment(fragment *gqlclient.StackRunBaseFra
ManageState: fragment.ManageState != nil && *fragment.ManageState,
Creds: fragment.PluralCreds,
StateUrls: fragment.StateUrls,
Variables: fragment.Variables,
}
}

Expand All @@ -58,6 +61,16 @@ func (in *StackRun) Env() []string {
return env
}

// Vars parses the StackRun.Variables map as a valid JSON.
func (in *StackRun) Vars() (*string, error) {
if in.Variables == nil {
return nil, nil
}

data, err := json.Marshal(in.Variables)
return lo.ToPtr(string(data)), err
}

type Lifecycle string

const (
Expand Down
12 changes: 8 additions & 4 deletions pkg/harness/tool/ansible/ansible.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,23 @@ func (in *Ansible) Plan() (*console.StackStateAttributes, error) {

// Modifier implements [v1.Tool] interface.
func (in *Ansible) Modifier(stage console.StepStage) v1.Modifier {
globalEnvModifier := NewGlobalEnvModifier(in.workDir)
modifiers := []v1.Modifier{NewGlobalEnvModifier(in.workDir)}

if in.variables != nil {
modifiers = append(modifiers, NewVariableInjectorModifier(in.variablesFileName))
}

if stage == console.StepStagePlan {
return v1.NewMultiModifier(NewPassthroughModifier(in.planFilePath), globalEnvModifier)
modifiers = append(modifiers, NewPassthroughModifier(in.planFilePath))
}

return globalEnvModifier
return v1.NewMultiModifier(modifiers...)
}

func (in *Ansible) init() *Ansible {
in.planFileName = "ansible.plan"
in.planFilePath = path.Join(in.execDir, in.planFileName)
helpers.EnsureFileOrDie(in.planFilePath)
helpers.EnsureFileOrDie(in.planFilePath, nil)

return in
}
Expand Down
8 changes: 8 additions & 0 deletions pkg/harness/tool/ansible/ansible_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,12 @@ type Ansible struct {

// planFilePath
planFilePath string

// variablesFileName is an ansible variables file name.
// Default: plural.variables.json
variablesFileName string

// variables is a JSON encoded string representing
// ansible variable file.
variables *string
}
8 changes: 8 additions & 0 deletions pkg/harness/tool/ansible/modifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,11 @@ func (in *GlobalEnvModifier) Env(env []string) []string {
func NewGlobalEnvModifier(workDir string) v1.Modifier {
return &GlobalEnvModifier{workDir: workDir}
}

func (in *VariableInjectorModifier) Args(args []string) []string {
return append(args, fmt.Sprintf("--extra-vars @%s", in.variablesFile))
}

func NewVariableInjectorModifier(variablesFile string) v1.Modifier {
return &VariableInjectorModifier{variablesFile: variablesFile}
}
7 changes: 7 additions & 0 deletions pkg/harness/tool/ansible/modifier_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,13 @@ type GlobalEnvModifier struct {
workDir string
}

type VariableInjectorModifier struct {
v1.DefaultModifier

// variablesFile
variablesFile string
}

const (
ansibleDir = ".ansible"
ansibleTmpDir = "tmp"
Expand Down
11 changes: 7 additions & 4 deletions pkg/harness/tool/terraform/terraform.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,14 +142,17 @@ func (in *Terraform) plan() (string, error) {
return string(output), nil
}

func (in *Terraform) init() *Terraform {
func (in *Terraform) init() v1.Tool {
in.planFileName = "terraform.tfplan"
helpers.EnsureFileOrDie(path.Join(in.dir, in.planFileName))
helpers.EnsureFileOrDie(path.Join(in.dir, in.planFileName), nil)

in.variablesFileName = "plural.auto.tfvars.json"
helpers.EnsureFileOrDie(path.Join(in.dir, in.variablesFileName), in.variables)

return in
}

// New creates a Terraform structure that implements v1.Tool interface.
func New(dir string) v1.Tool {
return (&Terraform{dir: dir}).init()
func New(dir string, variables *string) v1.Tool {
return (&Terraform{dir: dir, variables: variables}).init()
}
8 changes: 8 additions & 0 deletions pkg/harness/tool/terraform/terraform_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,12 @@ type Terraform struct {
// planFileName is a terraform plan file name.
// Default: terraform.tfplan
planFileName string

// variablesFileName is a terraform variables file name.
// Default: plural.auto.tfvars.json
variablesFileName string

// variables is a JSON encoded string representing
// terraform variable file.
variables *string
}
4 changes: 2 additions & 2 deletions pkg/harness/tool/tool.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ import (

// New creates a specific tool implementation structure based on the provided
// gqlclient.StackType.
func New(stackType console.StackType, workDir, execDir string) v1.Tool {
func New(stackType console.StackType, workDir, execDir string, variables *string) v1.Tool {
var t v1.Tool

switch stackType {
case console.StackTypeTerraform:
t = terraform.New(execDir)
t = terraform.New(execDir, variables)
case console.StackTypeAnsible:
t = ansible.New(workDir, execDir)
case console.StackTypeCustom:
Expand Down
Loading