diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml index 1e83015..4f2756c 100644 --- a/.github/workflows/go.yml +++ b/.github/workflows/go.yml @@ -25,7 +25,7 @@ jobs: - name: Set up Go 1.x uses: actions/setup-go@v2 with: - go-version: ^1.16 + go-version: ^1.17 - name: Check out code into the Go module directory uses: actions/checkout@v2 @@ -46,7 +46,7 @@ jobs: - name: Set up Go 1.x uses: actions/setup-go@v2 with: - go-version: ^1.16 + go-version: ^1.17 - name: Check out code into the Go module directory uses: actions/checkout@v2 diff --git a/Dockerfile b/Dockerfile index 7fb768e..96d3378 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM docker.io/library/golang:1.16 as builder +FROM docker.io/library/golang:1.17 as builder WORKDIR /go/src/app diff --git a/go.mod b/go.mod index 1635608..b91b2b2 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/bakito/adguardhome-sync -go 1.16 +go 1.17 require ( github.com/go-resty/resty/v2 v2.7.0 @@ -13,4 +13,26 @@ require ( github.com/spf13/cobra v1.3.0 github.com/spf13/viper v1.10.1 go.uber.org/zap v1.19.1 + golang.org/x/mod v0.5.0 +) + +require ( + github.com/fsnotify/fsnotify v1.5.1 // indirect + github.com/hashicorp/hcl v1.0.0 // indirect + github.com/inconshreveable/mousetrap v1.0.0 // indirect + github.com/magiconair/properties v1.8.5 // indirect + github.com/mitchellh/mapstructure v1.4.3 // indirect + github.com/pelletier/go-toml v1.9.4 // indirect + github.com/spf13/afero v1.6.0 // indirect + github.com/spf13/cast v1.4.1 // indirect + github.com/spf13/jwalterweatherman v1.1.0 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/subosito/gotenv v1.2.0 // indirect + go.uber.org/atomic v1.7.0 // indirect + go.uber.org/multierr v1.6.0 // indirect + golang.org/x/net v0.0.0-20211029224645-99673261e6eb // indirect + golang.org/x/sys v0.0.0-20211210111614-af8b64212486 // indirect + golang.org/x/text v0.3.7 // indirect + gopkg.in/ini.v1 v1.66.2 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect ) diff --git a/go.sum b/go.sum index c6ced32..e188bb4 100644 --- a/go.sum +++ b/go.sum @@ -436,6 +436,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.5.0 h1:UG21uOlmZabA4fW5i7ZX6bjw1xELEGg/ZLgZq9auk/Q= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= diff --git a/pkg/client/client.go b/pkg/client/client.go index 79979a9..aa465c8 100644 --- a/pkg/client/client.go +++ b/pkg/client/client.go @@ -65,7 +65,7 @@ type Client interface { DeleteRewriteEntries(e ...types.RewriteEntry) error Filtering() (*types.FilteringStatus, error) - ToggleFiltering(enabled bool, interval int) error + ToggleFiltering(enabled bool, interval float64) error AddFilters(whitelist bool, e ...types.Filter) error DeleteFilters(whitelist bool, e ...types.Filter) error UpdateFilters(whitelist bool, e ...types.Filter) error @@ -88,9 +88,9 @@ type Client interface { DeleteClients(client ...types.Client) error QueryLogConfig() (*types.QueryLogConfig, error) - SetQueryLogConfig(enabled bool, interval int, anonymizeClientIP bool) error + SetQueryLogConfig(enabled bool, interval float64, anonymizeClientIP bool) error StatsConfig() (*types.IntervalConfig, error) - SetStatsConfig(interval int) error + SetStatsConfig(interval float64) error Setup() error AccessList() (*types.AccessList, error) @@ -291,7 +291,7 @@ func (cl *client) SetCustomRules(rules types.UserRules) error { return cl.doPost(cl.client.R().EnableTrace().SetBody(rules.String()), "/filtering/set_rules") } -func (cl *client) ToggleFiltering(enabled bool, interval int) error { +func (cl *client) ToggleFiltering(enabled bool, interval float64) error { cl.log.With("enabled", enabled, "interval", interval).Info("Toggle filtering") return cl.doPost(cl.client.R().EnableTrace().SetBody(&types.FilteringConfig{ EnableConfig: types.EnableConfig{Enabled: enabled}, @@ -357,7 +357,7 @@ func (cl *client) QueryLogConfig() (*types.QueryLogConfig, error) { return qlc, err } -func (cl *client) SetQueryLogConfig(enabled bool, interval int, anonymizeClientIP bool) error { +func (cl *client) SetQueryLogConfig(enabled bool, interval float64, anonymizeClientIP bool) error { cl.log.With("enabled", enabled, "interval", interval, "anonymizeClientIP", anonymizeClientIP).Info("Set query log config") return cl.doPost(cl.client.R().EnableTrace().SetBody(&types.QueryLogConfig{ EnableConfig: types.EnableConfig{Enabled: enabled}, @@ -372,7 +372,7 @@ func (cl *client) StatsConfig() (*types.IntervalConfig, error) { return stats, err } -func (cl *client) SetStatsConfig(interval int) error { +func (cl *client) SetStatsConfig(interval float64) error { cl.log.With("interval", interval).Info("Set stats config") return cl.doPost(cl.client.R().EnableTrace().SetBody(&types.IntervalConfig{Interval: interval}), "/stats_config") } diff --git a/pkg/client/client_test.go b/pkg/client/client_test.go index 6deac00..4dfb045 100644 --- a/pkg/client/client_test.go +++ b/pkg/client/client_test.go @@ -265,7 +265,7 @@ bar`) qlc, err := cl.QueryLogConfig() Ω(err).ShouldNot(HaveOccurred()) Ω(qlc.Enabled).Should(BeTrue()) - Ω(qlc.Interval).Should(Equal(90)) + Ω(qlc.Interval).Should(Equal(90.0)) }) It("should set QueryLogConfig", func() { ts, cl = ClientPost("/querylog_config", `{"enabled":true,"interval":123,"anonymize_client_ip":true}`) @@ -278,11 +278,11 @@ bar`) ts, cl = ClientGet("stats_info.json", "/stats_info") sc, err := cl.StatsConfig() Ω(err).ShouldNot(HaveOccurred()) - Ω(sc.Interval).Should(Equal(1)) + Ω(sc.Interval).Should(Equal(1.0)) }) It("should set StatsConfig", func() { ts, cl = ClientPost("/stats_config", `{"interval":123}`) - err := cl.SetStatsConfig(123) + err := cl.SetStatsConfig(123.0) Ω(err).ShouldNot(HaveOccurred()) }) }) diff --git a/pkg/mocks/client/mock.go b/pkg/mocks/client/mock.go index 2b958d7..73859f5 100644 --- a/pkg/mocks/client/mock.go +++ b/pkg/mocks/client/mock.go @@ -430,7 +430,7 @@ func (mr *MockClientMockRecorder) SetDNSConfig(arg0 interface{}) *gomock.Call { } // SetQueryLogConfig mocks base method. -func (m *MockClient) SetQueryLogConfig(arg0 bool, arg1 int, arg2 bool) error { +func (m *MockClient) SetQueryLogConfig(arg0 bool, arg1 float64, arg2 bool) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SetQueryLogConfig", arg0, arg1, arg2) ret0, _ := ret[0].(error) @@ -458,7 +458,7 @@ func (mr *MockClientMockRecorder) SetServices(arg0 interface{}) *gomock.Call { } // SetStatsConfig mocks base method. -func (m *MockClient) SetStatsConfig(arg0 int) error { +func (m *MockClient) SetStatsConfig(arg0 float64) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "SetStatsConfig", arg0) ret0, _ := ret[0].(error) @@ -516,7 +516,7 @@ func (mr *MockClientMockRecorder) Status() *gomock.Call { } // ToggleFiltering mocks base method. -func (m *MockClient) ToggleFiltering(arg0 bool, arg1 int) error { +func (m *MockClient) ToggleFiltering(arg0 bool, arg1 float64) error { m.ctrl.T.Helper() ret := m.ctrl.Call(m, "ToggleFiltering", arg0, arg1) ret0, _ := ret[0].(error) diff --git a/pkg/sync/sync.go b/pkg/sync/sync.go index dfc9c36..245f5ec 100644 --- a/pkg/sync/sync.go +++ b/pkg/sync/sync.go @@ -10,8 +10,11 @@ import ( "github.com/bakito/adguardhome-sync/version" "github.com/robfig/cron/v3" "go.uber.org/zap" + "golang.org/x/mod/semver" ) +const minAghVersion = "v0.107.0" + var l = log.GetLogger("sync") // Sync config from origin to replica @@ -97,6 +100,11 @@ func (w *worker) sync() { return } + if semver.Compare(o.status.Version, minAghVersion) == -1 { + sl.With("error", err, "version", o.status.Version).Errorf("Origin AdGuard Home version must be >= %s", minAghVersion) + return + } + o.parental, err = oc.Parental() if err != nil { sl.With("error", err).Error("Error getting parental status") @@ -186,6 +194,11 @@ func (w *worker) syncTo(l *zap.SugaredLogger, o *origin, replica types.AdGuardIn return } + if semver.Compare(rs.Version, minAghVersion) == -1 { + rl.With("error", err, "version", rs.Version).Errorf("Replica AdGuard Home version must be >= %s", minAghVersion) + return + } + if o.status.Version != rs.Version { rl.With("originVersion", o.status.Version, "replicaVersion", rs.Version).Warn("Versions do not match") } diff --git a/pkg/sync/sync_test.go b/pkg/sync/sync_test.go index ab1084e..9576009 100644 --- a/pkg/sync/sync_test.go +++ b/pkg/sync/sync_test.go @@ -269,7 +269,7 @@ var _ = Describe("Sync", func() { It("should have QueryLogConfig changes", func() { o.queryLogConfig.Interval = 123 cl.EXPECT().QueryLogConfig().Return(qlc, nil) - cl.EXPECT().SetQueryLogConfig(false, 123, false) + cl.EXPECT().SetQueryLogConfig(false, 123.0, false) cl.EXPECT().StatsConfig().Return(sc, nil) err := w.syncConfigs(o, cl) Ω(err).ShouldNot(HaveOccurred()) @@ -278,7 +278,7 @@ var _ = Describe("Sync", func() { o.statsConfig.Interval = 123 cl.EXPECT().QueryLogConfig().Return(qlc, nil) cl.EXPECT().StatsConfig().Return(sc, nil) - cl.EXPECT().SetStatsConfig(123) + cl.EXPECT().SetStatsConfig(123.0) err := w.syncConfigs(o, cl) Ω(err).ShouldNot(HaveOccurred()) }) @@ -425,7 +425,7 @@ var _ = Describe("Sync", func() { }) Context("sync", func() { - It("should have no changes", func() { + BeforeEach(func() { w.cfg = &types.Config{ Origin: types.AdGuardInstance{}, Replica: types.AdGuardInstance{URL: "foo"}, @@ -447,9 +447,11 @@ var _ = Describe("Sync", func() { QueryLogConfig: true, }, } + }) + It("should have no changes", func() { // origin cl.EXPECT().Host() - cl.EXPECT().Status().Return(&types.Status{}, nil) + cl.EXPECT().Status().Return(&types.Status{Version: minAghVersion}, nil) cl.EXPECT().Parental() cl.EXPECT().SafeSearch() cl.EXPECT().SafeBrowsing() @@ -465,7 +467,7 @@ var _ = Describe("Sync", func() { // replica cl.EXPECT().Host() - cl.EXPECT().Status().Return(&types.Status{}, nil) + cl.EXPECT().Status().Return(&types.Status{Version: minAghVersion}, nil) cl.EXPECT().Parental() cl.EXPECT().SafeSearch() cl.EXPECT().SafeBrowsing() @@ -493,6 +495,34 @@ var _ = Describe("Sync", func() { cl.EXPECT().DeleteDHCPStaticLeases().Return(nil) w.sync() }) + It("origin version is too small", func() { + // origin + cl.EXPECT().Host() + cl.EXPECT().Status().Return(&types.Status{Version: "v0.106.9"}, nil) + w.sync() + }) + It("replica version is too small", func() { + // origin + cl.EXPECT().Host() + cl.EXPECT().Status().Return(&types.Status{Version: minAghVersion}, nil) + cl.EXPECT().Parental() + cl.EXPECT().SafeSearch() + cl.EXPECT().SafeBrowsing() + cl.EXPECT().RewriteList().Return(&types.RewriteEntries{}, nil) + cl.EXPECT().Services() + cl.EXPECT().Filtering().Return(&types.FilteringStatus{}, nil) + cl.EXPECT().Clients().Return(&types.Clients{}, nil) + cl.EXPECT().QueryLogConfig().Return(&types.QueryLogConfig{}, nil) + cl.EXPECT().StatsConfig().Return(&types.IntervalConfig{}, nil) + cl.EXPECT().AccessList().Return(&types.AccessList{}, nil) + cl.EXPECT().DNSConfig().Return(&types.DNSConfig{}, nil) + cl.EXPECT().DHCPServerConfig().Return(&types.DHCPServerConfig{}, nil) + + // replica + cl.EXPECT().Host() + cl.EXPECT().Status().Return(&types.Status{Version: "v0.106.9"}, nil) + w.sync() + }) }) }) }) diff --git a/pkg/types/types.go b/pkg/types/types.go index 47bbef4..6ef0383 100644 --- a/pkg/types/types.go +++ b/pkg/types/types.go @@ -215,7 +215,7 @@ type EnableConfig struct { // IntervalConfig API struct type IntervalConfig struct { - Interval int `json:"interval"` + Interval float64 `json:"interval"` } // FilteringConfig API struct