refactor code
This commit is contained in:
parent
e366dd3613
commit
38c4a95b65
37
main.go
37
main.go
|
@ -1,6 +1,9 @@
|
|||
package ddnsclient
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/datahearth/ddnsclient/pkg/providers/ovh"
|
||||
|
@ -11,21 +14,43 @@ import (
|
|||
|
||||
// Start create a new instance of ddns-client
|
||||
func Start(logger logrus.FieldLogger) error {
|
||||
log := logger.WithFields(logrus.Fields{
|
||||
"pkg": "ddnsclient",
|
||||
"component": "root",
|
||||
})
|
||||
|
||||
log.Debugln("create OVH provider")
|
||||
ovh, err := ovh.NewOVH(logger)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
log.Debugln("creating watcher with OVH provider")
|
||||
w, err := watcher.NewWatcher(logger, ovh, viper.GetString("web-ip"))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
c := make(chan bool)
|
||||
go w.Run(c)
|
||||
for {
|
||||
|
||||
}
|
||||
sigc := make(chan os.Signal, 1)
|
||||
signal.Notify(sigc, syscall.SIGINT, syscall.SIGTERM, syscall.SIGQUIT)
|
||||
chClose := make(chan struct{})
|
||||
chErr := make(chan error)
|
||||
defer close(chClose)
|
||||
defer close(chErr)
|
||||
defer close(sigc)
|
||||
|
||||
return nil
|
||||
log.Infoln("Start watching periodically for changes!")
|
||||
go w.Run(time.NewTicker(viper.GetDuration("update-time")*time.Second), chClose, chErr)
|
||||
|
||||
for {
|
||||
select {
|
||||
case err := <-chErr:
|
||||
log.WithError(err).Errorln("An error occured while running the watcher. Retrying in the next tick")
|
||||
continue
|
||||
case <-sigc:
|
||||
log.Infoln("Interrupt signal received. Stopping watcher...")
|
||||
chClose <- struct{}{}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,23 +11,24 @@ import (
|
|||
)
|
||||
|
||||
type ovh struct {
|
||||
ovhConfig config
|
||||
ovhConfig utils.ProviderConfig
|
||||
logger logrus.FieldLogger
|
||||
}
|
||||
|
||||
// NewOVH returns a new instance of the OVH provider
|
||||
func NewOVH(logger logrus.FieldLogger) (providers.Provider, error) {
|
||||
var ovhConfig config
|
||||
if c, ok := viper.GetStringMap("provider")["ovh"].(config); ok {
|
||||
var ovhConfig utils.ProviderConfig
|
||||
if c, ok := viper.GetStringMap("provider")["ovh"].(utils.ProviderConfig); ok {
|
||||
ovhConfig = c
|
||||
} else {
|
||||
return nil, ErrNilOvhConfig
|
||||
return nil, utils.ErrNilOvhConfig
|
||||
}
|
||||
|
||||
if logger == nil {
|
||||
return nil, utils.ErrNilLogger
|
||||
}
|
||||
|
||||
logger = logger.WithField("pkg", "provider-ovh")
|
||||
|
||||
return &ovh{
|
||||
ovhConfig: ovhConfig,
|
||||
logger: logger,
|
||||
|
@ -37,11 +38,16 @@ func NewOVH(logger logrus.FieldLogger) (providers.Provider, error) {
|
|||
func (ovh *ovh) UpdateIP(subdomain, ip string) error {
|
||||
newURL := strings.ReplaceAll(ovh.ovhConfig["url"].(string), "SUBDOMAIN", subdomain)
|
||||
newURL = strings.ReplaceAll(newURL, "NEWIP", ip)
|
||||
logger := ovh.logger.WithFields(logrus.Fields{
|
||||
"component": "update-ip",
|
||||
"ovh-update-url": newURL,
|
||||
})
|
||||
|
||||
// * create GET request
|
||||
req, err := http.NewRequest("GET", newURL, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
logger.WithError(err).WithField("request-type", "GET").Errorln(utils.ErrCreateNewRequest.Error())
|
||||
return utils.ErrCreateNewRequest
|
||||
}
|
||||
req.SetBasicAuth(ovh.ovhConfig["username"].(string), ovh.ovhConfig["password"].(string))
|
||||
|
||||
|
@ -49,10 +55,11 @@ func (ovh *ovh) UpdateIP(subdomain, ip string) error {
|
|||
c := new(http.Client)
|
||||
resp, err := c.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
logger.WithError(err).Errorln(utils.ErrUpdateRequest.Error())
|
||||
return utils.ErrUpdateRequest
|
||||
}
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
logger.WithField("status-code", resp.StatusCode).Errorln(utils.ErrWrongStatusCode.Error())
|
||||
return utils.ErrWrongStatusCode
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
package ovh
|
||||
|
||||
import "errors"
|
||||
|
||||
type (
|
||||
config map[string]interface{}
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNilOvhConfig is thrown when OVH configuration is empty
|
||||
ErrNilOvhConfig = errors.New("OVH config is mandatory")
|
||||
)
|
|
@ -27,7 +27,7 @@ func NewSubdomain(logger logrus.FieldLogger, subdomainAddr string) (Subdomain, e
|
|||
return nil, utils.ErrNilLogger
|
||||
}
|
||||
|
||||
logger = logger.WithField("package", "http")
|
||||
logger = logger.WithField("pkg", "subdomain")
|
||||
|
||||
return &subdomain{
|
||||
logger: logger,
|
||||
|
@ -37,20 +37,25 @@ func NewSubdomain(logger logrus.FieldLogger, subdomainAddr string) (Subdomain, e
|
|||
|
||||
// RetrieveSubdomainIP will retrieve the subdomain IP with a HEAD request
|
||||
func (sd *subdomain) retrieveSubdomainIP() error {
|
||||
logger := sd.logger.WithField("component", "retrieve-subdomain-ip")
|
||||
|
||||
resp, err := h.Head(sd.subdomainAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
logger.WithError(err).WithField("subdomain", sd.subdomainAddr).Errorln(utils.ErrHeadRemoteIP.Error())
|
||||
return utils.ErrHeadRemoteIP
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
logger.WithField("status-code", resp.StatusCode).Errorln(utils.ErrWrongStatusCode.Error())
|
||||
return utils.ErrWrongStatusCode
|
||||
}
|
||||
|
||||
h, _, err := net.SplitHostPort(resp.Request.RemoteAddr)
|
||||
host, _, err := net.SplitHostPort(resp.Request.RemoteAddr)
|
||||
if err != nil {
|
||||
return err
|
||||
logger.WithError(err).WithField("remote-address", resp.Request.RemoteAddr).Errorln()
|
||||
return utils.ErrSplitAddr
|
||||
}
|
||||
|
||||
sd.ip = h
|
||||
sd.ip = host
|
||||
|
||||
return nil
|
||||
}
|
||||
|
@ -58,6 +63,7 @@ func (sd *subdomain) retrieveSubdomainIP() error {
|
|||
// CheckIPAddr will compare the srvIP passed in parameter and the subIP retrieved from the head request
|
||||
func (sd *subdomain) CheckIPAddr(srvIP string) (bool, error) {
|
||||
if err := sd.retrieveSubdomainIP(); err != nil {
|
||||
sd.logger.WithError(err).WithField("component", "check-ip-address").Errorln("failed to retrieve subdomain ip address")
|
||||
return false, err
|
||||
}
|
||||
|
||||
|
|
|
@ -2,11 +2,34 @@ package utils
|
|||
|
||||
import "errors"
|
||||
|
||||
// * Errors
|
||||
var (
|
||||
// ErrReadConfigFile is thrown when viper failed to read config file
|
||||
ErrReadConfigFile = errors.New("failed to read config file")
|
||||
// ErrNilLogger is thrown when the parameter logger is nil
|
||||
ErrNilLogger = errors.New("logger can't be nil")
|
||||
ErrNilLogger = errors.New("logger is mandatory")
|
||||
// ErrNilOvhConfig is thrown when OVH configuration is empty
|
||||
ErrNilOvhConfig = errors.New("OVH config is mandatory")
|
||||
// ErrNilProvider ...
|
||||
ErrNilProvider = errors.New("provider is mandatory")
|
||||
// ErrNilHTTP ...
|
||||
ErrNilHTTP = errors.New("http is mandatory")
|
||||
// ErrWrongStatusCode is thrown when the response status code isn't a 200
|
||||
ErrWrongStatusCode = errors.New("response sent an non 200 status code")
|
||||
// ErrGetServerIP is thrown when HTTP can't contact the web-ip service
|
||||
ErrGetServerIP = errors.New("failed to fetch server IP")
|
||||
// ErrParseHTTPBody is thrown when the HTTP service can't parse the body response
|
||||
ErrParseHTTPBody = errors.New("can't parse response body")
|
||||
// ErrHeadRemoteIP ...
|
||||
ErrHeadRemoteIP = errors.New("failed to fetch subdomain informations with HEAD")
|
||||
// ErrSplitAddr ...
|
||||
ErrSplitAddr = errors.New("can't split subdomain remote IP address")
|
||||
// ErrCreateNewRequest ...
|
||||
ErrCreateNewRequest = errors.New("can't create http request")
|
||||
// ErrUpdateRequest ...
|
||||
ErrUpdateRequest = errors.New("failed to set new IP address")
|
||||
)
|
||||
|
||||
type (
|
||||
ProviderConfig map[string]interface{}
|
||||
)
|
||||
|
|
|
@ -64,20 +64,31 @@ func AggregateSubdomains(subdomains []string, domain string) []string {
|
|||
}
|
||||
|
||||
// RetrieveServerIP will use the defined web-ip service to get the server public address and save it to the struct
|
||||
func RetrieveServerIP(webIP) (string, error) {
|
||||
func RetrieveServerIP(webIP string) (string, error) {
|
||||
logger := logrus.WithFields(logrus.Fields{
|
||||
"pkg": "utils",
|
||||
"component": "server-ip",
|
||||
})
|
||||
|
||||
// * retrieve client's server IP
|
||||
resp, err := http.Get(webIP)
|
||||
if err != nil {
|
||||
return "", err
|
||||
logger.WithError(err).WithField("web-ip", webIP).Errorln(ErrGetServerIP.Error())
|
||||
return "", ErrGetServerIP
|
||||
}
|
||||
if resp.StatusCode != 200 {
|
||||
logger.WithError(err).WithFields(logrus.Fields{
|
||||
"web-ip": webIP,
|
||||
"statuc-code": resp.StatusCode,
|
||||
}).Errorln(ErrWrongStatusCode.Error())
|
||||
return "", ErrWrongStatusCode
|
||||
}
|
||||
|
||||
// * get ip from body
|
||||
d, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return "", err
|
||||
logger.WithError(err).WithField("web-ip", webIP).Errorln(ErrParseHTTPBody.Error())
|
||||
return "", ErrParseHTTPBody
|
||||
}
|
||||
|
||||
return string(d), nil
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
package watcher
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
ErrNilProvider = errors.New("provider can't be nil")
|
||||
ErrNilHTTP = errors.New("http can't be nil")
|
||||
)
|
|
@ -1,6 +1,8 @@
|
|||
package watcher
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/datahearth/ddnsclient/pkg/providers"
|
||||
"github.com/datahearth/ddnsclient/pkg/subdomain"
|
||||
"github.com/datahearth/ddnsclient/pkg/utils"
|
||||
|
@ -9,7 +11,7 @@ import (
|
|||
)
|
||||
|
||||
type Watcher interface {
|
||||
Run(chan bool) error
|
||||
Run(*time.Ticker, chan struct{}, chan error)
|
||||
}
|
||||
|
||||
type watcher struct {
|
||||
|
@ -25,11 +27,13 @@ func NewWatcher(logger logrus.FieldLogger, provider providers.Provider, webIP st
|
|||
return nil, utils.ErrNilLogger
|
||||
}
|
||||
if provider == nil {
|
||||
return nil, ErrNilProvider
|
||||
return nil, utils.ErrNilProvider
|
||||
}
|
||||
if webIP == "" {
|
||||
webIP = "http://dynamicdns.park-your-domain.com/getip"
|
||||
}
|
||||
logger = logger.WithField("pkg", "watcher")
|
||||
|
||||
domain := viper.GetStringMap("watcher")["domain"].(string)
|
||||
sbs := utils.AggregateSubdomains(viper.GetStringMap("watcher")["subdomains"].([]string), domain)
|
||||
subdomains := make([]subdomain.Subdomain, len(sbs))
|
||||
|
@ -51,24 +55,49 @@ func NewWatcher(logger logrus.FieldLogger, provider providers.Provider, webIP st
|
|||
}, nil
|
||||
}
|
||||
|
||||
func (w *watcher) Run(close chan bool) error {
|
||||
func (w *watcher) Run(t *time.Ticker, chClose chan struct{}, chErr chan error) {
|
||||
logger := w.logger.WithField("component", "run")
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-close:
|
||||
return nil
|
||||
default:
|
||||
case <-chClose:
|
||||
t.Stop()
|
||||
logger.Infoln("Close watcher channel triggered. Ticker stoped")
|
||||
return
|
||||
case <-t.C:
|
||||
logger.Infoln("Starting DDNS check")
|
||||
srvIP, err := utils.RetrieveServerIP(w.webIP)
|
||||
if err != nil {
|
||||
return err
|
||||
chErr <- err
|
||||
continue
|
||||
}
|
||||
|
||||
logger.WithField("server-ip", srvIP).Debugln("Server IP retrieved. Checking subdomains...")
|
||||
for _, sd := range w.subdomains {
|
||||
ok, err := sd.CheckIPAddr(srvIP)
|
||||
if err != nil {
|
||||
return err
|
||||
logger.WithError(err).WithField("server-ip", srvIP).Errorln("failed to check ip addresses")
|
||||
chErr <- err
|
||||
continue
|
||||
}
|
||||
if !ok {
|
||||
w.provider.UpdateIP(sd.GetSubdomainIP(), srvIP)
|
||||
subIP := sd.GetSubdomainIP()
|
||||
logger.WithFields(logrus.Fields{
|
||||
"server-ip": srvIP,
|
||||
"subdomain-ip": subIP,
|
||||
}).Infoln("IP addresses doesn't match. Updating subdomain's ip...")
|
||||
if err := w.provider.UpdateIP(subIP, srvIP); err != nil {
|
||||
logger.WithError(err).WithFields(logrus.Fields{
|
||||
"server-ip": srvIP,
|
||||
"subdomain-ip": subIP,
|
||||
}).Errorln("failed to update subdomain's ip")
|
||||
chErr <- err
|
||||
continue
|
||||
}
|
||||
logger.WithFields(logrus.Fields{
|
||||
"server-ip": srvIP,
|
||||
"subdomain-ip": subIP,
|
||||
}).Infoln("Subdomain updated successfully!")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue