ddnsclient/pkg/providers/google/main.go

100 lines
2.9 KiB
Go

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
}