Skip to content

Instantly share code, notes, and snippets.

@rverma-nikiai
Created June 21, 2019 14:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rverma-nikiai/4b468c9231994caa59e9d7d037295d62 to your computer and use it in GitHub Desktop.
Save rverma-nikiai/4b468c9231994caa59e9d7d037295d62 to your computer and use it in GitHub Desktop.
terrafrom upgrade gist
package main
import (
"context"
"fmt"
"github.com/fako1024/topo"
"github.com/google/go-github/v26/github"
"golang.org/x/oauth2"
"log"
"os"
"os/exec"
"regexp"
"strings"
"time"
)
var client *github.Client
var ctx = context.Background()
const (
token = "github-api-token"
sourceOwner = "rverma-nikiai"
prRepoOwner = "cloudposse"
)
type Repo struct {
name string
url string
owner string
}
var re = regexp.MustCompile(`::([^\[\]]*)\?`)
func getReposInUse() map[string]Repo {
localRepos := make(map[string]Repo)
mods := []string{
"git::https://github.com/cloudposse/terraform-aws-acm-request-certificate.git?ref=master",
"git::https://github.com/cloudposse/terraform-aws-iam-chamber-s3-role.git?ref=master",
"git::https://github.com/cloudposse/terraform-aws-cloudfront-cdn.git?ref=master",
"git::https://github.com/cloudposse/terraform-aws-cloudfront-s3-cdn.git?ref=master",
"git::https://github.com/cloudposse/terraform-aws-cloudtrail-s3-bucket.git?ref=master",
"git::https://github.com/cloudposse/terraform-aws-cloudtrail.git?ref=master",
"git::https://github.com/cloudposse/terraform-aws-dynamic-subnets.git?ref=master",
"git::https://github.com/cloudposse/terraform-aws-dynamodb-autoscaler.git?ref=master",
"git::https://github.com/cloudposse/terraform-aws-dynamodb.git?ref=master",
"git::https://github.com/cloudposse/terraform-aws-elasticache-redis.git?ref=master",
"git::https://github.com/cloudposse/terraform-aws-elasticsearch.git?ref=master",
"git::https://github.com/cloudposse/terraform-aws-iam-account-settings.git?ref=master",
"git::https://github.com/cloudposse/terraform-aws-iam-chamber-user.git?ref=master",
"git::https://github.com/cloudposse/terraform-aws-iam-role.git?ref=master",
"git::https://github.com/cloudposse/terraform-aws-iam-s3-user.git?ref=master",
"git::https://github.com/cloudposse/terraform-aws-iam-system-user.git?ref=master",
"git::https://github.com/cloudposse/terraform-aws-key-pair.git?ref=master",
"git::https://github.com/cloudposse/terraform-aws-kms-key.git?ref=master",
"git::https://github.com/cloudposse/terraform-aws-multi-az-subnets.git?ref=master",
"git::https://github.com/cloudposse/terraform-aws-rds-cluster.git?ref=master",
"git::https://github.com/cloudposse/terraform-aws-route53-alias.git?ref=master",
"git::https://github.com/cloudposse/terraform-aws-route53-cluster-hostname.git?ref=master",
"git::https://github.com/cloudposse/terraform-aws-route53-cluster-zone.git?ref=master",
"git::https://github.com/cloudposse/terraform-aws-s3-bucket.git?ref=master",
"git::https://github.com/cloudposse/terraform-aws-s3-log-storage.git?ref=master",
"git::https://github.com/cloudposse/terraform-aws-s3-website.git?ref=master",
"git::https://github.com/cloudposse/terraform-aws-ses-lambda-forwarder.git?ref=master",
"git::https://github.com/cloudposse/terraform-aws-tfstate-backend.git?ref=master",
"git::https://github.com/cloudposse/terraform-aws-vpc.git?ref=master",
"git::https://github.com/cloudposse/terraform-external-module-artifact.git?ref=master",
"git::https://github.com/cloudposse/terraform-null-label.git?ref=master",
"git::https://github.com/cloudposse/terraform-terraform-label.git?ref=master",
"git::https://github.com/cloudposse/terraform-aws-iam-policy-document-aggregator.git?ref=master",
}
for _, s := range mods {
repo := getRepo(s, prRepoOwner)
localRepos[repo.name] = repo
}
ts := oauth2.StaticTokenSource(&oauth2.Token{AccessToken: token})
tc := oauth2.NewClient(ctx, ts)
client = github.NewClient(tc)
return localRepos
}
func getRepo(element string, owner string) Repo {
moduleUrl := re.FindAllString(element, -1)
repoUrl := strings.Trim(moduleUrl[0], "::")
repoUrl = strings.Trim(repoUrl, "?")
var name = repoUrl[len("https://github.com/"+owner+"/"):]
name = name[:len(name)-4]
return Repo{url: repoUrl, owner: prRepoOwner, name: name}
}
func forkRepoInUse() {
for _, rx := range getReposInUse() {
_, resp2, _ := client.Repositories.Get(ctx, sourceOwner, rx.name)
if resp2.StatusCode >= 300 || resp2.StatusCode < 200 {
fork, resp, _ := client.Repositories.CreateFork(ctx, rx.owner, rx.name, nil)
if resp.StatusCode == 202 {
time.Sleep(100)
log.Printf("forked %s\n", *fork.Name)
}
} else {
log.Printf("repo %s already exists", rx.name)
}
}
}
func syncReposInUse() {
all := getReposInUse()
for _, rx := range all {
target := "/Users/rverma/exp/" + prRepoOwner + "/" + rx.name
if _, err := os.Stat(target); os.IsNotExist(err) {
url := strings.Replace(rx.url, prRepoOwner, sourceOwner, -1)
log.Printf("cloning into %s:%s\n", target, url)
cmd := exec.Command("git", "clone", url, target)
err := cmd.Run()
if err != nil {
log.Fatal(err)
}
} else {
log.Printf("found locally %s\n", target)
}
}
}
func getOrderOfUpgrade() ([]string){
localRepos := []string{
"terraform-aws-acm-request-certificate",
"terraform-aws-cloudfront-cdn",
"terraform-aws-cloudfront-s3-cdn",
"terraform-aws-cloudtrail",
"terraform-aws-cloudtrail-s3-bucket",
"terraform-aws-dynamic-subnets",
"terraform-aws-dynamodb",
"terraform-aws-dynamodb-autoscaler",
"terraform-aws-elasticache-redis",
"terraform-aws-elasticsearch",
"terraform-aws-iam-account-settings",
"terraform-aws-iam-chamber-s3-role",
"terraform-aws-iam-chamber-user",
"terraform-aws-iam-role",
"terraform-aws-iam-s3-user",
"terraform-aws-iam-system-user",
"terraform-aws-key-pair",
"terraform-aws-kms-key",
"terraform-aws-multi-az-subnets",
"terraform-aws-rds-cluster",
"terraform-aws-route53-alias",
"terraform-aws-route53-cluster-hostname",
"terraform-aws-route53-cluster-zone",
"terraform-aws-s3-bucket",
"terraform-aws-s3-log-storage",
"terraform-aws-s3-website",
"terraform-aws-ses-lambda-forwarder",
"terraform-aws-tfstate-backend",
"terraform-aws-vpc",
"terraform-external-module-artifact",
"terraform-null-label",
"terraform-aws-iam-policy-document-aggregator",
}
var stringDependencies []topo.Dependency
for _, rx := range localRepos {
target := "/Users/rverma/exp/" + prRepoOwner + "/" + rx
cmd := exec.Command("bash", "-c", "grep -hr --exclude-dir=examples --include \\*.tf git::https://github.com/rverma . | awk '{ print $3 }'")
cmd.Dir = target
output, err := cmd.CombinedOutput()
if err != nil {
fmt.Println(fmt.Sprint(err) + ": " + string(output))
panic(err.Error())
}
out := string(output)
if out != "" {
childrens := strings.Split(out, "\n")
for _, child := range childrens {
if child != "" {
tmp := getRepo(strings.Trim(child, "\""), sourceOwner).name
if rx != "" && tmp != "" && rx != "null" && tmp != "null"{
stringDependencies = append(stringDependencies, topo.Dependency{Child:rx,Parent:tmp})
}
}
}
}
}
// Getter function to convert original elements to a generic type
getter := func(i int) topo.Type {
return localRepos[i]
}
// Setter function to restore the original type of the data
setter := func(i int, val topo.Type) {
localRepos[i] = val.(string)
}
// Perform topological sort
if err := topo.Sort(localRepos, stringDependencies, getter, setter); err != nil {
fmt.Printf("Error performing topological sort on slice of strings: %s\n", err)
os.Exit(1)
}
return localRepos
}
func upgrade(){
localRepos := []string{
"terraform-aws-acm-request-certificate",
"terraform-null-label",
"terraform-aws-s3-log-storage",
"terraform-aws-route53-alias",
"terraform-aws-cloudfront-cdn",
"terraform-aws-cloudfront-s3-cdn",
"terraform-aws-cloudtrail",
"terraform-aws-cloudtrail-s3-bucket",
"terraform-aws-dynamic-subnets",
"terraform-aws-dynamodb-autoscaler",
"terraform-aws-dynamodb",
"terraform-aws-route53-cluster-hostname",
"terraform-aws-elasticache-redis",
"terraform-aws-elasticsearch",
"terraform-aws-iam-account-settings",
"terraform-aws-iam-system-user",
"terraform-aws-iam-s3-user",
"terraform-aws-s3-bucket",
"terraform-aws-iam-policy-document-aggregator",
"terraform-aws-kms-key",
"terraform-aws-iam-role",
"terraform-aws-iam-chamber-s3-role",
"terraform-aws-iam-chamber-user",
"terraform-aws-key-pair",
"terraform-aws-multi-az-subnets",
"terraform-aws-rds-cluster",
"terraform-aws-route53-cluster-zone",
"terraform-aws-s3-website",
"terraform-external-module-artifact",
"terraform-aws-ses-lambda-forwarder",
"terraform-aws-tfstate-backend",
"terraform-aws-vpc",
}
for _, rx := range localRepos {
target := "/Users/rverma/exp/" + prRepoOwner + "/" + rx
log.Printf("upgrading %s",rx)
cmd := exec.Command("bash", "-c", "if [ -f versions.tf ]; then echo already upgraded; else rm -rf .terraform && terraform init && terraform 0.12upgrade --yes; fi;")
cmd.Dir = target
output, err := cmd.CombinedOutput()
if err != nil {
fmt.Println(fmt.Sprint(err) + ": " + string(output))
panic(err.Error())
}
log.Printf(string(output))
log.Printf("pushing %s",rx)
commit := exec.Command("bash", "-c", "git add -A . && git commit -m \"upgraded-tf\" && git push")
commit.Dir = target
outCommit, err2 := commit.CombinedOutput()
if err != nil {
fmt.Println(fmt.Sprint(err2) + ": " + string(outCommit))
panic(err.Error())
}
log.Printf(string(outCommit))
}
}
func validate(){
localRepos := []string{
"terraform-aws-acm-request-certificate",
"terraform-null-label",
"terraform-aws-s3-log-storage",
"terraform-aws-route53-alias",
"terraform-aws-cloudfront-cdn",
"terraform-aws-cloudfront-s3-cdn",
"terraform-aws-cloudtrail",
"terraform-aws-cloudtrail-s3-bucket",
"terraform-aws-dynamic-subnets",
"terraform-aws-dynamodb-autoscaler",
"terraform-aws-dynamodb",
"terraform-aws-route53-cluster-hostname",
"terraform-aws-elasticache-redis",
"terraform-aws-elasticsearch",
"terraform-aws-iam-account-settings",
"terraform-aws-iam-system-user",
"terraform-aws-iam-s3-user",
"terraform-aws-s3-bucket",
"terraform-aws-iam-policy-document-aggregator",
"terraform-aws-kms-key",
"terraform-aws-iam-role",
"terraform-aws-iam-chamber-s3-role",
"terraform-aws-iam-chamber-user",
"terraform-aws-key-pair",
"terraform-aws-multi-az-subnets",
"terraform-aws-rds-cluster",
"terraform-aws-route53-cluster-zone",
"terraform-aws-s3-website",
"terraform-external-module-artifact",
"terraform-aws-ses-lambda-forwarder",
"terraform-aws-tfstate-backend",
"terraform-aws-vpc",
}
for _, rx := range localRepos {
target := "/Users/rverma/exp/" + prRepoOwner + "/" + rx
log.Printf("validating %s",rx)
//cmd := exec.Command("bash", "-c", "rm -rf .terraform && terraform init")
cmd := exec.Command("bash", "-c", "terraform validate")
cmd.Dir = target
cmd.Env = os.Environ()
cmd.Env = append(cmd.Env, "TF_VAR_region=ap-south-1")
output, err := cmd.CombinedOutput()
if err != nil {
fmt.Println(fmt.Sprint(err) + ": " + string(output))
//panic(err.Error())
}
log.Printf(string(output))
}
}
func createPR() {
localRepos := []string{
//"terraform-null-label",
"terraform-aws-s3-log-storage",
"terraform-aws-route53-alias",
"terraform-aws-cloudfront-cdn",
"terraform-aws-cloudfront-s3-cdn",
"terraform-aws-cloudtrail",
"terraform-aws-cloudtrail-s3-bucket",
"terraform-aws-dynamic-subnets",
"terraform-aws-dynamodb-autoscaler",
"terraform-aws-dynamodb",
"terraform-aws-route53-cluster-hostname",
"terraform-aws-elasticache-redis",
"terraform-aws-elasticsearch",
"terraform-aws-iam-account-settings",
"terraform-aws-iam-system-user",
"terraform-aws-iam-s3-user",
"terraform-aws-s3-bucket",
"terraform-aws-iam-policy-document-aggregator",
"terraform-aws-kms-key",
"terraform-aws-iam-role",
"terraform-aws-iam-chamber-s3-role",
"terraform-aws-iam-chamber-user",
"terraform-aws-key-pair",
"terraform-aws-multi-az-subnets",
"terraform-aws-rds-cluster",
"terraform-aws-route53-cluster-zone",
"terraform-aws-s3-website",
"terraform-external-module-artifact",
"terraform-aws-ses-lambda-forwarder",
"terraform-aws-tfstate-backend",
"terraform-aws-vpc",
}
queue := make(chan string, len(localRepos))
for _,x := range localRepos {
queue <- x
}
close(queue)
for prRepo := range queue {
target := "/Users/rverma/exp/" + prRepoOwner + "/" + prRepo
ss := exec.Command("bash","-c", "hub pull-request -m \"upgrade 0.12\" -b \"cloudposse:master\" -h \"rverma-nikiai:master\"")
ss.Dir = target
output, err := ss.CombinedOutput()
if err != nil {
fmt.Println(fmt.Sprint(err) + ": " + string(output))
panic(err.Error())
}
log.Printf(string(output))
}
}
func main() {
//forkRepoInUse()
//syncReposInUse()
//fmt.Printf(strings.Join(getOrderOfUpgrade(),"\n"))
//upgrade()
//validate()
createPR()
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment