add multi credentials support

This commit is contained in:
DataHearth 2021-05-17 13:15:39 +02:00
parent c5a780dfb0
commit c88eb9c7d8
No known key found for this signature in database
GPG Key ID: E88FD356ACC5F3C4
13 changed files with 224 additions and 521 deletions

View File

@ -22,12 +22,13 @@ var (
},
}
logger = logrus.StandardLogger()
config ddnsclient.ClientConfig
config utils.ClientConfig
)
func init() {
viper.BindEnv("CONFIG_PATH")
viper.SetConfigType("yaml")
if conf := viper.GetString("CONFIG_PATH"); conf == "" {
viper.SetConfigFile("ddnsclient.yaml")
} else {

View File

@ -1,31 +0,0 @@
package ddnsclient
import (
"github.com/datahearth/ddnsclient/pkg/providers/google"
"github.com/datahearth/ddnsclient/pkg/providers/ovh"
)
type ClientConfig struct {
Logger Logger `mapstructure:"logger"`
Providers Providers `mapstructure:"providers"`
Watchers WatcherConfig `mapstructure:"watchers"`
UpdateTime int `mapstructure:"update-time,omitempty"`
PendingDnsPropagation int `mapstructure:"pending-dns-propagation,omitempty"`
WebIP string `mapstructure:"web-ip,omitempty"`
}
type Logger struct {
Level string `mapstructure:"level"`
DisableTimestamp bool `mapstructure:"disable-timestamp,omitempty"`
DisableColor bool `mapstructure:"disable-color,omitempty"`
}
type Providers struct {
Ovh ovh.OvhConfig `mapstructure:"ovh,omitempty"`
Google google.GoogleConfig `mapstructure:"google,omitempty"`
}
type WatcherConfig struct {
Ovh []string `yaml:"ovh,omitempty"`
Google []string `yaml:"google,omitempty"`
}

69
main.go
View File

@ -4,14 +4,10 @@ import (
"errors"
"os"
"os/signal"
"reflect"
"strings"
"syscall"
"time"
"github.com/datahearth/ddnsclient/pkg/providers"
"github.com/datahearth/ddnsclient/pkg/providers/google"
"github.com/datahearth/ddnsclient/pkg/providers/ovh"
"github.com/datahearth/ddnsclient/pkg/utils"
"github.com/datahearth/ddnsclient/pkg/watcher"
"github.com/sirupsen/logrus"
)
@ -24,25 +20,15 @@ var (
)
// Start create a new instance of ddns-client
func Start(logger logrus.FieldLogger, config ClientConfig) error {
func Start(logger logrus.FieldLogger, config utils.ClientConfig) error {
log := logger.WithFields(logrus.Fields{
"pkg": "ddnsclient",
"component": "root",
})
fields := reflect.ValueOf(config.Watchers)
ws := []watcher.Watcher{}
// * check providers and watchers config
// todo: invalid condition but while still exit in the next step. To be corrected
if fields.NumField() == 0 || reflect.ValueOf(config.Providers).NumField() == 0 {
return ErrWatchersConfigLen
}
for i := 0; i < fields.NumField(); i++ {
providerName := strings.ToLower(fields.Type().Field(i).Name)
w, err := CreateWatcher(providerName, config.WebIP, logger, config.Watchers, config.Providers, config.PendingDnsPropagation)
ws := make([]watcher.Watcher, 0, len(config.Watchers))
for _, cw := range config.Watchers {
w, err := watcher.NewWatcher(logger, &cw, config.WebIP)
if err != nil {
logger.Warnf("Provider error: %v. Skipping...\n", err.Error())
continue
@ -51,24 +37,20 @@ func Start(logger logrus.FieldLogger, config ClientConfig) error {
ws = append(ws, w)
}
// * check for valid created watchers
if len(ws) == 0 {
return ErrWatcherCreationLen
}
// * create signal watcher
sigc := make(chan os.Signal, 1)
signal.Notify(sigc, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
defer close(sigc)
// * create close and error channel
chClose := make(chan struct{})
chErr := make(chan error)
defer close(chClose)
defer close(chErr)
logger.Infoln("Start watching periodically for changes!")
// * run every created watchers in goroutines
for _, w := range ws {
tickTime := config.UpdateTime
if tickTime == 0 {
@ -79,7 +61,6 @@ func Start(logger logrus.FieldLogger, config ClientConfig) error {
go w.Run(t, chClose, chErr)
}
// * listening for errors and exit signal
for {
select {
case err := <-chErr:
@ -92,43 +73,3 @@ func Start(logger logrus.FieldLogger, config ClientConfig) error {
}
}
}
func CreateWatcher(provider, webIP string, logger logrus.FieldLogger, wc WatcherConfig, ps Providers, pendingDnsPropagation int) (watcher.Watcher, error) {
var sbs []string
var p providers.Provider
var err error
// * check for implemented providers
switch provider {
case "ovh":
logger.Debugln("create OVH provider")
p, err = ovh.NewOVH(logger, &ps.Ovh)
if err != nil {
return nil, err
}
sbs = wc.Ovh
case "google":
logger.Debugln("create GOOGLE provider")
p, err = google.NewGoogle(logger, &ps.Google)
if err != nil {
return nil, err
}
sbs = wc.Google
default:
return nil, ErrInvalidProvider
}
if len(sbs) == 0 {
return nil, ErrSbsLen
}
// * create provider's watcher
w, err := watcher.NewWatcher(logger, p, sbs, webIP, provider, pendingDnsPropagation)
if err != nil {
return nil, err
}
return w, nil
}

119
pkg/provider/main.go Normal file
View File

@ -0,0 +1,119 @@
package provider
import (
"errors"
"io/ioutil"
"net/http"
"strings"
"github.com/datahearth/ddnsclient/pkg/utils"
"github.com/sirupsen/logrus"
)
// Provider is the default interface for all providers
type Provider interface {
UpdateSubdomains(ip string) error
}
type provider struct {
logger logrus.FieldLogger
config utils.Config
name string
url string
}
func NewProvider(logger logrus.FieldLogger, config utils.Config, url, name string) (Provider, error) {
if logger == nil {
return nil, utils.ErrNilLogger
}
if name == "" {
return nil, utils.ErrInvalidName
}
if url == "" {
if utils.DefaultURLs[name] == "" {
return nil, utils.ErrInvalidURL
}
url = utils.DefaultURLs[name]
}
logger = logger.WithField("pkg", "providers")
return &provider{
config: config,
logger: logger,
name: name,
url: url,
}, nil
}
func (p *provider) UpdateSubdomains(srvIP string) error {
for _, sb := range p.config.Subdomains {
ip, err := utils.RetrieveSubdomainIP(sb)
if err != nil {
return err
}
if ip == srvIP {
continue
}
p.logger.WithFields(logrus.Fields{
"component": "UpdateSubdomains",
"server-ip": srvIP,
"subdomain-address": ip,
"subdomain": sb,
}).Infoln("IP addresses doesn't match. Updating subdomain's ip...")
if err := p.updateSubdomain(sb, srvIP); err != nil {
if err != utils.ErrReadBody && err != utils.ErrWrongStatusCode {
return err
}
p.logger.WithError(err).WithFields(logrus.Fields{
"component": "UpdateSubdomains",
"subdomain": sb,
"new-ip": srvIP,
}).Warnln("failed to update subdomain ip")
}
}
return nil
}
func (p *provider) updateSubdomain(subdomain, ip string) error {
newURL := strings.ReplaceAll(p.url, "SUBDOMAIN", subdomain)
newURL = strings.ReplaceAll(newURL, "NEWIP", ip)
logger := p.logger.WithFields(logrus.Fields{
"component": "UpdateIP",
"updated-url": newURL,
"subdomain": subdomain,
"new-ip": ip,
})
req, err := http.NewRequest("GET", newURL, nil)
if err != nil {
return utils.ErrCreateNewRequest
}
req.SetBasicAuth(p.config.Username, p.config.Password)
logger.Debugln("calling DDNS provider for subdomain update")
c := new(http.Client)
resp, err := c.Do(req)
if err != nil {
return utils.ErrUpdateRequest
}
if resp.ContentLength != 0 {
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return utils.ErrReadBody
}
if !strings.Contains(string(b), "good "+ip) && !strings.Contains(string(b), "nochg "+ip) {
return errors.New("failed to update subdomain ip. Error: " + string(b))
}
}
if resp.StatusCode != 200 {
return utils.ErrWrongStatusCode
}
return nil
}

View File

@ -1,99 +0,0 @@
package google
import (
"errors"
"io/ioutil"
"net/http"
"strings"
"github.com/datahearth/ddnsclient/pkg/providers"
"github.com/datahearth/ddnsclient/pkg/utils"
"github.com/sirupsen/logrus"
)
var (
// ErrNilGoogleConfig is thrown when GOOGLE configuration is empty
ErrNilGoogleConfig = errors.New("GOOGLE config is mandatory")
// ErrInvalidConfig is thrown when no username and password are provided and URL doesn't contains them
ErrInvalidConfig = errors.New("username and password are required if url doesn't contains them")
// ErrReadBody is thrown when reader failed to read response body
ErrReadBody = errors.New("failed to read response body")
)
// GoogleConfig is the struct for the yaml configuration file
type GoogleConfig struct {
URL string `mapstructure:"url"`
Username string `mapstructure:"username,omitempty"`
Password string `mapstructure:"password,omitempty"`
}
type google struct {
config *GoogleConfig
logger logrus.FieldLogger
}
// NewGoogle returns a new instance of the GOOGLE provider
func NewGoogle(logger logrus.FieldLogger, googleConfig *GoogleConfig) (providers.Provider, error) {
if googleConfig == nil {
return nil, ErrNilGoogleConfig
}
if logger == nil {
return nil, utils.ErrNilLogger
}
if (googleConfig.Username == "" && googleConfig.Password == "") && !strings.Contains(googleConfig.URL, "@") {
return nil, ErrInvalidConfig
}
logger = logger.WithField("pkg", "provider-google")
return &google{
config: googleConfig,
logger: logger,
}, nil
}
// UpdateIP updates the subdomain A record
func (g *google) UpdateIP(subdomain, ip string) error {
newURL := strings.ReplaceAll(g.config.URL, "SUBDOMAIN", subdomain)
newURL = strings.ReplaceAll(newURL, "NEWIP", ip)
logger := g.logger.WithFields(logrus.Fields{
"component": "update-ip",
"ovh-update-url": newURL,
"subdomain": subdomain,
"new-ip": ip,
})
// * create POST request
req, err := http.NewRequest("POST", newURL, nil)
if err != nil {
return utils.ErrCreateNewRequest
}
// * use basic auth if config is set
if g.config.Username != "" && g.config.Password != "" {
logger.Debugln("username and password passed in config. Use basic auth")
req.SetBasicAuth(g.config.Username, g.config.Password)
}
// * perform POST request
logger.Debugln("calling Google DynDNS to update subdomain IP")
c := new(http.Client)
resp, err := c.Do(req)
if err != nil {
return utils.ErrUpdateRequest
}
// * read response body
b, err := ioutil.ReadAll(resp.Body)
if err != nil {
return ErrReadBody
}
// * check for error response
// doc: https://support.google.com/domains/answer/6147083?hl=en#zippy=%2Cusing-the-api-to-update-your-dynamic-dns-record
// todo: check why the hell do I need to use () for conditions here !!!!
if (strings.Contains(string(b), "good "+ip) != true) || (strings.Contains(string(b), "nochg "+ip) != false) {
return errors.New("failed to update subdomain ip. Google error: " + string(b))
}
return nil
}

View File

@ -1,6 +0,0 @@
package providers
// Provider is the default interface for all providers
type Provider interface {
UpdateIP(subdomain, ip string) error
}

View File

@ -1,76 +0,0 @@
package ovh
import (
"errors"
"net/http"
"strings"
"github.com/datahearth/ddnsclient/pkg/providers"
"github.com/datahearth/ddnsclient/pkg/utils"
"github.com/sirupsen/logrus"
)
// ErrNilOvhConfig is thrown when OVH configuration is empty
var ErrNilOvhConfig = errors.New("OVH config is mandatory")
type OvhConfig struct {
URL string `mapstructure:"url,omitempty"`
Username string `mapstructure:"username"`
Password string `mapstructure:"password"`
}
type ovh struct {
config *OvhConfig
logger logrus.FieldLogger
}
// NewOVH returns a new instance of the OVH provider
func NewOVH(logger logrus.FieldLogger, ovhConfig *OvhConfig) (providers.Provider, error) {
if ovhConfig == nil {
return nil, ErrNilOvhConfig
}
if logger == nil {
return nil, utils.ErrNilLogger
}
if ovhConfig.URL == "" {
ovhConfig.URL = "http://www.ovh.com/nic/update?system=dyndns&hostname=SUBDOMAIN&myip=NEWIP"
}
logger = logger.WithField("pkg", "provider-ovh")
return &ovh{
config: ovhConfig,
logger: logger,
}, nil
}
func (ovh *ovh) UpdateIP(subdomain, ip string) error {
newURL := strings.ReplaceAll(ovh.config.URL, "SUBDOMAIN", subdomain)
newURL = strings.ReplaceAll(newURL, "NEWIP", ip)
logger := ovh.logger.WithFields(logrus.Fields{
"component": "update-ip",
"ovh-update-url": newURL,
"subdomain": subdomain,
"new-ip": ip,
})
// * create GET request
req, err := http.NewRequest("GET", newURL, nil)
if err != nil {
return utils.ErrCreateNewRequest
}
req.SetBasicAuth(ovh.config.Username, ovh.config.Password)
// * perform GET request
logger.Debugln("calling OVH DynHost to update subdomain IP")
c := new(http.Client)
resp, err := c.Do(req)
if err != nil {
return utils.ErrUpdateRequest
}
if resp.StatusCode != 200 {
return utils.ErrWrongStatusCode
}
return nil
}

View File

@ -1,92 +0,0 @@
package subdomain
import (
"errors"
"net"
"strings"
"time"
"github.com/datahearth/ddnsclient/pkg/utils"
"github.com/sirupsen/logrus"
)
// ErrIpLength is thrown when subdomain no or multiples remote IP address
var ErrIpLenght = errors.New("zero or more than 1 ips have been found")
type (
PendingSubdomains map[time.Time]Subdomain
subdomain struct {
logger logrus.FieldLogger
subdomainAddr string
ip string
}
Subdomain interface {
CheckIPAddr(srvIP string) (bool, error)
GetSubdomainIP() string
retrieveSubdomainIP() error
GetSubdomainAddr() string
SubIsPending(sbs PendingSubdomains) bool
FindSubdomain(sbs PendingSubdomains) Subdomain
}
)
// NewSubdomain instanciate a new http implementation
func NewSubdomain(logger logrus.FieldLogger, subdomainAddr string) (Subdomain, error) {
if logger == nil {
return nil, utils.ErrNilLogger
}
logger = logger.WithField("pkg", "subdomain")
return &subdomain{
logger: logger,
subdomainAddr: subdomainAddr,
}, nil
}
// RetrieveSubdomainIP will retrieve the subdomain IP with a HEAD request
func (sd *subdomain) retrieveSubdomainIP() error {
ips, err := net.LookupIP(sd.subdomainAddr)
if err != nil {
return err
}
if len(ips) != 1 {
return ErrIpLenght
}
ip := ips[0].String()
if strings.Contains(ip, ":") {
ip, _, err = net.SplitHostPort(ip)
if err != nil {
return utils.ErrSplitAddr
}
}
sd.ip = ip
return nil
}
// CheckIPAddr will compare the server IP and the subdomain IP
func (sd *subdomain) CheckIPAddr(srvIP string) (bool, error) {
if err := sd.retrieveSubdomainIP(); err != nil {
return false, err
}
if srvIP != sd.ip {
return false, nil
}
return true, nil
}
// GetSubdomainIP returns the subdomain IP
func (sd *subdomain) GetSubdomainIP() string {
return sd.ip
}
// GetSubdomainAddr returns the subdomain address
func (sd *subdomain) GetSubdomainAddr() string {
return sd.subdomainAddr
}

View File

@ -1,52 +0,0 @@
package subdomain
import "time"
// SubIsPending check if the current subdomain is waiting the DNS propagation.
func (sb *subdomain) SubIsPending(sbs PendingSubdomains) bool {
for _, sub := range sbs {
if sb == sub {
return true
}
}
return false
}
// FindSubdomain returns a subdomain found in the pending map of subdomain.
// If not found, it returns nil.
func (sb *subdomain) FindSubdomain(sbs PendingSubdomains) Subdomain {
for _, sub := range sbs {
if sub == sb {
return sb
}
}
return nil
}
// CheckPendingSubdomains check if any pending subdomains are waiting to be restored.
// If so, it/they will be returned as a slice.
// If not, it returns nil.
func CheckPendingSubdomains(sbs PendingSubdomains, now time.Time) PendingSubdomains {
delSbs := make(PendingSubdomains)
for t, sb := range sbs {
if t.Add(5 * time.Minute).Before(now) {
delSbs[t] = sb
}
}
if len(delSbs) < 1 {
return nil
}
return delSbs
}
func DeletePendingSubdomains(delSbs PendingSubdomains, pending PendingSubdomains) PendingSubdomains {
for t := range delSbs {
delete(pending, t)
}
return pending
}

33
pkg/utils/config.go Normal file
View File

@ -0,0 +1,33 @@
package utils
type ClientConfig struct {
Logger Logger `mapstructure:"logger"`
Watchers []Watcher `mapstructure:"watchers"`
UpdateTime int `mapstructure:"update-time,omitempty"`
PendingDnsPropagation int `mapstructure:"pending-dns-propagation,omitempty"`
WebIP string `mapstructure:"web-ip,omitempty"`
}
type Logger struct {
Level string `mapstructure:"level"`
DisableTimestamp bool `mapstructure:"disable-timestamp,omitempty"`
DisableColor bool `mapstructure:"disable-color,omitempty"`
}
type Watcher struct {
Name string `yaml:"name"`
URL string `yaml:"url,omitempty"`
Config []Config `yaml:"config"`
}
type Config struct {
Username string `yaml:"username"`
Password string `yaml:"password"`
Subdomains []string `yaml:"subdomains"`
}
var DefaultURLs = map[string]string{
"ovh": "http://www.ovh.com/nic/update?system=dyndns&hostname=SUBDOMAIN&myip=NEWIP",
"google": "https://domains.google.com/nic/update?hostname=SUBDOMAIN&myip=NEWIP",
"webIP": "http://dynamicdns.park-your-domain.com/getip",
}

View File

@ -8,18 +8,28 @@ import (
var (
// ErrNilLogger is thrown when the parameter logger is nil
ErrNilLogger = errors.New("logger is mandatory")
// ErrNilProvider ...
ErrNilProvider = errors.New("provider is mandatory")
// ErrWrongStatusCode is thrown when the response status code isn't a 200
ErrWrongStatusCode = errors.New("web-ip returns a non 200 status code")
// ErrGetServerIP is thrown when HTTP can't contact the web-ip service
ErrGetServerIP = errors.New("HTTP error")
// ErrParseHTTPBody is thrown when the HTTP service can't parse the body response
ErrParseHTTPBody = errors.New("can't parse response body")
// ErrSplitAddr ...
// ErrSplitAddr is thrown when the remote address can't be splitted
ErrSplitAddr = errors.New("can't split subdomain remote IP address")
// ErrCreateNewRequest ...
// ErrCreateNewRequest is thrown when http request creation failed
ErrCreateNewRequest = errors.New("can't create http request")
// ErrUpdateRequest ...
// ErrUpdateRequest is thrown when the update request failed
ErrUpdateRequest = errors.New("failed to set new IP address")
// ErrInvalidURL is thrown when user does not provide a URL and it does not exist in default urls
ErrInvalidURL = errors.New("no url was provided")
// ErrInvalidName is thrown when provider name was not provided
ErrInvalidName = errors.New("no provider name was provided")
// ErrReadBody is thrown when body response can't be parsed
ErrReadBody = errors.New("failed to read response body")
// ErrNilWatcher is thrown when no watcher config was provided
ErrNilWatcher = errors.New("watcher is mandatory")
// ErrIpLength is thrown when subdomain no or multiples remote IP address
ErrIpLenght = errors.New("zero or more than 1 ips have been found")
// ErrNilConfig is thrown when an empty config is provided
ErrNilConfig = errors.New("config is mandatory")
)

View File

@ -2,7 +2,9 @@ package utils
import (
"io/ioutil"
"net"
"net/http"
"strings"
"github.com/sirupsen/logrus"
"github.com/spf13/viper"
@ -54,18 +56,8 @@ func SetupLogger(logger *logrus.Logger) {
})
}
func AggregateSubdomains(subdomains []string, domain string) []string {
agdSub := make([]string, len(subdomains))
for i, sd := range subdomains {
agdSub[i] = sd + "." + domain
}
return agdSub
}
// RetrieveServerIP will use the defined web-ip service to get the server public address and save it to the struct
// RetrieveServerIP will use the defined web-ip service to get the server public address
func RetrieveServerIP(webIP string) (string, error) {
// * retrieve client's server IP
resp, err := http.Get(webIP)
if err != nil {
return "", ErrGetServerIP
@ -74,7 +66,6 @@ func RetrieveServerIP(webIP string) (string, error) {
return "", ErrWrongStatusCode
}
// * get ip from body
d, err := ioutil.ReadAll(resp.Body)
if err != nil {
return "", ErrParseHTTPBody
@ -82,3 +73,25 @@ func RetrieveServerIP(webIP string) (string, error) {
return string(d), nil
}
// RetrieveSubdomainIP will retrieve the subdomain IP
func RetrieveSubdomainIP(addr string) (string, error) {
ips, err := net.LookupIP(addr)
if err != nil {
return "", err
}
if len(ips) != 1 {
return "", ErrIpLenght
}
ip := ips[0].String()
if strings.Contains(ip, ":") {
ip, _, err = net.SplitHostPort(ip)
if err != nil {
return "", ErrSplitAddr
}
}
return ip, nil
}

View File

@ -3,8 +3,7 @@ package watcher
import (
"time"
"github.com/datahearth/ddnsclient/pkg/providers"
"github.com/datahearth/ddnsclient/pkg/subdomain"
"github.com/datahearth/ddnsclient/pkg/provider"
"github.com/datahearth/ddnsclient/pkg/utils"
"github.com/sirupsen/logrus"
)
@ -14,58 +13,47 @@ type Watcher interface {
}
type watcher struct {
logger logrus.FieldLogger
provider providers.Provider
subdomains []subdomain.Subdomain
pendingSubdomains subdomain.PendingSubdomains
firstRun bool
pendingDnsPropagation int
webIP string
providerName string
logger logrus.FieldLogger
providers []provider.Provider
firstRun bool
webIP string
providerName string
}
// NewWatcher creates a watcher a given provider and its subdomains
func NewWatcher(logger logrus.FieldLogger, provider providers.Provider, sbs []string, webIP, providerName string, pendingDnsPropagation int) (Watcher, error) {
// NewWatcher creates a watcher a given provider config
func NewWatcher(logger logrus.FieldLogger, w *utils.Watcher, webIP string) (Watcher, error) {
if logger == nil {
return nil, utils.ErrNilLogger
}
if provider == nil {
return nil, utils.ErrNilProvider
if w == nil {
return nil, utils.ErrNilWatcher
}
if webIP == "" {
webIP = "http://dynamicdns.park-your-domain.com/getip"
webIP = utils.DefaultURLs["webIP"]
}
if pendingDnsPropagation == 0 {
pendingDnsPropagation = 180
}
logger = logger.WithField("pkg", "watcher")
subdomains := make([]subdomain.Subdomain, len(sbs))
for i, sb := range sbs {
sub, err := subdomain.NewSubdomain(logger, sb)
providers := []provider.Provider{}
for _, c := range w.Config {
p, err := provider.NewProvider(logger, c, w.URL, w.Name)
if err != nil {
return nil, err
}
subdomains[i] = sub
providers = append(providers, p)
}
logger = logger.WithField("pkg", "watcher")
return &watcher{
logger: logger,
provider: provider,
subdomains: subdomains,
webIP: webIP,
firstRun: true,
pendingSubdomains: make(map[time.Time]subdomain.Subdomain),
pendingDnsPropagation: pendingDnsPropagation,
providerName: providerName,
logger: logger,
providers: providers,
webIP: webIP,
firstRun: true,
providerName: w.Name,
}, nil
}
func (w *watcher) Run(t *time.Ticker, chClose chan struct{}, chErr chan error) {
logger := w.logger.WithField("component", "Run")
go w.checkPendingSubdomains(chClose)
if w.firstRun {
if err := w.runDDNSCheck(); err != nil {
chErr <- err
@ -77,7 +65,7 @@ func (w *watcher) Run(t *time.Ticker, chClose chan struct{}, chErr chan error) {
select {
case <-chClose:
t.Stop()
logger.Infoln("Close watcher channel triggered. Ticker stopped")
logger.WithField("provider", w.providerName).Infoln("Close watcher channel triggered. Ticker stopped")
return
case <-t.C:
if err := w.runDDNSCheck(); err != nil {
@ -92,64 +80,18 @@ func (w *watcher) runDDNSCheck() error {
logger.Infof("Starting [%s] DDNS check...\n", w.providerName)
logger.Debugln("Checking server IP...")
srvIP, err := utils.RetrieveServerIP(w.webIP)
if err != nil {
return err
}
logger.Debugln("Checking server IP...")
for _, sb := range w.subdomains {
if sb.SubIsPending(w.pendingSubdomains) {
continue
}
logger.Debugf("Checking subdomain %s...\n", sb.GetSubdomainAddr())
ok, err := sb.CheckIPAddr(srvIP)
if err != nil {
for _, p := range w.providers {
if err := p.UpdateSubdomains(srvIP); err != nil {
return err
}
subAddr := sb.GetSubdomainAddr()
if !ok {
logger.WithFields(logrus.Fields{
"server-ip": srvIP,
"subdomain-address": subAddr,
}).Infoln("IP addresses doesn't match. Updating subdomain's ip...")
if err := w.provider.UpdateIP(subAddr, srvIP); err != nil {
return err
}
logger.WithFields(logrus.Fields{
"server-ip": srvIP,
"subdomain-address": subAddr,
}).Infoln("Subdomain's ip updated! Removing from checks for 5 mins")
w.pendingSubdomains[time.Now()] = sb
continue
}
logger.Debugf("%s is up to date. \n", subAddr)
}
logger.Infof("[%s] DDNS check finished\n", w.providerName)
return nil
}
func (w *watcher) checkPendingSubdomains(chClose chan struct{}) {
logger := w.logger.WithField("component", "checkPendingSubdomains")
t := time.NewTicker(time.Second * time.Duration(w.pendingDnsPropagation))
logger.Debugln("Start checking for pending subdomains...")
for {
select {
case <-chClose:
logger.Debugln("Close pending subdomains")
return
case <-t.C:
logger.Debugln("Checking pending subdomains...")
if delSbs := subdomain.CheckPendingSubdomains(w.pendingSubdomains, time.Now()); delSbs != nil {
w.pendingSubdomains = subdomain.DeletePendingSubdomains(delSbs, w.pendingSubdomains)
logger.Debugln("Pendings subdomains found. Cleaned.")
}
}
}
}