nginx-org-asg/main.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(&region, "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
}