Initial commit
This commit is contained in:
@@ -0,0 +1,90 @@
|
||||
package digitalocean
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type client struct {
|
||||
baseUrl string
|
||||
domain string
|
||||
token string
|
||||
httpClient *http.Client
|
||||
}
|
||||
|
||||
func NewClient(baseUrl, token, domain string) *client {
|
||||
return &client{
|
||||
baseUrl: baseUrl,
|
||||
domain: domain,
|
||||
token: token,
|
||||
httpClient: &http.Client{
|
||||
Timeout: 30 * time.Second,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (c *client) GetARecordID() (string, error) {
|
||||
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/v2/domains/%s/records", c.baseUrl, c.domain), nil)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", c.token))
|
||||
|
||||
var records RecordsResponse
|
||||
err = c.doRequest(req, &records)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
for _, record := range records.DomainRecords {
|
||||
if record.Name == "vpn" && record.Type == "A" {
|
||||
return strconv.Itoa(int(record.Id)), nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", ErrNotFound
|
||||
}
|
||||
|
||||
func (c *client) SetARecord(id, ip string) error {
|
||||
body := fmt.Sprintf(`{"data":%q}`, strings.ReplaceAll(ip, "\n", ""))
|
||||
req, err := http.NewRequest(http.MethodPatch, fmt.Sprintf("%s/v2/domains/%s/records/%s", c.baseUrl, c.domain, id), bytes.NewBufferString(body))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
req.Header.Add("Authorization", fmt.Sprintf("Bearer %s", c.token))
|
||||
req.Header.Add("Content-Type", "application/json")
|
||||
|
||||
var resp map[string]interface{}
|
||||
err = c.doRequest(req, &resp)
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *client) doRequest(req *http.Request, output interface{}) error {
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode >= http.StatusInternalServerError {
|
||||
return fmt.Errorf("%w: statuscode %d", ErrServerError, resp.StatusCode)
|
||||
}
|
||||
|
||||
if resp.StatusCode >= http.StatusBadRequest {
|
||||
return fmt.Errorf("%w: statuscode %d", ErrClientError, resp.StatusCode)
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = json.Unmarshal(body, &output)
|
||||
return err
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package digitalocean
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
ErrNotFound = errors.New("not found")
|
||||
ErrClientError = errors.New("client error")
|
||||
ErrServerError = errors.New("server error")
|
||||
)
|
||||
@@ -0,0 +1,12 @@
|
||||
package digitalocean
|
||||
|
||||
type DomainRecords struct {
|
||||
Data string `json:"data"`
|
||||
Id int64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Type string `json:"type"`
|
||||
}
|
||||
|
||||
type RecordsResponse struct {
|
||||
DomainRecords []DomainRecords `json:"domain_records"`
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"github.com/davidlick/digitalocean-ddns/digitalocean"
|
||||
)
|
||||
|
||||
var (
|
||||
client = &http.Client{}
|
||||
)
|
||||
|
||||
func main() {
|
||||
token := os.Getenv("DIGITALOCEAN_TOKEN")
|
||||
doBaseUrl := os.Getenv("DIGITALOCEAN_URL")
|
||||
doDomain := os.Getenv("DIGITALOCEAN_DOMAIN")
|
||||
|
||||
client := digitalocean.NewClient(doBaseUrl, token, doDomain)
|
||||
|
||||
ip, err := getPublicIP()
|
||||
if err != nil {
|
||||
log.Fatalf("failed to get public ip: %v", err)
|
||||
}
|
||||
|
||||
id, err := client.GetARecordID()
|
||||
if err != nil {
|
||||
log.Fatalf("failed to get A record ID: %v", err)
|
||||
}
|
||||
|
||||
err = client.SetARecord(id, ip)
|
||||
if err != nil {
|
||||
log.Fatalf("failed to set A record ip: %v", err)
|
||||
}
|
||||
|
||||
log.Printf("successfully set DNS A record id %s to %s", id, ip)
|
||||
}
|
||||
|
||||
func getPublicIP() (string, error) {
|
||||
resp, err := http.Get("https://icanhazip.com")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(body), nil
|
||||
}
|
||||
Reference in New Issue
Block a user