Skip to content

Commit

Permalink
Add function to provisioner interface to for setting up a new bundle (#…
Browse files Browse the repository at this point in the history
…139)

* Add function to provisioner interface to for setting up a new bundle (copying files)

* remove unnecessary comment

* remove unnecessary comment
  • Loading branch information
chrisghill authored Aug 19, 2024
1 parent 4ce53f4 commit 4ef28e9
Show file tree
Hide file tree
Showing 17 changed files with 256 additions and 8 deletions.
6 changes: 3 additions & 3 deletions cmd/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ func runBundleBuild(cmd *cobra.Command, args []string) error {
return err
}

unmarshalledBundle, err := bundle.UnmarshalandApplyDefaults(buildDirectory)
unmarshalledBundle, err := bundle.UnmarshalAndApplyDefaults(buildDirectory)
if err != nil {
return err
}
Expand All @@ -267,7 +267,7 @@ func runBundleLint(cmd *cobra.Command, args []string) error {
return err
}

unmarshalledBundle, err := bundle.UnmarshalandApplyDefaults(buildDirectory)
unmarshalledBundle, err := bundle.UnmarshalAndApplyDefaults(buildDirectory)
if err != nil {
return err
}
Expand All @@ -293,7 +293,7 @@ func runBundlePublish(cmd *cobra.Command, args []string) error {
return err
}

unmarshalledBundle, err := bundle.UnmarshalandApplyDefaults(buildDirectory)
unmarshalledBundle, err := bundle.UnmarshalAndApplyDefaults(buildDirectory)
if err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/bundle/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ func Unmarshal(readDirectory string) (*Bundle, error) {
return unmarshalledBundle, nil
}

func UnmarshalandApplyDefaults(readDirectory string) (*Bundle, error) {
func UnmarshalAndApplyDefaults(readDirectory string) (*Bundle, error) {
unmarshalledBundle, err := Unmarshal(readDirectory)
if err != nil {
return nil, err
Expand Down
27 changes: 26 additions & 1 deletion pkg/commands/generate_new_bundle.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,34 @@
package commands

import (
"path"

"github.com/massdriver-cloud/mass/pkg/bundle"
"github.com/massdriver-cloud/mass/pkg/provisioners"
"github.com/massdriver-cloud/mass/pkg/templatecache"
)

func GenerateNewBundle(bundleCache templatecache.TemplateCache, templateData *templatecache.TemplateData) error {
return bundleCache.RenderTemplate(templateData)
renderErr := bundleCache.RenderTemplate(templateData)
if renderErr != nil {
return renderErr
}

// if we imported params from existing IaC, pass that to the provisioner in case more initialization should be done
if templateData.ExistingParamsPath != "" {
b, unmarshalErr := bundle.UnmarshalAndApplyDefaults(templateData.OutputDir)
if unmarshalErr != nil {
return unmarshalErr
}

for _, step := range b.Steps {
prov := provisioners.NewProvisioner(step.Provisioner)
initErr := prov.InitializeStep(path.Join(templateData.OutputDir, step.Path), templateData.ExistingParamsPath)
if initErr != nil {
return initErr
}
}
}

return nil
}
13 changes: 13 additions & 0 deletions pkg/provisioners/bicep.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package provisioners
import (
"bytes"
"encoding/json"
"errors"
"os"
"path"

Expand Down Expand Up @@ -68,3 +69,15 @@ func (p *BicepProvisioner) ReadProvisionerInputs(stepPath string) (map[string]in

return variables, nil
}

func (p *BicepProvisioner) InitializeStep(stepPath string, sourcePath string) error {
pathInfo, statErr := os.Stat(sourcePath)
if statErr != nil {
return statErr
}
if pathInfo.IsDir() {
return errors.New("path is a directory not a bicep template")
}

return copyFile(sourcePath, path.Join(stepPath, "template.bicep"))
}
37 changes: 37 additions & 0 deletions pkg/provisioners/bicep_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,3 +154,40 @@ func TestBicepReadProvisionerInputs(t *testing.T) {
})
}
}

func TestBicepInitializeStep(t *testing.T) {
type test struct {
name string
templatePath string
want string
}
tests := []test{
{
name: "same",
templatePath: "testdata/bicep/inittest.bicep",
want: `foobar
`,
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
testDir := t.TempDir()

prov := provisioners.BicepProvisioner{}
initErr := prov.InitializeStep(testDir, tc.templatePath)
if initErr != nil {
t.Fatalf("unexpected error: %s", initErr)
}

got, gotErr := os.ReadFile(path.Join(testDir, "template.bicep"))
if gotErr != nil {
t.Fatalf("unexpected error: %s", gotErr)
}

if string(got) != tc.want {
t.Errorf("want %v got %v", got, tc.want)
}
})
}
}
82 changes: 82 additions & 0 deletions pkg/provisioners/copy.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
package provisioners

import (
"fmt"
"io"
"os"
"path/filepath"
)

// CopyFile copies a single file from source to destination.
func copyFile(src, dst string) error {
sourceFileStat, err := os.Stat(src)
if err != nil {
return err
}

if !sourceFileStat.Mode().IsRegular() {
return fmt.Errorf("%s is not a regular file", src)
}

source, err := os.Open(src)
if err != nil {
return err
}
defer source.Close()

destination, err := os.Create(dst)
if err != nil {
return err
}
defer destination.Close()

_, err = io.Copy(destination, source)
return err
}

// CopyDir copies a whole directory recursively from src to dst,
// ignoring files and directories that match any of the ignore patterns.
func copyDir(src string, dst string, ignorePatterns []string) error {
entries, err := os.ReadDir(src)
if err != nil {
return err
}

for _, entry := range entries {
srcPath := filepath.Join(src, entry.Name())
dstPath := filepath.Join(dst, entry.Name())

if shouldIgnore(srcPath, ignorePatterns) {
continue
}

if entry.IsDir() {
if err := os.MkdirAll(dstPath, entry.Type().Perm()); err != nil {

Check failure on line 54 in pkg/provisioners/copy.go

View workflow job for this annotation

GitHub Actions / lint

shadow: declaration of "err" shadows declaration at line 40 (govet)
return err
}
if err := copyDir(srcPath, dstPath, ignorePatterns); err != nil {

Check failure on line 57 in pkg/provisioners/copy.go

View workflow job for this annotation

GitHub Actions / lint

shadow: declaration of "err" shadows declaration at line 40 (govet)
return err
}
} else {
if err := copyFile(srcPath, dstPath); err != nil {

Check failure on line 61 in pkg/provisioners/copy.go

View workflow job for this annotation

GitHub Actions / lint

shadow: declaration of "err" shadows declaration at line 40 (govet)
return err
}
}
}
return nil
}

// shouldIgnore checks if a given path matches any of the glob patterns.
func shouldIgnore(path string, patterns []string) bool {
for _, pattern := range patterns {
matched, err := filepath.Match(pattern, filepath.Base(path))
if err != nil {
fmt.Printf("Error matching pattern: %v\n", err)
continue
}
if matched {
return true
}
}
return false
}
30 changes: 30 additions & 0 deletions pkg/provisioners/opentofu.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package provisioners
import (
"bytes"
"encoding/json"
"errors"
"os"
"path"

Expand Down Expand Up @@ -69,3 +70,32 @@ func (p *OpentofuProvisioner) ReadProvisionerInputs(stepPath string) (map[string

return variables, nil
}

func (p *OpentofuProvisioner) InitializeStep(stepPath string, sourcePath string) error {
pathInfo, statErr := os.Stat(sourcePath)
if statErr != nil {
return statErr
}
if !pathInfo.IsDir() {
return errors.New("path is not a directory, cannot initialize")
}

// remove the dummy main.tf if we are copying from a source
maintfPath := path.Join(stepPath, "main.tf")
if _, maintfErr := os.Stat(maintfPath); maintfErr == nil {
err := os.Remove(maintfPath)
if err != nil {
return err
}
}

// intentionally not ignoring the .terraform.lock.hcl file since it should be copied
ignorePatterns := []string{
".terraform",
"*.tfstate",
"*.tfstate.backup",
"*.tfvars",
"*.tfvars.json",
}
return copyDir(sourcePath, stepPath, ignorePatterns)
}
51 changes: 51 additions & 0 deletions pkg/provisioners/opentofu_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"os"
"path"
"reflect"
"slices"
"testing"

"github.com/massdriver-cloud/mass/pkg/provisioners"
Expand Down Expand Up @@ -155,3 +156,53 @@ func TestOpentofuReadProvisionerInputs(t *testing.T) {
})
}
}

func TestOpentofuInitializeStep(t *testing.T) {
type test struct {
name string
modulePath string
want []string
}
tests := []test{
{
name: "same",
modulePath: "testdata/opentofu/initializetest",
want: []string{
"foo.tf",
".terraform.lock.hcl",
},
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
testDir := t.TempDir()

_, createErr := os.Create(path.Join(testDir, "main.tf"))
if createErr != nil {
t.Fatalf("unexpected error: %s", createErr)
return
}

prov := provisioners.OpentofuProvisioner{}
initErr := prov.InitializeStep(testDir, tc.modulePath)
if initErr != nil {
t.Fatalf("unexpected error: %s", initErr)
}

got, gotErr := os.ReadDir(testDir)
if gotErr != nil {
t.Fatalf("unexpected error: %s", gotErr)
}

if len(got) != len(tc.want) {
t.Errorf("want %v got %v", got, tc.want)
}
for _, curr := range got {
if !slices.Contains(tc.want, curr.Name()) {
t.Errorf("%v doesn't exist in %v", curr.Name(), tc.want)
}
}
})
}
}
1 change: 1 addition & 0 deletions pkg/provisioners/testdata/bicep/inittest.bicep
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
foobar

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
foo
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
foo
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
foo
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
foo = bar
8 changes: 6 additions & 2 deletions pkg/provisioners/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package provisioners
type Provisioner interface {
ExportMassdriverInputs(stepPath string, variables map[string]interface{}) error
ReadProvisionerInputs(stepPath string) (map[string]interface{}, error)
InitializeStep(stepPath string, sourcePath string) error
}

func NewProvisioner(provisionerType string) Provisioner {
Expand All @@ -18,9 +19,12 @@ func NewProvisioner(provisionerType string) Provisioner {

type NoopProvisioner struct{}

func (p *NoopProvisioner) ExportMassdriverInputs(_ string, _ map[string]interface{}) error {
func (p *NoopProvisioner) ExportMassdriverInputs(string, map[string]interface{}) error {
return nil
}
func (p *NoopProvisioner) ReadProvisionerInputs(_ string) (map[string]interface{}, error) {
func (p *NoopProvisioner) ReadProvisionerInputs(string) (map[string]interface{}, error) {
return nil, nil

Check failure on line 26 in pkg/provisioners/types.go

View workflow job for this annotation

GitHub Actions / lint

return both the `nil` error and invalid value: use a sentinel error instead (nilnil)
}
func (p *NoopProvisioner) InitializeStep(string, string) error {
return nil
}
2 changes: 1 addition & 1 deletion pkg/server/bundle/bundle.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ func (h *Handler) Build(w http.ResponseWriter, r *http.Request) {
return
}

unmarshalledBundle, err := bundle.UnmarshalandApplyDefaults(h.bundleDir)
unmarshalledBundle, err := bundle.UnmarshalAndApplyDefaults(h.bundleDir)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
Expand Down

0 comments on commit 4ef28e9

Please sign in to comment.