diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/LICENSE.md b/LICENSE.md old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 index ecec89a..f6aa77b --- a/README.md +++ b/README.md @@ -4,7 +4,8 @@ A simple script in Go language to automatically update Digital ocean DNS records ## requirements Requires Git and Go for building. -Requires that the record already exists in DigitalOcean's DNS. +Requires that the record already exists in DigitalOcean's DNS so that it can be updated. +(manually find your IP and add it to DO's DNS it will later be updated) ## Usage ```bash @@ -15,11 +16,24 @@ create a file ".digitalocean-dynamic-ip.json"(dot prefix to hide the file) and p ```json { "apikey": "samplekeydasjkdhaskjdhrwofihsamplekey", - "domain": "example.com", - "records": [ + "domains": [ { - "name": "subdomain", - "type": "A" + "domain": "example.com", + "records": [ + { + "name": "subdomainOrRecord", + "type": "A" + } + ] + }, + { + "domain": "example2.com", + "records": [ + { + "name": "subdomainOrRecord2", + "type": "A" + } + ] } ] } diff --git a/digitalocean-dynamic-ip.go b/digitalocean-dynamic-ip.go old mode 100644 new mode 100755 index 200b2e0..3df31c3 --- a/digitalocean-dynamic-ip.go +++ b/digitalocean-dynamic-ip.go @@ -13,15 +13,20 @@ import ( func checkError(err error) { if err != nil { - panic(err) + log.Fatal(err) } } // ClientConfig : configuration json type ClientConfig struct { - APIKey string `json:"apiKey"` - Domain string `json:"domain"` - Record []DNSRecord `json:"records"` + APIKey string `json:"apiKey"` + Domains []Domain `json:"domains"` +} + +// Domain : domains to be changed +type Domain struct { + Domain string `json:"domain"` + Records []DNSRecord `json:"records"` } // DNSRecord : Modifyiable DNS record @@ -37,7 +42,8 @@ type DOResponse struct { DomainRecords []DNSRecord `json:"domain_records"` } -func main() { +//GetConfig : get configuration file ~/.digitalocean-dynamic-ip.json +func GetConfig() ClientConfig { homeDirectory, err := homedir.Dir() checkError(err) getfile, err := ioutil.ReadFile(homeDirectory + "/.digitalocean-dynamic-ip.json") @@ -45,52 +51,70 @@ func main() { var config ClientConfig json.Unmarshal(getfile, &config) checkError(err) + return config +} - // check current local ip - +//CheckLocalIP : get current IP of server. +func CheckLocalIP() string { currentIPRequest, err := http.Get("https://diagnostic.opendns.com/myip") checkError(err) defer currentIPRequest.Body.Close() currentIPRequestParse, err := ioutil.ReadAll(currentIPRequest.Body) checkError(err) - currentIP := string(currentIPRequestParse) - - // get current dns record ip + return string(currentIPRequestParse) +} +//GetDomainRecords : Get DNS records of current domain. +func GetDomainRecords(apiKey string, domain string) DOResponse { client := &http.Client{} request, err := http.NewRequest("GET", - "https://api.digitalocean.com/v2/domains/"+string(config.Domain)+"/records", + "https://api.digitalocean.com/v2/domains/"+domain+"/records", nil) checkError(err) request.Header.Add("Content-type", "Application/json") - request.Header.Add("Authorization", "Bearer "+string(config.APIKey)) + request.Header.Add("Authorization", "Bearer "+apiKey) response, err := client.Do(request) checkError(err) defer response.Body.Close() body, err := ioutil.ReadAll(response.Body) - var jsonResponse DOResponse - e := json.Unmarshal(body, &jsonResponse) + var jsonDOResponse DOResponse + e := json.Unmarshal(body, &jsonDOResponse) checkError(e) + return jsonDOResponse +} - // update ip by matching dns records and config - - for _, record := range jsonResponse.DomainRecords { - for _, configRecord := range config.Record { - if configRecord.Name == record.Name && configRecord.Type == record.Type && currentIP != record.Data { - update := []byte(`{"type":"` + configRecord.Type + `","data":"` + currentIP + `"}`) +// UpdateRecords : Update DNS records of domain +func UpdateRecords(apiKey string, domain string, currentIP string, currentRecords DOResponse, toUpdateRecords []DNSRecord) { + for _, currentRecord := range currentRecords.DomainRecords { + for _, toUpdateRecord := range toUpdateRecords { + if toUpdateRecord.Name == currentRecord.Name && toUpdateRecord.Type == currentRecord.Type && currentIP != currentRecord.Data { + update := []byte(`{"type":"` + toUpdateRecord.Type + `","data":"` + currentIP + `"}`) client := &http.Client{} request, err := http.NewRequest("PUT", - "https://api.digitalocean.com/v2/domains/"+string(config.Domain)+"/records/"+strconv.FormatInt(int64(record.ID), 10), + "https://api.digitalocean.com/v2/domains/"+domain+"/records/"+strconv.FormatInt(int64(currentRecord.ID), 10), bytes.NewBuffer(update)) checkError(err) request.Header.Set("Content-Type", "application/json") - request.Header.Add("Authorization", "Bearer "+string(config.APIKey)) + request.Header.Add("Authorization", "Bearer "+apiKey) response, err := client.Do(request) checkError(err) defer response.Body.Close() body, err := ioutil.ReadAll(response.Body) - log.Printf("DO update response for %s: %s", record.Name, string(body)) + log.Printf("DO update response for %s: %s\n", currentRecord.Name, string(body)) } } } } + +func main() { + config := GetConfig() + currentIP := CheckLocalIP() + + for _, domains := range config.Domains { + domainName := domains.Domain + apiKey := config.APIKey + currentDomainRecords := GetDomainRecords(apiKey, domainName) + log.Println(domainName) + UpdateRecords(apiKey, domainName, currentIP, currentDomainRecords, domains.Records) + } +} diff --git a/digitalocean-dynamic-ip.sample.json b/digitalocean-dynamic-ip.sample.json old mode 100644 new mode 100755 index 5be77a7..f9fae24 --- a/digitalocean-dynamic-ip.sample.json +++ b/digitalocean-dynamic-ip.sample.json @@ -1,10 +1,23 @@ { "apikey": "samplekeydasjkdhaskjdhrwofihsamplekey", - "domain": "example.com", - "records": [ + "domains": [ { - "name": "subdomain", - "type": "A" + "domain": "example.com", + "records": [ + { + "name": "subdomainOrRecord", + "type": "A" + } + ] + }, + { + "domain": "example2.com", + "records": [ + { + "name": "subdomainOrRecord2", + "type": "A" + } + ] } ] } \ No newline at end of file