diff --git a/Dockerfile b/Dockerfile index 6774c23..4d2b71c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -4,8 +4,13 @@ COPY . . RUN go get . RUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o dnsupdater . -FROM scratch +FROM busybox:glibc COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt COPY --from=builder /usr/share/zoneinfo /usr/share/zoneinfo COPY --from=builder /tmp/dnsupdater/dnsupdater . -ENTRYPOINT ["/dnsupdater"] \ No newline at end of file + +RUN mkdir -p /var/spool/cron/crontabs /var/log +COPY entry.sh /entry.sh +RUN touch /var/log/cron.log +WORKDIR "/" +ENTRYPOINT ["/entry.sh"] diff --git a/build.sh b/build.sh index 65af44d..a987ca1 100644 --- a/build.sh +++ b/build.sh @@ -1,4 +1,7 @@ #!/bin/sh docker build --rm -t llehouerou/dnsupdater:latest . -docker push llehouerou/dnsupdater \ No newline at end of file +rc=$? +if [[ ${rc} == 0 ]]; then + docker push llehouerou/dnsupdater +fi \ No newline at end of file diff --git a/entry.sh b/entry.sh new file mode 100644 index 0000000..40a5c3f --- /dev/null +++ b/entry.sh @@ -0,0 +1,21 @@ +#!bin/sh +echo "Starting container ..." + +echo "Setup check cron job with cron expression CHECK_CRON: ${CHECK_CRON}" +echo "${CHECK_CRON} flock -n /tmp/check.lockfile /dnsupdater >> /var/log/cron.log 2>&1" > /var/spool/cron/crontabs/root + +cat /var/spool/cron/crontabs/root + +# Make sure the file exists before we start tail +touch /var/log/cron.log + +# start the cron deamon +crond + +echo "Container started." + +if [[ -n "${CHECKONSTART}" ]]; then + flock -n /tmp/check.lockfile /dnsupdater +fi + +tail -fn0 /var/log/cron.log diff --git a/go.mod b/go.mod index 1e1833b..83bbda4 100644 --- a/go.mod +++ b/go.mod @@ -3,7 +3,6 @@ module gogs.lehouerou.net/Laurent/dnsupdater go 1.12 require ( - github.com/robfig/cron v1.1.0 // indirect - github.com/sirupsen/logrus v1.4.2 // indirect - github.com/urfave/cli v1.20.0 // indirect + github.com/sirupsen/logrus v1.4.2 + github.com/urfave/cli v1.20.0 ) diff --git a/go.sum b/go.sum index 240be25..c396562 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,22 @@ +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/robfig/cron v1.1.0 h1:jk4/Hud3TTdcrJgUOBgsqrZBarcxl6ADIjSC2iniwLY= -github.com/robfig/cron v1.1.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/urfave/cli v1.20.0 h1:fDqGv3UG/4jbVl/QkFwEdddtEDjh/5Ov6X+0B/3bPaw= github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190609082536-301114b31cce h1:CQakrGkKbydnUmt7cFIlmQ4lNQiqdTPt6xzXij4nYCc= +golang.org/x/sys v0.0.0-20190609082536-301114b31cce/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= diff --git a/main.go b/main.go index 4771306..9c9ed3d 100644 --- a/main.go +++ b/main.go @@ -4,18 +4,13 @@ import ( "bytes" "encoding/json" "fmt" - "github.com/robfig/cron" log "github.com/sirupsen/logrus" "github.com/urfave/cli" "io/ioutil" "net/http" "net/smtp" "os" - "os/signal" "path" - "strconv" - "syscall" - "time" ) type Configuration struct { @@ -33,21 +28,15 @@ type DnsResponse struct { } var ( - configPath string - scheduleSpec string + configPath string ) -var version = "master" -var commit = "unknown" -var date = "unknown" - func main() { app := cli.NewApp() app.Name = "dnsupdater" - app.Version = version + " - " + commit + " - " + date + app.Version = "0.0.1" app.Usage = "Automatically update dns" - app.Before = before app.Action = start app.Flags = []cli.Flag{ @@ -57,17 +46,6 @@ func main() { Value: "/config/conf.json", EnvVar: "CONFIG_PATH", }, - cli.IntFlag{ - Name: "interval, i", - Usage: "poll interval (in seconds)", - Value: 300, - EnvVar: "DNSUPDATER_POLL_INTERVAL", - }, - cli.StringFlag{ - Name: "schedule, s", - Usage: "the cron expression which defines when to update", - EnvVar: "DNSUPDATER_SCHEDULE", - }, } if err := app.Run(os.Args); err != nil { @@ -75,67 +53,11 @@ func main() { } } -func before(c *cli.Context) error { - if c.GlobalBool("debug") { - log.SetLevel(log.DebugLevel) +func start(c *cli.Context) { + if err := update(c); err != nil { + log.Errorln(err) + SendStatusMail(fmt.Sprintf("Error during update process : %s", err)) } - - pollingSet := c.IsSet("interval") - cronSet := c.IsSet("schedule") - - if pollingSet && cronSet { - log.Fatal("Only schedule or interval can be defined, not both.") - } else if cronSet { - scheduleSpec = c.String("schedule") - } else { - scheduleSpec = "@every " + strconv.Itoa(c.Int("interval")) + "s" - } - return nil -} - -func start(c *cli.Context) error { - tryLockSem := make(chan bool, 1) - tryLockSem <- true - - cr := cron.New() - err := cr.AddFunc( - scheduleSpec, - func() { - select { - case v := <-tryLockSem: - defer func() { tryLockSem <- v }() - if err := update(c); err != nil { - log.Println(err) - SendStatusMail(fmt.Sprintf("Error during update process : %s", err)) - } - default: - log.Debug("Skipped another update already running.") - } - - nextRuns := cr.Entries() - if len(nextRuns) > 0 { - log.Debug("Scheduled next run: " + nextRuns[0].Next.String()) - } - }) - - if err != nil { - return err - } - - log.Info("First run: " + cr.Entries()[0].Schedule.Next(time.Now()).String()) - cr.Start() - - // Graceful shut-down on SIGINT/SIGTERM - interrupt := make(chan os.Signal, 1) - signal.Notify(interrupt, os.Interrupt) - signal.Notify(interrupt, syscall.SIGTERM) - - <-interrupt - cr.Stop() - log.Info("Waiting for running update to be finished...") - <-tryLockSem - os.Exit(1) - return nil } func update(c *cli.Context) error { @@ -151,30 +73,35 @@ func update(c *cli.Context) error { configuration := Configuration{} err := decoder.Decode(&configuration) - currentIp, err := GetCurrentIp(configuration) - if err != nil { - return err - } newIp, err := GetOutboundIP() if err != nil { return err } - if currentIp == newIp { - return nil - } - - Info("Ip has changed %s -> %s", currentIp, newIp) - + updatedDomains := "" for _, domain := range configuration.Domains { + currentIp, err := GetCurrentIp(configuration, domain) + if err != nil { + return err + } + + if currentIp == newIp { + continue + } + + fmt.Printf("%s -> Ip has changed %s -> %s\n", domain, currentIp, newIp) + err = SetCurrentIp(newIp, domain, configuration) if err != nil { return err } + updatedDomains += fmt.Sprintf("\t- %s\n", domain) } - SendStatusMail(fmt.Sprintf(`Home IP has changed : %s -> %s -Dns updated successfully`, currentIp, newIp)) + if updatedDomains != "" { + SendStatusMail(fmt.Sprintf(`Home IP has changed : %s +Dns updated successfully for domains\n%s`, newIp, updatedDomains)) + } return nil } @@ -210,8 +137,8 @@ Subject: DnsUpdater Status } } -func GetCurrentIp(configuration Configuration) (string, error) { - url := "https://dns.api.gandi.net/api/v5/domains/lehouerou.net/records/@/A" +func GetCurrentIp(configuration Configuration, domain string) (string, error) { + url := fmt.Sprintf("https://dns.api.gandi.net/api/v5/domains/%s/records/@/A", domain) req, err := http.NewRequest("GET", url, nil) if err != nil { @@ -290,7 +217,3 @@ func exists(path string) (bool, error) { } return true, err } - -func Info(format string, args ...interface{}) { - fmt.Printf("\x1b[34;1m%s\x1b[0m\n", fmt.Sprintf(format, args...)) -}