Skip to content

Commit

Permalink
feat(notifier): add new Telegram notifier
Browse files Browse the repository at this point in the history
  • Loading branch information
aerialls committed Jun 28, 2020
1 parent 4cc6f43 commit d570e2c
Show file tree
Hide file tree
Showing 11 changed files with 384 additions and 163 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ dist/
# Test binary, built with `go test -c`
*.test

# Local binary
# Local testing
/scaleway-ddns
/config.yml

# Output of the go coverage tool, specifically when used with LiteIDE
*.out
63 changes: 0 additions & 63 deletions cmd/scaleway-ddns/dns.go

This file was deleted.

48 changes: 15 additions & 33 deletions cmd/scaleway-ddns/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ package main
import (
"fmt"
"os"
"time"

"github.com/aerialls/scaleway-ddns/config"
"github.com/aerialls/scaleway-ddns/ddns"
"github.com/aerialls/scaleway-ddns/notifier"
"github.com/aerialls/scaleway-ddns/scaleway"

"github.com/sirupsen/logrus"
Expand Down Expand Up @@ -41,39 +42,20 @@ var rootCmd = &cobra.Command{
logger.Fatal(err)
}

ticker := time.NewTicker(time.Duration(cfg.Interval) * time.Second)

for {
select {
case <-ticker.C:
logger.Debugf(
"updating A/AAAA records for %s.%s",
cfg.DomainConfig.Record,
cfg.DomainConfig.Name,
)

recordTypes := map[string]config.IPConfig{
"A": cfg.IPv4Config,
"AAAA": cfg.IPv6Config,
}

for recordType, recordCfg := range recordTypes {
err := UpdateDNSRecordFromCurrentIP(
dns,
cfg.DomainConfig,
recordCfg,
recordType,
dryRun,
)

if err != nil {
logger.WithError(err).Errorf(
"unable to update %s record", recordType,
)
}
}
}
// Create a container to store all objects in one place
container := config.NewContainer(logger, cfg, dns)

if cfg.TelegramConfig.Enabled {
tgCfg := cfg.TelegramConfig
container.AddNotifier(notifier.NewTelegram(
tgCfg.Token,
tgCfg.ChatID,
tgCfg.Template,
))
}

updater := ddns.NewDynamicDNSUpdater(container, dryRun)
updater.Start()
},
}

Expand Down
73 changes: 7 additions & 66 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,72 +7,6 @@ import (
"gopkg.in/yaml.v2"
)

const (
// IntervalMinValue is the lowest possible value between two updates (in sec)
IntervalMinValue = 60
)

// Config struct for the configuration file
type Config struct {
Interval uint `yaml:"interval"`
IPv4Config IPConfig `yaml:"ipv4"`
IPv6Config IPConfig `yaml:"ipv6"`
ScalewayConfig ScalewayConfig `yaml:"scaleway"`
DomainConfig DomainConfig `yaml:"domain"`
}

// IPConfig struct for the required configuration for IPv4 or IPv6
type IPConfig struct {
URL string `yaml:"url"`
Enabled bool `yaml:"enabled"`
}

// ScalewayConfig struct for the required configuration to use the Scaleway API
type ScalewayConfig struct {
OrganizationID string `yaml:"organization_id"`
AccessKey string `yaml:"access_key"`
SecretKey string `yaml:"secret_key"`
}

// DomainConfig struct for the domain parameters
type DomainConfig struct {
Name string `yaml:"name"`
Record string `yaml:"record"`
TTL uint32 `yaml:"ttl"`
}

var (
// DefaultIPv4Config is the default configuration for IPv4
DefaultIPv4Config = IPConfig{
URL: "https://api-ipv4.ip.sb/ip",
Enabled: true,
}

// DefaultIPv6Config is the default configuration for IPv6
DefaultIPv6Config = IPConfig{
URL: "https://api-ipv6.ip.sb/ip",
Enabled: false,
}

// DefaultScalewayConfig is the default configuration to use the Scaleway API
DefaultScalewayConfig = ScalewayConfig{}

// DefaultDomainConfig is the default domain configuration for common parameters
DefaultDomainConfig = DomainConfig{
Record: "ddns",
TTL: 60,
}

// DefaultConfig is the global default configuration.
DefaultConfig = Config{
Interval: 300,
DomainConfig: DefaultDomainConfig,
IPv4Config: DefaultIPv4Config,
IPv6Config: DefaultIPv6Config,
ScalewayConfig: DefaultScalewayConfig,
}
)

// NewConfig returns a new config object if the file exists
func NewConfig(path string) (*Config, error) {
data, err := ioutil.ReadFile(path)
Expand Down Expand Up @@ -112,5 +46,12 @@ func (c *Config) validate() error {
)
}

tgCfg := c.TelegramConfig
if tgCfg.Enabled && (tgCfg.Token == "" || tgCfg.ChatID == 0) {
return fmt.Errorf(
"token and chat_id are required for the Telegram notifier",
)
}

return nil
}
41 changes: 41 additions & 0 deletions config/container.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package config

import (
"github.com/aerialls/scaleway-ddns/scaleway"

"github.com/sirupsen/logrus"
)

// Notifier interface to represent any notifier
type Notifier interface {
Notify(domain string, record string, previousIP string, newIP string) error
}

// Container structure to hold global objects
type Container struct {
Logger *logrus.Logger
Config *Config
DNS *scaleway.DNS
Notifiers []Notifier
}

// NewContainer returns a new container instance
func NewContainer(
logger *logrus.Logger,
config *Config,
dns *scaleway.DNS,

) *Container {
return &Container{
Config: config,
Logger: logger,
DNS: dns,
Notifiers: []Notifier{},
}
}

// AddNotifier adds a new notifier into the container
func (c *Container) AddNotifier(notifier Notifier) {
c.Logger.Debugf("New notifier %T added", notifier)
c.Notifiers = append(c.Notifiers, notifier)
}
83 changes: 83 additions & 0 deletions config/data.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package config

const (
// IntervalMinValue is the lowest possible value between two updates (in sec)
IntervalMinValue = 60
)

// Config struct for the configuration file
type Config struct {
Interval uint `yaml:"interval"`
IPv4Config IPConfig `yaml:"ipv4"`
IPv6Config IPConfig `yaml:"ipv6"`
ScalewayConfig ScalewayConfig `yaml:"scaleway"`
DomainConfig DomainConfig `yaml:"domain"`
TelegramConfig TelegramConfig `yaml:"telegram"`
}

// IPConfig struct for the required configuration for IPv4 or IPv6
type IPConfig struct {
URL string `yaml:"url"`
Enabled bool `yaml:"enabled"`
}

// ScalewayConfig struct for the required configuration to use the Scaleway API
type ScalewayConfig struct {
OrganizationID string `yaml:"organization_id"`
AccessKey string `yaml:"access_key"`
SecretKey string `yaml:"secret_key"`
}

// DomainConfig struct for the domain parameters
type DomainConfig struct {
Name string `yaml:"name"`
Record string `yaml:"record"`
TTL uint32 `yaml:"ttl"`
}

// TelegramConfig struct for Telegram notifications after updates
type TelegramConfig struct {
Enabled bool `yaml:"enabled"`
Token string `yaml:"token"`
ChatID int64 `yaml:"chat_id"`
Template string `yaml:"template"`
}

var (
// DefaultIPv4Config is the default configuration for IPv4
DefaultIPv4Config = IPConfig{
URL: "https://api-ipv4.ip.sb/ip",
Enabled: true,
}

// DefaultIPv6Config is the default configuration for IPv6
DefaultIPv6Config = IPConfig{
URL: "https://api-ipv6.ip.sb/ip",
Enabled: false,
}

// DefaultScalewayConfig is the default configuration to use the Scaleway API
DefaultScalewayConfig = ScalewayConfig{}

// DefaultDomainConfig is the default domain configuration for common parameters
DefaultDomainConfig = DomainConfig{
Record: "ddns",
TTL: 60,
}

// DefaultTelegramConfig is the default configuration to use Telegram notifications
DefaultTelegramConfig = TelegramConfig{
Enabled: false,
Template: "DNS record *{{ .Record }}.{{ .Domain }}* has been updated from *{{ .PreviousIP }}* to *{{ .NewIP }}*",
}

// DefaultConfig is the global default configuration.
DefaultConfig = Config{
Interval: 300,
DomainConfig: DefaultDomainConfig,
IPv4Config: DefaultIPv4Config,
IPv6Config: DefaultIPv6Config,
ScalewayConfig: DefaultScalewayConfig,
TelegramConfig: DefaultTelegramConfig,
}
)
Loading

0 comments on commit d570e2c

Please sign in to comment.