commit c597c6d65f45cdf175a8ff72767851bcf41ba249 Author: anoop narang Date: Mon Jan 13 18:49:36 2020 +0530 [ch2531] | [Anoop] | Init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..331c58f --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.idea +vendor \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..b2f1b08 --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# infra-provisioner +This tool provisions infra resources like rds, s3 on demand with details given in `infra_manifest`. +Simply explained, its a thin wrapper over terraform to hide the complexities like hcl, remote backend, targeted resources etc when provisioning resources. diff --git a/bindata.go b/bindata.go new file mode 100644 index 0000000..0084181 --- /dev/null +++ b/bindata.go @@ -0,0 +1,334 @@ +// Code generated by go-bindata. DO NOT EDIT. +// sources: +// templates/rds-tf/deploy.sh +// templates/rds-tf/main.tf + +package main + + +import ( + "bytes" + "compress/gzip" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + "time" +) + +func bindataRead(data []byte, name string) ([]byte, error) { + gz, err := gzip.NewReader(bytes.NewBuffer(data)) + if err != nil { + return nil, fmt.Errorf("Read %q: %v", name, err) + } + + var buf bytes.Buffer + _, err = io.Copy(&buf, gz) + clErr := gz.Close() + + if err != nil { + return nil, fmt.Errorf("Read %q: %v", name, err) + } + if clErr != nil { + return nil, err + } + + return buf.Bytes(), nil +} + + +type asset struct { + bytes []byte + info fileInfoEx +} + +type fileInfoEx interface { + os.FileInfo + MD5Checksum() string +} + +type bindataFileInfo struct { + name string + size int64 + mode os.FileMode + modTime time.Time + md5checksum string +} + +func (fi bindataFileInfo) Name() string { + return fi.name +} +func (fi bindataFileInfo) Size() int64 { + return fi.size +} +func (fi bindataFileInfo) Mode() os.FileMode { + return fi.mode +} +func (fi bindataFileInfo) ModTime() time.Time { + return fi.modTime +} +func (fi bindataFileInfo) MD5Checksum() string { + return fi.md5checksum +} +func (fi bindataFileInfo) IsDir() bool { + return false +} +func (fi bindataFileInfo) Sys() interface{} { + return nil +} + +var _bindataTemplatesRdstfDeploysh = []byte( + "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x9c\xcc\x4b\x8e\xc2\x30\x0c\x80\xe1\xfd\x9c\xc2\xa3\x59\x37\x3d\xc1\x9c" + + "\x83\x65\xe4\x26\xa6\x44\x34\x89\x65\xbb\xad\x50\xdb\xbb\xb3\x41\x50\x01\x0b\xc4\xce\x8f\x5f\xdf\xdf\x6f\xdb\xa5" + + "\xd2\xea\xe9\xc7\x48\x04\x8f\x55\x32\xa4\x92\x6c\xb7\xce\x55\xce\xca\x18\x08\x94\x06\x0a\x06\xcb\x02\xee\x70\x3f" + + "\x6e\x1b\xac\x2b\xbc\xcb\x0b\xcd\x2f\xed\xce\x45\xe6\xe1\x02\x8d\xa1\xf4\x64\xff\xb9\xc6\x71\x20\x27\x51\x5d\x44" + + "\x43\x87\xb3\x7a\x1d\xbb\x42\xe6\x53\x54\x17\x6a\xce\x58\xa2\x67\x49\x13\x1a\xdd\x5e\x0a\x0d\x8e\x56\x1b\x64\x96" + + "\x3a\xd1\x27\xf8\x63\xf4\xa9\xa8\x61\x09\xf4\x35\xc2\x55\xad\x17\x52\x1f\xbb\x27\xe3\x1a\x00\x00\xff\xff\xb9\x7c" + + "\xda\xf4\x57\x01\x00\x00") + +func bindataTemplatesRdstfDeployshBytes() ([]byte, error) { + return bindataRead( + _bindataTemplatesRdstfDeploysh, + "templates/rds-tf/deploy.sh", + ) +} + + + +func bindataTemplatesRdstfDeploysh() (*asset, error) { + bytes, err := bindataTemplatesRdstfDeployshBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{ + name: "templates/rds-tf/deploy.sh", + size: 343, + md5checksum: "", + mode: os.FileMode(420), + modTime: time.Unix(1578918947, 0), + } + + a := &asset{bytes: bytes, info: info} + + return a, nil +} + +var _bindataTemplatesRdstfMaintf = []byte( + "\x1f\x8b\x08\x00\x00\x00\x00\x00\x00\xff\x94\x53\x4d\x8f\x9b\x30\x10\xbd\xf3\x2b\xac\xdc\x0d\xaa\x7a\x8b\xb4\x52" + + "\xab\x76\x5b\x6d\x0f\xd5\xaa\x5f\x57\x64\xec\x81\x58\xd8\x63\xe2\x31\xa1\x59\x96\xff\x5e\x81\x21\x0b\x65\x7b\xa8" + + "\x6f\x79\x79\x1f\xf3\x9e\x44\x00\xef\x45\xe9\xbc\x65\x7d\xc2\x58\x21\x64\x0d\xa8\xd8\x81\xde\x1e\x26\x80\xb1\xa2" + + "\x95\x35\x04\xb6\x7d\x77\xec\x80\xe2\xa2\x79\x21\xb0\xe6\x37\x0b\x2e\x9d\xb5\x02\x15\xa7\x20\x02\x1c\x26\xb9\x87" + + "\x4a\x3b\xdc\xcb\x45\xc3\xc9\xb5\xe1\xc4\xdf\x44\x5e\x0d\x57\xb6\x7b\x77\xec\xe0\x15\x45\x42\xe7\x7c\x4d\x8d\x90" + + "\x90\xd7\x70\xcd\x1b\x0f\xa5\xfe\x3d\x13\x62\x1e\x65\x7d\xcf\xd2\x6f\x8a\xd2\x07\xa4\x20\x50\xc2\x57\x61\x81\x0d" + + "\x43\xd4\x37\xde\x95\xda\xc0\x2e\x40\x5a\x15\x09\x42\x9a\x57\x2f\x88\x03\x70\xd7\x21\x78\x5e\xb6\xc6\x70\xe9\x30" + + "\x78\x67\x46\xd9\x90\x0c\x49\x62\x9d\x6a\x0d\xc4\x5b\xa7\xd5\xc8\xb5\x5e\xc2\xca\xa3\xd2\xe1\x78\x24\x3a\x1d\xb3" + + "\xac\xd2\xe1\x5d\xa5\xc3\xa9\x2d\x52\x69\x55\x3a\xcd\x18\x40\x9e\x52\x8d\xd9\xf4\x43\x63\xe9\x45\xe6\x15\xa5\x95" + + "\x0e\x63\x06\xe0\x45\x7b\x87\x16\x30\x4c\x6e\x63\xcd\xfb\x15\xf6\xcc\xce\xad\x0b\x63\xd3\x84\x31\x3d\x77\xcf\x71" + + "\x2c\x1f\xc9\xbb\x4d\x36\x8a\x46\x10\x75\xce\xab\xe5\xd8\x45\xf1\xb8\xe0\x1b\x36\xe9\x27\x58\xcf\xb3\xb0\xbf\xeb" + + "\x27\x78\xc0\xcf\x45\x64\xb5\x04\xfe\x35\xd6\xcf\x11\x5f\xf9\x25\x8c\x29\x11\x44\x21\x08\xe8\x2f\xea\xc7\x1b\xfe" + + "\xcc\x6c\x4b\xe1\x87\xfb\x42\x0e\x67\x51\xdf\x73\xa6\xcb\x48\x7c\xdf\xd1\x52\xee\x83\x11\x44\xf1\x02\xd1\x51\x7e" + + "\xdb\x42\x4e\xf8\x8b\xf7\x4e\xb2\xa9\x38\x9a\x8f\x1f\xc1\x3e\xea\x91\xce\xe6\x93\xb0\xda\x5c\xe7\xe9\xe8\x6c\xf2" + + "\x32\x02\xab\xe1\x5e\x58\xff\xe1\x7b\x8f\x95\x46\xf8\x05\x9e\x74\xac\x39\xdb\xc3\x84\xe7\x97\xf9\x8f\x6d\xcc\x56" + + "\xf4\xaf\xb4\x21\xf9\x13\x00\x00\xff\xff\x5e\x09\x8e\x45\xe6\x03\x00\x00") + +func bindataTemplatesRdstfMaintfBytes() ([]byte, error) { + return bindataRead( + _bindataTemplatesRdstfMaintf, + "templates/rds-tf/main.tf", + ) +} + + + +func bindataTemplatesRdstfMaintf() (*asset, error) { + bytes, err := bindataTemplatesRdstfMaintfBytes() + if err != nil { + return nil, err + } + + info := bindataFileInfo{ + name: "templates/rds-tf/main.tf", + size: 998, + md5checksum: "", + mode: os.FileMode(420), + modTime: time.Unix(1578901238, 0), + } + + a := &asset{bytes: bytes, info: info} + + return a, nil +} + + +// +// Asset loads and returns the asset for the given name. +// It returns an error if the asset could not be found or +// could not be loaded. +// +func Asset(name string) ([]byte, error) { + cannonicalName := strings.Replace(name, "\\", "/", -1) + if f, ok := _bindata[cannonicalName]; ok { + a, err := f() + if err != nil { + return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err) + } + return a.bytes, nil + } + return nil, &os.PathError{Op: "open", Path: name, Err: os.ErrNotExist} +} + +// +// MustAsset is like Asset but panics when Asset would return an error. +// It simplifies safe initialization of global variables. +// nolint: deadcode +// +func MustAsset(name string) []byte { + a, err := Asset(name) + if err != nil { + panic("asset: Asset(" + name + "): " + err.Error()) + } + + return a +} + +// +// AssetInfo loads and returns the asset info for the given name. +// It returns an error if the asset could not be found or could not be loaded. +// +func AssetInfo(name string) (os.FileInfo, error) { + cannonicalName := strings.Replace(name, "\\", "/", -1) + if f, ok := _bindata[cannonicalName]; ok { + a, err := f() + if err != nil { + return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err) + } + return a.info, nil + } + return nil, &os.PathError{Op: "open", Path: name, Err: os.ErrNotExist} +} + +// +// AssetNames returns the names of the assets. +// nolint: deadcode +// +func AssetNames() []string { + names := make([]string, 0, len(_bindata)) + for name := range _bindata { + names = append(names, name) + } + return names +} + +// +// _bindata is a table, holding each asset generator, mapped to its name. +// +var _bindata = map[string]func() (*asset, error){ + "templates/rds-tf/deploy.sh": bindataTemplatesRdstfDeploysh, + "templates/rds-tf/main.tf": bindataTemplatesRdstfMaintf, +} + +// +// AssetDir returns the file names below a certain +// directory embedded in the file by go-bindata. +// For example if you run go-bindata on data/... and data contains the +// following hierarchy: +// data/ +// foo.txt +// img/ +// a.png +// b.png +// then AssetDir("data") would return []string{"foo.txt", "img"} +// AssetDir("data/img") would return []string{"a.png", "b.png"} +// AssetDir("foo.txt") and AssetDir("notexist") would return an error +// AssetDir("") will return []string{"data"}. +// +func AssetDir(name string) ([]string, error) { + node := _bintree + if len(name) != 0 { + cannonicalName := strings.Replace(name, "\\", "/", -1) + pathList := strings.Split(cannonicalName, "/") + for _, p := range pathList { + node = node.Children[p] + if node == nil { + return nil, &os.PathError{ + Op: "open", + Path: name, + Err: os.ErrNotExist, + } + } + } + } + if node.Func != nil { + return nil, &os.PathError{ + Op: "open", + Path: name, + Err: os.ErrNotExist, + } + } + rv := make([]string, 0, len(node.Children)) + for childName := range node.Children { + rv = append(rv, childName) + } + return rv, nil +} + + +type bintree struct { + Func func() (*asset, error) + Children map[string]*bintree +} + +var _bintree = &bintree{Func: nil, Children: map[string]*bintree{ + "templates": {Func: nil, Children: map[string]*bintree{ + "rds-tf": {Func: nil, Children: map[string]*bintree{ + "deploy.sh": {Func: bindataTemplatesRdstfDeploysh, Children: map[string]*bintree{}}, + "main.tf": {Func: bindataTemplatesRdstfMaintf, Children: map[string]*bintree{}}, + }}, + }}, +}} + +// RestoreAsset restores an asset under the given directory +func RestoreAsset(dir, name string) error { + data, err := Asset(name) + if err != nil { + return err + } + info, err := AssetInfo(name) + if err != nil { + return err + } + err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755)) + if err != nil { + return err + } + err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode()) + if err != nil { + return err + } + return os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime()) +} + +// RestoreAssets restores an asset under the given directory recursively +func RestoreAssets(dir, name string) error { + children, err := AssetDir(name) + // File + if err != nil { + return RestoreAsset(dir, name) + } + // Dir + for _, child := range children { + err = RestoreAssets(dir, filepath.Join(name, child)) + if err != nil { + return err + } + } + return nil +} + +func _filePath(dir, name string) string { + cannonicalName := strings.Replace(name, "\\", "/", -1) + return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...) +} diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..65d78b8 --- /dev/null +++ b/go.mod @@ -0,0 +1,11 @@ +module github.cmd.navi-tech.in/navi-infra/infra-provisioner + +go 1.13 + +require ( + github.com/Masterminds/sprig/v3 v3.0.2 + github.com/huandu/xstrings v1.2.1 // indirect + github.com/imdario/mergo v0.3.8 // indirect + github.com/urfave/cli/v2 v2.1.1 + golang.org/x/crypto v0.0.0-20200109152110-61a87790db17 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..baebd92 --- /dev/null +++ b/go.sum @@ -0,0 +1,51 @@ +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/Masterminds/goutils v1.1.0 h1:zukEsf/1JZwCMgHiK3GZftabmxiCw4apj3a28RPBiVg= +github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= +github.com/Masterminds/semver/v3 v3.0.3 h1:znjIyLfpXEDQjOIEWh+ehwpTU14UzUPub3c3sm36u14= +github.com/Masterminds/semver/v3 v3.0.3/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= +github.com/Masterminds/sprig/v3 v3.0.2 h1:wz22D0CiSctrliXiI9ZO3HoNApweeRGftyDN+BQa3B8= +github.com/Masterminds/sprig/v3 v3.0.2/go.mod h1:oesJ8kPONMONaZgtiHNzUShJbksypC5kWczhZAf6+aU= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d h1:U+s90UTSYgptZMwQh2aRr3LuazLJIa+Pg3Kc1ylSYVY= +github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY= +github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/huandu/xstrings v1.2.0/go.mod h1:DvyZB1rfVYsBIigL8HwpZgxHwXozlTgGqn63UyNX5k4= +github.com/huandu/xstrings v1.2.1 h1:v6IdmkCnDhJG/S0ivr58PeIfg+tyhqQYy4YsCsQ0Pdc= +github.com/huandu/xstrings v1.2.1/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= +github.com/imdario/mergo v0.3.7/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/imdario/mergo v0.3.8 h1:CGgOkSJeqMRmt0D9XLWExdT4m4F1vd3FV3VPt+0VxkQ= +github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= +github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= +github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= +github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q= +github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo= +github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= +github.com/spf13/cast v1.3.0 h1:oget//CVOEoFewqQxwr0Ej5yjygnqGkvggSE/gB35Q8= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/urfave/cli/v2 v2.1.1 h1:Qt8FeAtxE/vfdrLmR3rxR6JRE0RoVmbXu8+6kZtYU4k= +github.com/urfave/cli/v2 v2.1.1/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200109152110-61a87790db17 h1:nVJ3guKA9qdkEQ3TUdXI9QSINo2CUPM/cySEvw2w8I0= +golang.org/x/crypto v0.0.0-20200109152110-61a87790db17/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/main.go b/main.go new file mode 100644 index 0000000..e8d7acc --- /dev/null +++ b/main.go @@ -0,0 +1,64 @@ +package main + +import ( + "os" + "github.com/urfave/cli/v2" + "log" + "io/ioutil" + "encoding/json" +) + +func init() { + log.SetFlags(log.LstdFlags | log.Lshortfile) +} + +func parseManifest(manifestPath string) (*Manifest, error) { + manifestContent, err := ioutil.ReadFile(manifestPath) + if(err != nil) { + log.Fatalf("\nErr: %v", err) + return nil, err + } + var manifest Manifest + json.Unmarshal(manifestContent, &manifest) + manifest.Infra.Workspace = workspaceMap[manifest.Infra.Environment] + return &manifest, nil +} + +func main() { + app := &cli.App{ + Name: "infra-provisioner", + Version: "0.0.1", + + //Common flags for all subcommands + Flags: []cli.Flag { + &cli.StringFlag{ + Name: "manifest", + Usage: "Path of the manifest file", + Aliases: []string{"m"}, + Required: true, + }, + }, + + Commands: []*cli.Command{ + { + Name: "rds", + Usage: "Provision rds instance", + Action: func(c *cli.Context) error { + manifest, err := parseManifest(c.String("manifest")) + if(err != nil) { + log.Fatalf("\nErr: %v", err) + return err + } + err = provisionResource("rds", "rds-tf", manifest) + if err != nil { + log.Fatalf("\nErr: %v", err) + return err + } + return nil + }, + }, + }, + } + + app.Run(os.Args) +} diff --git a/resource.go b/resource.go new file mode 100644 index 0000000..2437bf2 --- /dev/null +++ b/resource.go @@ -0,0 +1,71 @@ +package main + +import ( + "strings" + "github.com/Masterminds/sprig/v3" + "text/template" + "os" + "os/exec" + "log" +) + +const TEMPLATES_DIR = "templates" +const INIT_SCRIPT = "./deploy.sh" + +func provisionResource(resourceName, resourceDir string, manifest *Manifest) error { + err := templateResourceTf(resourceName, resourceDir, manifest) + if(err != nil) { + log.Fatalf("\nErr: %v", err) + return err + } + + + err = executeResourceTf(resourceDir) + if(err != nil) { + log.Fatalf("\nErr: %v", err) + return err + } + + return nil +} + + +func templateResourceTf(templateName, resourceDir string, manifest *Manifest) error { + + tfFiles, err := AssetDir(strings.Join([]string{TEMPLATES_DIR, resourceDir}, "/")) + if err != nil { + return err + } + + for _, tfFile := range tfFiles { + tfBytes := MustAsset(strings.Join([]string{TEMPLATES_DIR, resourceDir, tfFile}, "/")) + t := template.Must(template.New(templateName).Funcs(sprig.TxtFuncMap()).Parse(string(tfBytes))) + + tfOut, err := createFile(resourceDir, tfFile) + if(err != nil) { + log.Fatalf("\nErr: %v", err) + return err + } + + err = t.Execute(tfOut, manifest.Infra) + if(err != nil) { + log.Fatalf("\nErr: %v", err) + return err + } + } + + return nil +} + +func executeResourceTf(resourceDir string) error { + cmd := exec.Command(INIT_SCRIPT) + cmd.Dir = resourceDir + cmd.Stdout = os.Stdout + cmd.Stderr = os.Stderr + err := cmd.Run() + if(err != nil) { + log.Fatalf("\nErr: %v", err) + return err + } + return err +} diff --git a/sample_infra_manifest.json b/sample_infra_manifest.json new file mode 100644 index 0000000..1960b7e --- /dev/null +++ b/sample_infra_manifest.json @@ -0,0 +1,12 @@ +{ + "infra": { + "environment": "prod", + "rds": { + "instanceName": "auth-service", + "user": "auth_service_user", + "password": "auth_service_password", + "sizeInGb": 7, + "databases": ["auth_service"] + } + } +} diff --git a/templates/rds-tf/deploy.sh b/templates/rds-tf/deploy.sh new file mode 100644 index 0000000..8bfd697 --- /dev/null +++ b/templates/rds-tf/deploy.sh @@ -0,0 +1,6 @@ +#!/bin/sh +terraform init +terraform workspace select {{ .Workspace }} || terraform workspace new {{ .Workspace }} +terraform apply -target=module.rds.data.aws_subnet_ids.command_private_subnets -auto-approve +terraform apply -target=module.rds.module.rds_instance -auto-approve +terraform apply -target=module.rds.module.postgres_db -auto-approve diff --git a/templates/rds-tf/main.tf b/templates/rds-tf/main.tf new file mode 100644 index 0000000..53fcff1 --- /dev/null +++ b/templates/rds-tf/main.tf @@ -0,0 +1,33 @@ +terraform { + backend "s3" { + bucket = "navi-bank-terraform-command-state" + region = "ap-south-1" + key = "rds" + workspace_key_prefix = "rds-states/{{ .Rds.InstanceName }}" + profile = "cmd" + acl = "bucket-owner-full-control" + } +} + +module "rds" { + source = "git::ssh://git@github.cmd.navi-tech.in/navi-infra/rds.git" + environment = {{ .Environment | quote }} + instance_name = {{ .Rds.InstanceName | quote }} + password = {{ .Rds.Password | quote }} + size = {{ .Rds.SizeInGb }} + user = {{ .Rds.User | quote }} + + databases = {{ .Rds.Databases | mustToJson }} + + {{- if .Rds.AwsInstanceClass }} + aws_instance_class = {{ .Rds.AwsInstanceClass | quote }} + {{- end }} + + {{- if .Rds.PsqlFamily }} + psql_family = {{ .Rds.PsqlFamily | quote }} + {{- end }} + + {{- if .Rds.PsqlEngineVersion }} + psql_engine_version = {{ .Rds.PsqlEngineVersion | quote }} + {{- end }} +} diff --git a/types.go b/types.go new file mode 100644 index 0000000..ec94f4e --- /dev/null +++ b/types.go @@ -0,0 +1,28 @@ +package main + +var workspaceMap = map[string]string { + "prod": "aps1.prod.navi-tech.in", +} + +type Manifest struct { + Infra Infra `json:"infra"` +} + +type Infra struct { + Environment string `json:"environment"` + Workspace string + Rds Rds `json:"rds"` +} + +//We provide defaults in respective terraforms instead of here to keep all values at one place +type Rds struct { + AwsInstanceClass string `json:"awsInstanceClass"` + PsqlFamily string `json:"psqlFamily"` + PsqlEngineVersion string `json:"psqlEngineVersion"` + User string `json:"user"` + Password string `json:"password"` + SizeInGb int `json:"sizeInGb"` + Databases []string `json:"databases"` + InstanceName string `json:"instanceName"` +} + diff --git a/util.go b/util.go new file mode 100644 index 0000000..88cfe1e --- /dev/null +++ b/util.go @@ -0,0 +1,24 @@ +package main +import ( + "os" + "strings" + "log" +) + +func createFile(dir, fileName string) (*os.File, error) { + err := os.MkdirAll(dir, os.ModePerm) + if(err != nil) { + log.Fatalf("\nErr: %v", err) + return nil, err + } + + filePath := strings.Join([]string{dir, fileName}, "/") + file, err := os.Create(filePath) + if(err != nil) { + log.Fatalf("\nErr: %v", err) + return nil, err + } + + os.Chmod(filePath, os.ModePerm) + return file, err +}