Skip to content

Commit 1fd6eb3

Browse files
committed
create new command adv2new
1 parent f0256f0 commit 1fd6eb3

File tree

14 files changed

+280
-0
lines changed

14 files changed

+280
-0
lines changed

cmd/plugin/main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"os"
66

7+
"github.com/mongodb-labs/atlas-cli-plugin-terraform/internal/cli/adv2new"
78
"github.com/mongodb-labs/atlas-cli-plugin-terraform/internal/cli/clu2adv"
89
"github.com/spf13/cobra"
910
)
@@ -15,6 +16,7 @@ func main() {
1516
Aliases: []string{"tf"},
1617
}
1718
terraformCmd.AddCommand(clu2adv.Builder())
19+
terraformCmd.AddCommand(adv2new.Builder())
1820

1921
completionOption := &cobra.CompletionOptions{
2022
DisableDefaultCmd: true,

internal/cli/adv2new/adv2new.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package adv2new
2+
3+
import (
4+
"github.com/mongodb-labs/atlas-cli-plugin-terraform/internal/flag"
5+
"github.com/spf13/afero"
6+
"github.com/spf13/cobra"
7+
)
8+
9+
func Builder() *cobra.Command {
10+
o := &opts{fs: afero.NewOsFs()}
11+
cmd := &cobra.Command{
12+
Use: "advancedClusterToNew",
13+
Short: "Convert advanced_cluster from provider version 1 to 2",
14+
Long: "Convert a Terraform configuration from mongodbatlas_advanced_cluster in provider version 1.X.X (SDKv2)" +
15+
" to version 2.X.X (TPF - Terraform Plugin Framework)",
16+
Aliases: []string{"adv2new"},
17+
RunE: func(_ *cobra.Command, _ []string) error {
18+
if err := o.PreRun(); err != nil {
19+
return err
20+
}
21+
return o.Run()
22+
},
23+
}
24+
cmd.Flags().StringVarP(&o.file, flag.File, flag.FileShort, "", "input file")
25+
_ = cmd.MarkFlagRequired(flag.File)
26+
cmd.Flags().StringVarP(&o.output, flag.Output, flag.OutputShort, "", "output file")
27+
_ = cmd.MarkFlagRequired(flag.Output)
28+
cmd.Flags().BoolVarP(&o.replaceOutput, flag.ReplaceOutput, flag.ReplaceOutputShort, false,
29+
"replace output file if exists")
30+
cmd.Flags().BoolVarP(&o.watch, flag.Watch, flag.WatchShort, false,
31+
"keeps the plugin running and watches the input file for changes")
32+
return cmd
33+
}

internal/cli/adv2new/opts.go

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
package adv2new
2+
3+
import (
4+
"errors"
5+
"fmt"
6+
7+
"github.com/fsnotify/fsnotify"
8+
"github.com/mongodb-labs/atlas-cli-plugin-terraform/internal/convert"
9+
"github.com/mongodb-labs/atlas-cli-plugin-terraform/internal/file"
10+
"github.com/spf13/afero"
11+
)
12+
13+
type opts struct {
14+
fs afero.Fs
15+
file string
16+
output string
17+
replaceOutput bool
18+
watch bool
19+
}
20+
21+
func (o *opts) PreRun() error {
22+
if err := file.MustExist(o.fs, o.file); err != nil {
23+
return err
24+
}
25+
if !o.replaceOutput {
26+
return file.MustNotExist(o.fs, o.output)
27+
}
28+
return nil
29+
}
30+
31+
func (o *opts) Run() error {
32+
if err := o.generateFile(false); err != nil {
33+
return err
34+
}
35+
if o.watch {
36+
return o.watchFile()
37+
}
38+
return nil
39+
}
40+
41+
func (o *opts) generateFile(allowParseErrors bool) error {
42+
inConfig, err := afero.ReadFile(o.fs, o.file)
43+
if err != nil {
44+
return fmt.Errorf("failed to read file %s: %w", o.file, err)
45+
}
46+
outConfig, err := convert.AdvancedClusterToNew(inConfig)
47+
if err != nil {
48+
if allowParseErrors {
49+
outConfig = []byte("# CONVERT ERROR: " + err.Error() + "\n\n")
50+
outConfig = append(outConfig, inConfig...)
51+
} else {
52+
return err
53+
}
54+
}
55+
if err := afero.WriteFile(o.fs, o.output, outConfig, 0o600); err != nil {
56+
return fmt.Errorf("failed to write file %s: %w", o.output, err)
57+
}
58+
return nil
59+
}
60+
61+
func (o *opts) watchFile() error {
62+
watcher, err := fsnotify.NewWatcher()
63+
if err != nil {
64+
return nil
65+
}
66+
defer watcher.Close()
67+
if err := watcher.Add(o.file); err != nil {
68+
return err
69+
}
70+
for {
71+
if err := o.waitForFileEvent(watcher); err != nil {
72+
return err
73+
}
74+
}
75+
}
76+
77+
func (o *opts) waitForFileEvent(watcher *fsnotify.Watcher) error {
78+
watcherError := errors.New("watcher has been closed")
79+
select {
80+
case event, ok := <-watcher.Events:
81+
if !ok {
82+
return watcherError
83+
}
84+
if event.Has(fsnotify.Write) {
85+
if err := o.generateFile(true); err != nil {
86+
return err
87+
}
88+
}
89+
case err, ok := <-watcher.Errors:
90+
if !ok {
91+
return watcherError
92+
}
93+
return err
94+
}
95+
return nil
96+
}

internal/convert/adv2new.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package convert
2+
3+
// AdvancedClusterToNew transforms all mongodbatlas_advanced_cluster resource definitions in a
4+
// Terraform configuration file from SDKv2 schema to TPF (Terraform Plugin Framework) schema.
5+
// All other resources and data sources are left untouched.
6+
func AdvancedClusterToNew(config []byte) ([]byte, error) {
7+
return config, nil
8+
}

internal/convert/adv2new_test.go

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
package convert_test
2+
3+
import (
4+
"encoding/json"
5+
"path/filepath"
6+
"strings"
7+
"testing"
8+
9+
"github.com/mongodb-labs/atlas-cli-plugin-terraform/internal/convert"
10+
"github.com/sebdah/goldie/v2"
11+
"github.com/spf13/afero"
12+
"github.com/stretchr/testify/assert"
13+
"github.com/stretchr/testify/require"
14+
)
15+
16+
func TestAdvancedClusterToNew(t *testing.T) {
17+
const (
18+
root = "testdata/adv2new"
19+
inSuffix = ".in.tf"
20+
outSuffix = ".out.tf"
21+
errFilename = "errors.json"
22+
)
23+
fs := afero.NewOsFs()
24+
errMap := make(map[string]string)
25+
errContent, err := afero.ReadFile(fs, filepath.Join(root, errFilename))
26+
require.NoError(t, err)
27+
err = json.Unmarshal(errContent, &errMap)
28+
require.NoError(t, err)
29+
g := goldie.New(t,
30+
goldie.WithFixtureDir(root),
31+
goldie.WithNameSuffix(outSuffix))
32+
pattern := filepath.Join(root, "*"+inSuffix)
33+
inputFiles, err := afero.Glob(fs, pattern)
34+
require.NoError(t, err)
35+
assert.NotEmpty(t, inputFiles)
36+
for _, inputFile := range inputFiles {
37+
testName := strings.TrimSuffix(filepath.Base(inputFile), inSuffix)
38+
t.Run(testName, func(t *testing.T) {
39+
inConfig, err := afero.ReadFile(fs, inputFile)
40+
require.NoError(t, err)
41+
outConfig, err := convert.AdvancedClusterToNew(inConfig)
42+
if err == nil {
43+
g.Assert(t, testName, outConfig)
44+
} else {
45+
errMsg, found := errMap[testName]
46+
assert.True(t, found, "error not found in file %s for test %s, errMsg: %v", errFilename, testName, err)
47+
assert.Contains(t, err.Error(), errMsg)
48+
}
49+
})
50+
}
51+
}
File renamed without changes.
File renamed without changes.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
resource "mongodbatlas_advanced_cluster" "basic" {
2+
name = "basic"
3+
// TODO: missing fields as transformation is not implemented yet
4+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
resource "mongodbatlas_advanced_cluster" "basic" {
2+
name = "basic"
3+
// TODO: missing fields as transformation is not implemented yet
4+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{}

0 commit comments

Comments
 (0)