allow multiple replicas

This commit is contained in:
bakito 2021-03-28 16:03:34 +02:00
parent 3e25d2c70e
commit 794aa32bd3
No known key found for this signature in database
GPG key ID: FAF93C1C384DD6B4
4 changed files with 120 additions and 67 deletions

View file

@ -1,7 +1,6 @@
package cmd
import (
"github.com/bakito/adguardhome-sync/pkg/client"
"github.com/bakito/adguardhome-sync/pkg/log"
"github.com/bakito/adguardhome-sync/pkg/sync"
"github.com/bakito/adguardhome-sync/pkg/types"
@ -24,21 +23,7 @@ var doCmd = &cobra.Command{
return
}
origin, err := client.New(cfg.Origin)
if err != nil {
logger.Error(err)
return
}
replica, err := client.New(cfg.Replica)
if err != nil {
logger.Error(err)
return
}
err = sync.Sync(origin, replica)
if err != nil {
logger.Error(err)
return
}
sync.Sync(cfg)
},
}

View file

@ -65,7 +65,7 @@ type Client interface {
ToggleParental(enable bool) error
ToggleSafeSearch(enable bool) error
Services() (types.Services, error)
Services() (*types.Services, error)
SetServices(services types.Services) error
Clients() (*types.Clients, error)
@ -190,10 +190,10 @@ func (cl *client) ToggleFiltering(enabled bool, interval int) error {
return err
}
func (cl *client) Services() (types.Services, error) {
func (cl *client) Services() (*types.Services, error) {
svcs := &types.Services{}
_, err := cl.client.R().EnableTrace().SetResult(svcs).Get("/blocked_services/list")
return *svcs, err
return svcs, err
}
func (cl *client) SetServices(services types.Services) error {

View file

@ -3,73 +3,118 @@ package sync
import (
"github.com/bakito/adguardhome-sync/pkg/client"
"github.com/bakito/adguardhome-sync/pkg/log"
"github.com/bakito/adguardhome-sync/pkg/types"
"go.uber.org/zap"
)
// Sync config from origin to replica
func Sync(origin client.Client, replica client.Client) error {
l := log.GetLogger("sync").With("from", origin.Host(), "to", replica.Host())
l.Info("Start sync")
os, err := origin.Status()
func Sync(cfg *types.Config) {
l := log.GetLogger("sync")
oc, err := client.New(cfg.Origin)
if err != nil {
return err
l.With("error", err, "url", cfg.Origin.URL).Error("Error creating origin client")
return
}
rs, err := replica.Status()
l = l.With("from", oc.Host())
o := &origin{}
o.status, err = oc.Status()
if err != nil {
return err
l.With("error", err).Error("Error getting origin status")
return
}
if os.Version != rs.Version {
panic("Versions do not match")
}
err = syncRewrites(origin, replica)
o.rewrites, err = oc.RewriteList()
if err != nil {
return err
l.With("error", err).Error("Error getting origin rewrites")
return
}
err = syncFilters(origin, replica)
o.services, err = oc.Services()
if err != nil {
return err
l.With("error", err).Error("Error getting origin services")
return
}
err = syncServices(origin, replica)
o.filters, err = oc.Filtering()
if err != nil {
return err
l.With("error", err).Error("Error getting origin filters")
return
}
o.clients, err = oc.Clients()
if err != nil {
l.With("error", err).Error("Error getting origin clients")
return
}
if err = syncClients(origin, replica); err != nil {
return err
replicas := cfg.UniqueReplicas()
for _, replica := range replicas {
syncTo(l, o, replica)
}
l.Info("Sync done")
return nil
}
func syncServices(origin client.Client, replica client.Client) error {
os, err := origin.Services()
func syncTo(l *zap.SugaredLogger, o *origin, replica types.AdGuardInstance) {
rc, err := client.New(replica)
if err != nil {
return err
l.With("error", err, "url", replica.URL).Error("Error creating replica client")
}
rl := l.With("to", rc.Host())
rl.Info("Start sync")
rs, err := rc.Status()
if err != nil {
l.With("error", err).Error("Error getting replica status")
return
}
if o.status.Version != rs.Version {
l.With("originVersion", o.status.Version, "replicaVersion", rs.Version).Warn("Versions do not match")
}
err = syncRewrites(o.rewrites, rc)
if err != nil {
l.With("error", err).Error("Error syncing rewrites")
return
}
err = syncFilters(o.filters, rc)
if err != nil {
l.With("error", err).Error("Error syncing filters")
return
}
err = syncServices(o.services, rc)
if err != nil {
l.With("error", err).Error("Error syncing services")
return
}
if err = syncClients(o.clients, rc); err != nil {
l.With("error", err).Error("Error syncing clients")
return
}
rl.Info("Sync done")
}
func syncServices(os *types.Services, replica client.Client) error {
rs, err := replica.Services()
if err != nil {
return err
}
if !os.Equals(rs) {
if err := replica.SetServices(os); err != nil {
if err := replica.SetServices(*os); err != nil {
return err
}
}
return nil
}
func syncFilters(origin client.Client, replica client.Client) error {
of, err := origin.Filtering()
if err != nil {
return err
}
func syncFilters(of *types.FilteringStatus, replica client.Client) error {
rf, err := replica.Filtering()
if err != nil {
return err
@ -118,17 +163,14 @@ func syncFilters(origin client.Client, replica client.Client) error {
return nil
}
func syncRewrites(origin client.Client, replica client.Client) error {
originRewrites, err := origin.RewriteList()
if err != nil {
return err
}
func syncRewrites(or *types.RewriteEntries, replica client.Client) error {
replicaRewrites, err := replica.RewriteList()
if err != nil {
return err
}
a, r := replicaRewrites.Merge(originRewrites)
a, r := replicaRewrites.Merge(or)
if err = replica.AddRewriteEntries(a...); err != nil {
return err
@ -139,11 +181,7 @@ func syncRewrites(origin client.Client, replica client.Client) error {
return nil
}
func syncClients(origin client.Client, replica client.Client) error {
oc, err := origin.Clients()
if err != nil {
return err
}
func syncClients(oc *types.Clients, replica client.Client) error {
rc, err := replica.Clients()
if err != nil {
return err
@ -162,3 +200,11 @@ func syncClients(origin client.Client, replica client.Client) error {
}
return nil
}
type origin struct {
status *types.Status
rewrites *types.RewriteEntries
services *types.Services
filters *types.FilteringStatus
clients *types.Clients
}

View file

@ -9,8 +9,26 @@ import (
)
type Config struct {
Origin AdGuardInstance `json:"origin" yaml:"origin"`
Replica AdGuardInstance `json:"replica" yaml:"replica"`
Origin AdGuardInstance `json:"origin" yaml:"origin"`
Replica *AdGuardInstance `json:"replica,omitempty" yaml:"replica,omitempty"`
Replicas []AdGuardInstance `json:"replicas,omitempty" yaml:"replicas,omitempty"`
Cron string `json:"cron,omitempty" yaml:"cron,omitempty"`
}
func (cfg *Config) UniqueReplicas() []AdGuardInstance {
dedup := make(map[string]AdGuardInstance)
if cfg.Replica != nil {
dedup[cfg.Replica.Key()] = *cfg.Replica
}
for _, replica := range cfg.Replicas {
dedup[replica.Key()] = replica
}
var r []AdGuardInstance
for _, replica := range dedup {
r = append(r, replica)
}
return r
}
type AdGuardInstance struct {
@ -21,6 +39,10 @@ type AdGuardInstance struct {
InsecureSkipVerify bool `json:"insecureSkipVerify" yaml:"insecureSkipVerify"`
}
func (i *AdGuardInstance) Key() string {
return fmt.Sprintf("%s%s", i.URL, i.APIPath)
}
type Status struct {
DNSAddresses []string `json:"dns_addresses"`
DNSPort int `json:"dns_port"`
@ -131,10 +153,10 @@ func (s Services) Sort() {
sort.Strings(s)
}
func (s Services) Equals(o Services) bool {
func (s *Services) Equals(o *Services) bool {
s.Sort()
o.Sort()
return equals(s, o)
return equals(*s, *o)
}
type Clients struct {