From aa828fe5b285124ea6624b3171c1507e162f1322 Mon Sep 17 00:00:00 2001 From: Jay Date: Mon, 22 Jan 2018 17:48:49 +0800 Subject: [PATCH] add domain zone and record get / update --- .gitignore | 1 + config.default.yml | 4 + main.go | 225 ++++++++++++++++++++++++++++++++++++++++++++- modules/setting.go | 49 ++++++++++ 4 files changed, 277 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 config.default.yml create mode 100644 modules/setting.go diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1d3ed4c --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +config.yml diff --git a/config.default.yml b/config.default.yml new file mode 100644 index 0000000..6531bbc --- /dev/null +++ b/config.default.yml @@ -0,0 +1,4 @@ +domains: + - name: domain.name + subdomain: + - subbname \ No newline at end of file diff --git a/main.go b/main.go index 83f5c1a..7b78a9f 100644 --- a/main.go +++ b/main.go @@ -1,5 +1,226 @@ package main -func main() { - println("Hello") +import ( + "flag" + "fmt" + "io/ioutil" + "log" + "net/http" + "regexp" + "time" + + "git.trj.tw/golang/go-aws-dns/modules" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/route53" +) + +var ( + r53 *route53.Route53 + config *setting.Config + confpath string + domains []*Domains + ip string +) + +func init() { + println("init") + flag.StringVar(&confpath, "config", "", "config file path (default pwd/config.yml)") + flag.StringVar(&confpath, "f", "", "config file path (short)(default pwd/config.yml)") + flag.Parse() +} + +type Domains struct { + Name string + Zone *route53.HostedZone + Sub []string +} + +func main() { + newR53() + config = setting.LoadConfig(confpath) + fmt.Println(config) + ip = getMyIP() + if ok, err := checkIP(ip); err != nil || !ok { + println("ip check fail") + checkErr(err) + } + println(ip) + mainLoc := make(chan bool) + + var tmp []string + for _, it := range config.Domains { + domains = append(domains, &Domains{ + Name: it.Name, + Sub: it.Sub, + }) + name := it.Name + if name[len(name)-1:] != "." { + name += "." + } + tmp = append(tmp, name) + } + + zones, err := getZones(tmp) + checkErr(err) + + for _, it := range domains { + for _, it2 := range zones { + tmp := *it2.Name + if tmp[len(tmp)-1:] == "." { + tmp = tmp[0 : len(tmp)-1] + } + if it.Name == tmp { + it.Zone = it2 + } + } + } + + fmt.Println(domains[0]) + + go func() { + for { + for _, it := range domains { + it.updateRecord() + } + + time.Sleep(time.Duration.Minutes * 5) + } + }() + + <-mainLoc +} + +func newR53() { + sess, err := session.NewSession(&aws.Config{ + Region: aws.String("us-east-2"), + Credentials: credentials.NewSharedCredentials("", "mtfos"), + }) + + checkErr(err) + + r53 = route53.New(sess) +} + +func checkIP(ip string) (bool, error) { + if len(ip) == 0 { + return false, nil + } + if ok, err := regexp.MatchString("^(\\d){1,3}\\.(\\d){1,3}\\.(\\d){1,3}\\.(\\d){1,3}$", ip); err != nil || !ok { + return false, err + } + + return true, nil +} + +func getMyIP() string { + res, err := http.Get("http://ipv4.trj.tw/") + checkErr(err) + defer res.Body.Close() + + if res.StatusCode != 200 { + return "" + } + + body, err := ioutil.ReadAll(res.Body) + checkErr(err) + return string(body) +} + +func (it *Domains) updateRecord() { + if len(it.Sub) == 0 { + return + } + listInput := &route53.ListResourceRecordSetsInput{ + HostedZoneId: it.Zone.Id, + } + ls, err := r53.ListResourceRecordSets(listInput) + checkErr(err) + var chs []*route53.Change + + for _, item := range ls.ResourceRecordSets { + for _, item2 := range it.Sub { + tmp := item2 + "." + it.Name + if tmp[len(tmp)-1:] != "." { + tmp += "." + } + if *item.Name == tmp { + if *item.Type == "A" && *item.ResourceRecords[0].Value != ip { + item.ResourceRecords[0].Value = aws.String(ip) + chs = append(chs, &route53.Change{ + ResourceRecordSet: item, + Action: aws.String("UPSERT"), + }) + } + } + } + } + + if len(chs) == 0 { + return + } + + changeInput := &route53.ChangeResourceRecordSetsInput{ + HostedZoneId: it.Zone.Id, + ChangeBatch: &route53.ChangeBatch{ + Changes: chs, + }, + } + _, err = r53.ChangeResourceRecordSets(changeInput) + checkErr(err) +} + +func getZones(names []string) (zones []*route53.HostedZone, err error) { + if len(names) == 0 { + return + } + + input := &route53.ListHostedZonesInput{} + list, err := r53.ListHostedZones(input) + if err != nil { + return + } + + for _, item := range list.HostedZones { + for _, name := range names { + if name == *item.Name { + zones = append(zones, item) + } + } + } + + return +} + +func getRecords(id *string, names []string) (records []*route53.ResourceRecordSet, err error) { + if len(names) == 0 { + return + } + + input := &route53.ListResourceRecordSetsInput{ + HostedZoneId: id, + } + + list, err := r53.ListResourceRecordSets(input) + if err != nil { + return + } + + for _, item := range list.ResourceRecordSets { + for _, name := range names { + if name == *item.Name { + records = append(records, item) + } + } + } + + return +} + +func checkErr(err error) { + if err != nil { + log.Fatal(err) + } } diff --git a/modules/setting.go b/modules/setting.go new file mode 100644 index 0000000..b86f9de --- /dev/null +++ b/modules/setting.go @@ -0,0 +1,49 @@ +package setting + +import ( + "io/ioutil" + "log" + "os" + "path" + "path/filepath" + + "gopkg.in/yaml.v2" +) + +type Config struct { + Domains []struct { + Name string `yaml:"name"` + Sub []string `yaml:"subdomain,flow"` + } `yaml:"domains"` +} + +func LoadConfig(fp ...string) *Config { + var p string + if len(fp) > 0 && len(fp[0]) > 0 { + p = fp[0] + } else { + dir, err := os.Getwd() + if err != nil { + log.Fatal(err) + } + p = path.Join(dir, "config.yml") + } + zone := &Config{} + + p, err := filepath.Abs(p) + if err != nil { + log.Fatal(err) + } + + data, err := ioutil.ReadFile(p) + if err != nil { + log.Fatal(err) + } + + err = yaml.Unmarshal([]byte(data), &zone) + if err != nil { + log.Fatal(err) + } + + return zone +}