170 lines
4.6 KiB
Go
170 lines
4.6 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"flag"
|
|
"log"
|
|
"os"
|
|
"os/signal"
|
|
"reflect"
|
|
"sort"
|
|
"sync"
|
|
"syscall"
|
|
"text/template"
|
|
"time"
|
|
|
|
"github.com/dtchanpura/nginx-org-asg/awsasg"
|
|
"github.com/dtchanpura/nginx-org-asg/models"
|
|
"github.com/dtchanpura/nginx-org-asg/utils"
|
|
)
|
|
|
|
var (
|
|
profile string
|
|
region string
|
|
asg string
|
|
referenceFile string
|
|
outputFile string
|
|
format string
|
|
period models.Interval
|
|
tmpl *template.Template
|
|
err error
|
|
quit chan os.Signal
|
|
hook string
|
|
debug bool
|
|
ticker *time.Ticker
|
|
logger *log.Logger
|
|
)
|
|
|
|
func init() {
|
|
logger = log.New(os.Stdout, "nginx-org-asg: ", log.Lshortfile|log.Ltime|log.Ldate)
|
|
flag.StringVar(&profile, "profile", "default", "Profile to use for from ~/.aws/credentials")
|
|
flag.StringVar(®ion, "region", "us-east-1", "AWS Region")
|
|
flag.StringVar(&asg, "asg", "autoscaling-group", "Autoscaling Group name to be matched")
|
|
flag.StringVar(&outputFile, "out", "~/output.txt", "Output file for extracting IP addresses")
|
|
flag.StringVar(&referenceFile, "ref", "~/reference.json", "Output file for reference of IP addresses")
|
|
flag.StringVar(&format, "format", "{{.PrivateIPAddress}}:8080;", "Format to print out with.")
|
|
flag.StringVar(&hook, "hook", "echo", "Executable Hook path")
|
|
flag.BoolVar(&debug, "debug", false, "Debug output.")
|
|
flag.Var(&period, "period", "Period to repeat it at")
|
|
flag.Parse()
|
|
tmpl, err = template.New("instances").Parse("{{range .}}" + format + "\n{{end}}")
|
|
if err != nil {
|
|
logger.Fatal("Problem parsing template", err)
|
|
}
|
|
|
|
}
|
|
|
|
func main() {
|
|
quit = make(chan os.Signal, 1)
|
|
signal.Notify(quit, syscall.SIGTERM)
|
|
signal.Notify(quit, syscall.SIGINT)
|
|
|
|
existingInstances := fetchInstancesFromFile()
|
|
|
|
if period.Duration > 0 {
|
|
ticker = time.NewTicker(period.Duration)
|
|
} else {
|
|
ticker = time.NewTicker(30 * time.Second)
|
|
}
|
|
var mutex = &sync.Mutex{}
|
|
//
|
|
for {
|
|
select {
|
|
case <-ticker.C:
|
|
mutex.Lock()
|
|
existingInstances = checkChange(existingInstances)
|
|
if debug {
|
|
logger.Printf("[DEBUG] Instances: %d\n", len(existingInstances))
|
|
}
|
|
mutex.Unlock()
|
|
case <-quit:
|
|
logger.Println("Quitting application...")
|
|
ticker.Stop()
|
|
return
|
|
// break loop
|
|
}
|
|
}
|
|
// ticker part
|
|
}
|
|
func checkChange(existingInstances []models.Instance) []models.Instance {
|
|
newInstances := fetchInstancesFromAWS()
|
|
if !reflect.DeepEqual(existingInstances, newInstances) {
|
|
err := utils.TruncateFile(outputFile)
|
|
if err != nil {
|
|
logger.Println("Problem with truncating output file", err)
|
|
return existingInstances
|
|
}
|
|
|
|
// Update outputFile with latest changes
|
|
of, err := os.OpenFile(outputFile, os.O_CREATE|os.O_WRONLY, 0644)
|
|
if err != nil {
|
|
logger.Println("Problem with file", err)
|
|
return existingInstances
|
|
}
|
|
defer of.Close()
|
|
err = tmpl.Execute(of, newInstances)
|
|
if err != nil {
|
|
logger.Println("Problem executing template", err)
|
|
return existingInstances
|
|
}
|
|
|
|
// Update referenceFile for consistency
|
|
err = utils.TruncateFile(referenceFile)
|
|
if err != nil {
|
|
logger.Println("Problem with truncating reference file", err)
|
|
return existingInstances
|
|
}
|
|
|
|
rf, err := os.OpenFile(referenceFile, os.O_CREATE|os.O_WRONLY, 0644)
|
|
if err != nil {
|
|
logger.Println("Problem with file", err)
|
|
return existingInstances
|
|
}
|
|
defer rf.Close()
|
|
encoder := json.NewEncoder(rf)
|
|
encoder.Encode(newInstances)
|
|
if err != nil {
|
|
logger.Println("Problem executing template", err)
|
|
return existingInstances
|
|
}
|
|
existingInstances = make([]models.Instance, len(newInstances))
|
|
copy(existingInstances, newInstances)
|
|
// Run Hooks
|
|
err = utils.ExecuteScript(".", "/Users/darshil/Projects/go/src/github.com/dtchanpura/nginx-org-asg/test.sh")
|
|
if err != nil {
|
|
logger.Println(err)
|
|
}
|
|
}
|
|
return existingInstances
|
|
}
|
|
|
|
func fetchInstancesFromFile() []models.Instance {
|
|
ref, err := os.OpenFile(referenceFile, os.O_CREATE|os.O_RDWR, 0644)
|
|
var instances []models.Instance
|
|
if err != nil {
|
|
logger.Println("Problem in opening file", err)
|
|
}
|
|
defer ref.Close()
|
|
// Get current instances from referenceFile
|
|
instances, err = utils.GetInstances(ref)
|
|
if err != nil {
|
|
logger.Println("Problem in getting instances", err)
|
|
return []models.Instance{}
|
|
}
|
|
// sort the instances by their IP
|
|
sort.Sort(models.ByIP(instances))
|
|
return instances
|
|
}
|
|
|
|
// fetchInstancesFromAWS fetches the instances from AWS API
|
|
func fetchInstancesFromAWS() []models.Instance {
|
|
instances, err := awsasg.Run(region, profile, asg)
|
|
if err != nil {
|
|
logger.Println("Problem in awsasg.Run", err)
|
|
return []models.Instance{}
|
|
}
|
|
// sort the instances by their IP
|
|
sort.Sort(models.ByIP(instances))
|
|
return instances
|
|
}
|