Skip to content

Commit

Permalink
adding tests
Browse files Browse the repository at this point in the history
  • Loading branch information
rafaela-soares committed Aug 19, 2022
1 parent 28e75b8 commit b29f0f3
Show file tree
Hide file tree
Showing 4 changed files with 187 additions and 84 deletions.
105 changes: 38 additions & 67 deletions pkg/terraformer/terraformer.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ package terraformer
import (
"fmt"
"io"
"io/fs"
"os"
"os/exec"
"path/filepath"
Expand All @@ -21,6 +20,12 @@ import (

const terraformerPathLength = 2

// for testing purposes
var (
runTerraformerFunc func(pathOptions *Path, destination string) (string, error) = runTerraformer
saveTerraformerOutputFunc func(destination, output string) error = saveTerraformerOutput
)

// Path is a struct that contains the terraformer path information
type Path struct {
CloudProvider string
Expand All @@ -46,27 +51,17 @@ func Import(terraformerPath, destinationPath string) (string, error) {

destFolderName := fmt.Sprintf("kics-extract-terraformer-%s", time.Now().Format("01-02-2006"))

// destination folder where the Terraform resources will be saved
// set destination folder path where the Terraform resources will be saved
destination := filepath.Join(destinationPath, destFolderName)

args := buildArgs(pathOptions, destination)
fmt.Println(args)

cmd := exec.Command("terraformer", args...)
cmd.Env = os.Environ()

fmt.Println(cmd.Env)

output, err := cmd.CombinedOutput()
fmt.Println(string(output))
// run Terraformer
output, err := runTerraformerFunc(pathOptions, destination)
if err != nil {
return "", errors.Wrap(err, "failed to import resources")
}

_, err = os.Stat(destination)
fmt.Println(err)
saveTerraformerOutput(destination, string(output), err)

// save Terraform output
err = saveTerraformerOutputFunc(destination, output)
if err != nil {
return "", errors.Wrap(err, "failed to import resources")
}
Expand All @@ -80,7 +75,9 @@ func Import(terraformerPath, destinationPath string) (string, error) {
// {CloudProvider}:{Resources}:{Regions}:{Projects}
func extractTerraformerOptions(path string) (*Path, error) {
pathInfo := strings.Split(path, ":")
if len(pathInfo) != terraformerPathLength && len(pathInfo) != terraformerPathLength+1 {
if len(pathInfo) != terraformerPathLength &&
len(pathInfo) != terraformerPathLength+2 &&
len(pathInfo) != terraformerPathLength+1 {
return nil, errors.New("wrong terraformer path syntax")
}
return &Path{
Expand All @@ -91,30 +88,6 @@ func extractTerraformerOptions(path string) (*Path, error) {
}, nil
}

// cleanUnwantedFiles deletes the output files from the destination folder
func cleanUnwantedFiles(destination string) {
err := filepath.Walk(destination, func(path string, info fs.FileInfo, err error) error {
if info != nil {
deleteOutputFile(path, info)
}
return nil
})

if err != nil {
log.Err(err).Msg("failed to clean unwanted files")
}
}

// deleteOutputFile deletes a 'outputs.tf' file
func deleteOutputFile(path string, output fs.FileInfo) {
if output.Name() == "outputs.tf" {
err := os.Remove(path)
if err != nil {
log.Err(err).Msgf("failed to remove outputs.tf in path %s", path)
}
}
}

// getProjects gets all the projects pointed in the KICS Terraformer Path Syntax
// projects are only required for gcp
func getProjects(pathInfo []string) string {
Expand All @@ -125,6 +98,8 @@ func getProjects(pathInfo []string) string {
return ""
}

// getRegions gets all the regions pointed in the KICS Terraformer Path Syntax
// regions are only required for aws and gcp
func getRegions(pathInfo []string) string {
if len(pathInfo) >= terraformerPathLength+1 {
return strings.ReplaceAll(pathInfo[2], "/", ",")
Expand All @@ -149,44 +124,40 @@ func buildArgs(pathOptions *Path, destination string) []string {

// probably we will need to define the profile to ""
if pathOptions.CloudProvider == "aws" {
args = append(args, "--regions="+pathOptions.Regions)
args = append(args, "--profile=\"\"")
args = append(args, "--regions="+pathOptions.Regions, "--profile=\"\"")
}

// the flag '--projects' is only required for gcp
if pathOptions.Projects != "" && pathOptions.CloudProvider == "google" {
args = append(args, "--regions="+pathOptions.Regions)
args = append(args, "--projects="+pathOptions.Projects)
args = append(args, "--regions="+pathOptions.Regions, "--projects="+pathOptions.Projects)
}

return args
}

// saveTerraformerOutput saves the terraformer command output in the destination folder
func saveTerraformerOutput(destination, output string, statErr error) {
if statErr != nil {
if err := os.MkdirAll(destination, os.ModePerm); err != nil {
log.Error().Msgf("failed to mkdir: %s", err)
}
}
// runTerraformer runs the terraformer binary
func runTerraformer(pathOptions *Path, destination string) (string, error) {
args := buildArgs(pathOptions, destination)
fmt.Println(args)

filePath := filepath.Join(destination, "terraformer-output.txt")
filepath.Clean(filePath)
cmd := exec.Command("terraformer", args...)
cmd.Env = os.Environ()

f, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModePerm)
fmt.Println(cmd.Env)

if err != nil {
log.Error().Msgf("failed to open file '%s': %s", filePath, err)
}
output, err := cmd.CombinedOutput()
fmt.Println(string(output))

defer func(f *os.File) {
err = f.Close()
if err != nil {
log.Err(err).Msgf("failed to close file: %s", filePath)
}
}(f)
return string(output), err
}

if _, err = f.WriteString(output); err != nil {
log.Error().Msgf("failed to write file '%s': %s", filePath, err)
}
// saveTerraformerOutput verifies if the destination folder exists
// if not, it means that someting went wrong in the Terraformer command
// it also saves the terraformer command output in the destination folder
func saveTerraformerOutput(destination, output string) error {
_, err := os.Stat(destination)
fmt.Println(err)
save(destination, output, err)

return err
}
17 changes: 0 additions & 17 deletions pkg/terraformer/terraformer_alt.go

This file was deleted.

84 changes: 84 additions & 0 deletions pkg/terraformer/terraformer_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
//go:build !dev
// +build !dev

package terraformer

import (
"os"
"path/filepath"
"strings"
"testing"
)

func TestImport(t *testing.T) {
type args struct {
terraformerPath string
}
tests := []struct {
name string
runTerraformer func(pathOptions *Path, destination string) (string, error)
args args
want string
wantErr bool
}{
{
name: "test import aws",
runTerraformer: func(pathOptions *Path, destination string) (string, error) {
return "", nil
},
args: args{
terraformerPath: "aws:subnet:eu-west-2",
},
want: "kics-extract-terraformer",
wantErr: false,
},
{
name: "test import gcp",
runTerraformer: func(pathOptions *Path, destination string) (string, error) {
return "", nil
},
args: args{
terraformerPath: "gcp:instances:us-west4:cosmic-1234",
},
want: "kics-extract-terraformer",
wantErr: false,
},
{
name: "test import azure",
runTerraformer: func(pathOptions *Path, destination string) (string, error) {
return "", nil
},
args: args{
terraformerPath: "azure:storage_account",
},
want: "kics-extract-terraformer",
wantErr: false,
},
{
name: "test import path error",
runTerraformer: func(pathOptions *Path, destination string) (string, error) {
return "", nil
},
args: args{
terraformerPath: "aws",
},
want: ".",
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
runTerraformerFunc = tt.runTerraformer
saveTerraformerOutputFunc = func(destination, output string) error { return nil }
got, err := Import(tt.args.terraformerPath, "")
os.RemoveAll(got)
if (err != nil) != tt.wantErr {
t.Errorf("Import() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !strings.Contains(filepath.Base(got), filepath.Base(tt.want)) {
t.Errorf("Import() = %v, want %v", filepath.Base(got), filepath.Base(tt.want))
}
})
}
}
65 changes: 65 additions & 0 deletions pkg/terraformer/utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//go:build !dev
// +build !dev

package terraformer

import (
"io/fs"
"os"
"path/filepath"

"github.com/rs/zerolog/log"
)

// save saves the terraformer command output in the destination folder
func save(destination, output string, statErr error) {
if statErr != nil {
if err := os.MkdirAll(destination, os.ModePerm); err != nil {
log.Error().Msgf("failed to mkdir: %s", err)
}
}

filePath := filepath.Join(destination, "terraformer-output.txt")
filepath.Clean(filePath)

f, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, os.ModePerm)

if err != nil {
log.Error().Msgf("failed to open file '%s': %s", filePath, err)
}

defer func(f *os.File) {
err = f.Close()
if err != nil {
log.Err(err).Msgf("failed to close file: %s", filePath)
}
}(f)

if _, err = f.WriteString(output); err != nil {
log.Error().Msgf("failed to write file '%s': %s", filePath, err)
}
}

// cleanUnwantedFiles deletes the output files from the destination folder
func cleanUnwantedFiles(destination string) {
err := filepath.Walk(destination, func(path string, info fs.FileInfo, err error) error {
if info != nil {
deleteOutputFile(path, info)
}
return nil
})

if err != nil {
log.Err(err).Msg("failed to clean unwanted files")
}
}

// deleteOutputFile deletes a 'outputs.tf' file
func deleteOutputFile(path string, output fs.FileInfo) {
if output.Name() == "outputs.tf" {
err := os.Remove(path)
if err != nil {
log.Err(err).Msgf("failed to remove outputs.tf in path %s", path)
}
}
}

0 comments on commit b29f0f3

Please sign in to comment.