Compare commits

...

143 Commits

Author SHA1 Message Date
bakito
01dbf8e50a regenerate model for v0.107.57 2025-02-21 19:55:24 +01:00
Marc Brugger
58d0302c74 chore(deps): update dependency adguardteam/adguardhome to v0.107.57 (#506)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2025-02-21 07:24:16 +01:00
Marc Brugger
90ea6a13de chore(deps): update module github.com/prometheus/client_golang to v1.21.0 (#505)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2025-02-20 07:16:22 +01:00
bakito
4f80a7979f test: format code on running tests 2025-02-19 08:07:38 +01:00
Marc Brugger
3812101c25 chore(deps): update module github.com/spf13/cobra to v1.9.1 (#503)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2025-02-17 08:08:50 +01:00
Marc Brugger
8c79c8b32d test: extened faker config (#502) 2025-02-15 22:39:53 +01:00
Marc Brugger
0afc437252 chore(deps): update module github.com/santhosh-tekuri/jsonschema/v5 to v6 (#501)
* chore(deps): update module github.com/santhosh-tekuri/jsonschema/v5 to v6

* Update validate.go

---------

Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2025-02-15 22:13:01 +01:00
Marc Brugger
6ae53fea6e chore(deps): update module github.com/spf13/cobra to v1.9.0 (#500)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2025-02-15 21:33:37 +01:00
Marc Brugger
d925ccf45a feat: add yaml config file schema validation (#499) 2025-02-15 21:27:52 +01:00
Marc Brugger
24243a4b4d chore(deps): update module github.com/golangci/golangci-lint/cmd/golangci-lint to v1.64.5 (#496)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2025-02-15 10:45:27 +01:00
Marc Brugger
ef9ebc29b7 chore(deps): update k8s to v0.32.2 (#498)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2025-02-15 10:37:19 +01:00
Marc Brugger
bd4e0f2b28 chore(deps): update module github.com/goreleaser/goreleaser/v2 to v2.7.0 (#494)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2025-02-12 08:11:48 +01:00
Marc Brugger
e952c9f85a chore(deps): update module github.com/golangci/golangci-lint/cmd/golangci-lint to v1.64.2 (#495)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2025-02-12 08:11:39 +01:00
Marc Brugger
df67e9a0bd chore(deps): update module golang.org/x/mod to v0.23.0 (#492)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2025-02-05 21:25:51 +01:00
bakito
7e47ed0879 regenerate model for v0.107.56 2025-02-01 11:23:19 +01:00
Marc Brugger
1952ec1527 chore(deps): update dependency adguardteam/adguardhome to v0.107.56 (#490)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2025-02-01 09:52:03 +01:00
Marc Brugger
9ca5205d6a chore(deps): update module github.com/go-resty/resty/v2 to v2.16.5 (#491)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2025-01-28 22:41:52 +01:00
Marc Brugger
8a8da9d162 chore(deps): update module github.com/goreleaser/goreleaser/v2 to v2.6.1 (#489)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2025-01-23 22:56:08 +01:00
Marc Brugger
6440c71492 chore(deps): update module github.com/go-resty/resty/v2 to v2.16.4 (#488)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2025-01-20 22:10:49 +01:00
Marc Brugger
0b66b2debb chore(deps): update module github.com/go-resty/resty/v2 to v2.16.3 (#484)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2025-01-20 21:27:27 +01:00
Marc Brugger
351c142b91 chore(deps): update k8s to v0.32.1 (#486)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2025-01-20 21:27:13 +01:00
Marc Brugger
8ce6aed66f chore(deps): update module github.com/onsi/ginkgo/v2 to v2.22.2 (#480)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2025-01-07 18:30:49 +01:00
Marc Brugger
778d18d816 chore(deps): update module github.com/goreleaser/goreleaser/v2 to v2.5.1 (#482)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2025-01-07 18:30:38 +01:00
Marc Brugger
2ea436bbbc chore(deps): update module github.com/golangci/golangci-lint/cmd/golangci-lint to v1.63.4 (#481)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2025-01-07 18:30:14 +01:00
Marc Brugger
b5a820b6f4 cancel in progress actions (#483) 2025-01-07 18:29:51 +01:00
Marc Brugger
37f5043493 chore(deps): update module github.com/onsi/gomega to v1.36.2 (#476)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-12-30 14:18:26 +01:00
Marc Brugger
7638fb75a3 Update .goreleaser.yml (#478) 2024-12-29 11:54:24 +01:00
bakito
fdad6d3b7b update golang.org/x/net 2024-12-28 10:58:40 +01:00
Marc Brugger
074e300974 Format code with golines (#475) 2024-12-23 08:19:45 +01:00
Marc Brugger
523e068195 run on start if api disabled and cron enabled (#474) 2024-12-23 08:16:19 +01:00
Marc Brugger
9a7c617311 chore(deps): update module github.com/onsi/ginkgo/v2 to v2.22.1 (#471)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-12-23 08:15:29 +01:00
Marc Brugger
c214899b75 chore(deps): update module github.com/caarlos0/env/v11 to v11.3.1 (#472)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-12-23 08:15:13 +01:00
Marc Brugger
e31a8c8064 Correct webpage styling (#469) 2024-12-18 08:33:36 +01:00
bakito
31cc27df1b check for nil in stats 2024-12-18 08:15:44 +01:00
Marc Brugger
d60051b5cb remove golang.org/x/exp dependency (#467) 2024-12-17 20:43:18 +01:00
Marc Brugger
6770ae2a99 chore(deps): update module github.com/caarlos0/env/v11 to v11.3.0 (#465)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-12-17 06:40:43 +01:00
Marc Brugger
84738809ef chore(deps): update golang.org/x/exp digest to 4a55095 (#463)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-12-16 07:30:16 +01:00
Marc Brugger
43a08f7eef chore(deps): update module github.com/goreleaser/goreleaser/v2 to v2.5.0 (#464)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-12-16 07:30:06 +01:00
Marc Brugger
89aeec5f97 Draw also stats of single instances in dashboard diagram (#462)
* allow multiple graphs

* draw single instances
2024-12-15 12:06:09 +01:00
Marc Brugger
00ee5415a5 chore(deps): update k8s.io/utils digest to 24370be (#460)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-12-14 23:56:56 +01:00
Marc Brugger
b5bd79b61e Update README.md add API_METRICS_ENABLED 2024-12-14 22:28:14 +01:00
Marc Brugger
7080c236eb Show aggregated stats in web UI (#459) 2024-12-14 19:28:11 +01:00
Marc Brugger
bb073eb51e chore(deps): update dependency adguardteam/adguardhome to v0.107.55 (#455)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-12-12 07:18:25 +01:00
dependabot[bot]
7372d49aca build(deps): bump golang.org/x/crypto from 0.30.0 to 0.31.0 (#457)
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.30.0 to 0.31.0.
- [Commits](https://github.com/golang/crypto/compare/v0.30.0...v0.31.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-12-12 07:17:34 +01:00
Marc Brugger
1d771d4a0a chore(deps): update k8s to v0.32.0 (#456)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-12-12 06:45:35 +01:00
Marc Brugger
dcffdbd98e chore(deps): update golang.org/x/exp digest to 1829a12 (#453)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-12-11 13:32:02 +01:00
Marc Brugger
abcc2e4125 chore(deps): update module github.com/onsi/gomega to v1.36.1 (#452)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-12-11 13:31:51 +01:00
Marc Brugger
e453381382 chore(deps): update k8s to v0.31.4 (#454)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-12-11 13:31:39 +01:00
Marc Brugger
9a9913998a chore(deps): update golang.org/x/exp digest to 43b7b7c (#451)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-12-06 11:37:24 +01:00
Marc Brugger
a3cdb66fe6 chore(deps): update module github.com/onsi/gomega to v1.36.0 (#444)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-11-26 06:45:08 +01:00
Marc Brugger
39aa84e2fd chore(deps): update module github.com/golangci/golangci-lint/cmd/golangci-lint to v1.62.2 (#449)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-11-26 06:20:41 +01:00
Marc Brugger
1ec2270eb5 Delete .github/dependabot.yml 2024-11-25 07:10:51 +01:00
dependabot[bot]
5d1ee9b538 build(deps): bump github.com/onsi/ginkgo/v2 in the onsi group (#447)
Bumps the onsi group with 1 update: [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo).


Updates `github.com/onsi/ginkgo/v2` from 2.21.0 to 2.22.0
- [Release notes](https://github.com/onsi/ginkgo/releases)
- [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/ginkgo/compare/v2.21.0...v2.22.0)

---
updated-dependencies:
- dependency-name: github.com/onsi/ginkgo/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: onsi
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-25 07:06:55 +01:00
Marc Brugger
03d3cf57e9 chore(deps): update module github.com/goreleaser/goreleaser/v2 to v2.4.8 (#438)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-11-25 06:52:10 +01:00
dependabot[bot]
2a5465ddb0 build(deps): bump dcarbone/install-jq-action from 2 to 3 (#441)
Bumps [dcarbone/install-jq-action](https://github.com/dcarbone/install-jq-action) from 2 to 3.
- [Release notes](https://github.com/dcarbone/install-jq-action/releases)
- [Commits](https://github.com/dcarbone/install-jq-action/compare/v2...v3)

---
updated-dependencies:
- dependency-name: dcarbone/install-jq-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-25 06:52:02 +01:00
Marc Brugger
84efc786d4 chore(deps): update dcarbone/install-jq-action action to v3 (#442)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-11-25 06:51:45 +01:00
Marc Brugger
12e5fb6f7f chore(deps): update k8s to v0.31.3 (#445)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-11-25 06:51:17 +01:00
dependabot[bot]
5c66900fdb build(deps): bump github.com/go-resty/resty/v2 from 2.16.0 to 2.16.2 (#448)
Bumps [github.com/go-resty/resty/v2](https://github.com/go-resty/resty) from 2.16.0 to 2.16.2.
- [Release notes](https://github.com/go-resty/resty/releases)
- [Commits](https://github.com/go-resty/resty/compare/v2.16.0...v2.16.2)

---
updated-dependencies:
- dependency-name: github.com/go-resty/resty/v2
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-11-25 06:50:51 +01:00
Jeremy Diaz
2710ead089 Updated README.md (#440)
Co-authored-by: diaznet <jd@diaznet.fr>
2024-11-16 12:56:29 +01:00
Marc Brugger
839aa420e0 chore(deps): update module github.com/go-resty/resty/v2 to v2.16.0 (#436)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-11-11 07:04:24 +01:00
Marc Brugger
4ee42d4092 chore(deps): update module github.com/golangci/golangci-lint/cmd/golangci-lint to v1.62.0 (#437)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-11-11 07:04:13 +01:00
Marc Brugger
b2950f0718 chore(deps): update golang.org/x/exp digest to 2d47ceb (#434)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-11-09 10:35:54 +01:00
Marc Brugger
7b1793476d chore(deps): update dependency adguardteam/adguardhome to v0.107.54 (#432)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-11-08 18:54:34 +01:00
Marc Brugger
f8750ef231 chore(deps): update module golang.org/x/mod to v0.22.0 (#433)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-11-08 07:03:48 +01:00
Marc Brugger
cc9283530f chore(deps): update module github.com/goreleaser/goreleaser/v2 to v2.4.4 (#431)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-11-05 06:21:07 +01:00
Marc Brugger
5a61e56766 chore(deps): update module github.com/goreleaser/goreleaser/v2 to v2.4.3 (#430)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-11-04 21:27:27 +01:00
Marc Brugger
8f71d514ee chore(deps): update module github.com/goreleaser/goreleaser/v2 to v2.4.1 (#429)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-11-02 21:34:53 +01:00
Marc Brugger
1b122b228f chore(deps): update module github.com/onsi/gomega to v1.35.1 (#428)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-11-01 08:26:02 +01:00
Marc Brugger
e88c0cdd38 Update README.md (#427) 2024-10-30 22:04:44 +01:00
Marc Brugger
3ceb188b81 chore(deps): update onsi (#425)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-10-30 07:37:29 +01:00
Marc Brugger
0bc52ecb3c chore(deps): update k8s to v0.31.2 (#424)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-10-24 07:21:34 +02:00
Marc Brugger
36d6c37df3 chore(deps): update module go.uber.org/mock to v0.5.0 (#422)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-10-18 09:38:01 +02:00
Marc Brugger
8fd793fdab chore(deps): update module go.uber.org/mock/mockgen to v0.5.0 (#423)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-10-18 09:37:52 +02:00
Marc Brugger
be1909aedb chore(deps): update module github.com/prometheus/client_golang to v1.20.5 (#421)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-10-16 07:29:55 +02:00
Marc Brugger
e83b4d84ec chore(deps): update golang.org/x/exp digest to f66d83c (#420)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-10-09 23:43:54 +02:00
Marc Brugger
b39b3f38fe print ignored error count (#419)
* print ignored error count
2024-10-05 16:28:40 +02:00
bakito
d50765925b delete Taskfile.yml 2024-10-05 11:03:04 +02:00
Marc Brugger
e0f8971155 Sync DNS settings before filters (#418) 2024-10-05 10:59:12 +02:00
Marc Brugger
f1d53f5610 chore(deps): update golang.org/x/exp digest to 225e2ab (#417)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-10-05 09:01:17 +02:00
Marc Brugger
4b4e6b1c72 ignore more errors (#416) 2024-10-03 22:07:01 +02:00
Marc Brugger
095af716c9 chore(deps): update dependency adguardteam/adguardhome to v0.107.53 (#415)
* chore(deps): update dependency adguardteam/adguardhome to v0.107.53

* update schema

---------

Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-10-03 18:45:25 +02:00
bakito
e4e9f050df track AdGuardHome with renovate 2024-10-03 18:30:28 +02:00
bakito
638b9b9428 upgrade toolbox 2024-09-28 15:07:17 +02:00
Marc Brugger
0d4d18c595 chore(deps): update module github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen to v2.4.1 (#414)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-09-28 15:04:13 +02:00
bakito
33350c168d go mod tidy 2024-09-28 09:05:51 +02:00
bakito
1bbb882225 cleanup renovate config 2024-09-28 08:59:41 +02:00
bakito
6e86e8e5c5 correct renovate config regex 2024-09-28 08:57:57 +02:00
bakito
7cb4c8793a update renovate config 2024-09-28 08:46:39 +02:00
Marc Brugger
4d2c636d9b Upgrade to Go 1.23 (#413)
* Update Dockerfile
* Update go.mod
* Update .goreleaser.yml
* Update AdGuardHome.yaml
2024-09-27 21:15:21 +02:00
bakito
9895d6de43 update makefile dependencies 2024-09-27 18:47:32 +02:00
Marc Brugger
f62b6f94c5 chore(deps): update module github.com/go-resty/resty/v2 to v2.15.3 (#412)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-09-26 23:16:19 +02:00
Marc Brugger
e00d9a6c59 #403 add feature to disable theme sync (#411) 2024-09-22 21:24:20 +02:00
Marc Brugger
d2e573bbed chore(deps): update module github.com/go-resty/resty/v2 to v2.15.2 (#409)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-09-22 07:36:51 +02:00
Marc Brugger
8c0b6ee70d chore(deps): update module github.com/go-resty/resty/v2 to v2.15.1 (#408)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-09-20 06:45:23 +02:00
Marc Brugger
b9c7b1f559 chore(deps): update module github.com/prometheus/client_golang to v1.20.4 (#407)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-09-18 11:28:04 +02:00
Marc Brugger
7b5b876b0c chore(deps): update module github.com/go-resty/resty/v2 to v2.15.0 (#406)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-09-15 13:56:06 +02:00
Marc Brugger
848fb50132 chore(deps): update module k8s.io/apimachinery to v0.31.1 (#405)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-09-13 06:30:04 +02:00
Marc Brugger
6206402cae chore(deps): update golang.org/x/exp digest to 701f63a (#404)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-09-10 07:18:49 +02:00
Marc Brugger
b24dc91ef2 chore(deps): update module golang.org/x/mod to v0.21.0 (#401)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-09-06 00:18:13 +02:00
Marc Brugger
d2d58f9058 chore(deps): update module github.com/prometheus/client_golang to v1.20.3 (#402)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-09-06 00:18:01 +02:00
Marc Brugger
e6fb75f715 chore(deps): update golang.org/x/exp digest to e7e105d (#400)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-09-05 07:37:23 +02:00
bakito
3b31049636 correct cron description and add video section to Readme #398 2024-08-29 19:30:38 +02:00
Marc Brugger
5db091d800 chore(deps): update onsi (#399)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-08-29 06:47:25 +02:00
Marc Brugger
8278ecb6a2 chore(deps): update module github.com/prometheus/client_golang to v1.20.2 (#397)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-08-23 21:51:21 +02:00
Marc Brugger
084eeba24a chore(deps): update golang.org/x/exp digest to 9b4947d (#396)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-08-23 07:00:03 +02:00
Marc Brugger
0134840300 chore(deps): update golang.org/x/exp digest to 778ce7b (#395)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-08-22 20:23:40 +02:00
Marc Brugger
05335aaf3f chore(deps): update module github.com/onsi/ginkgo/v2 to v2.20.1 (#394)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-08-22 07:09:14 +02:00
Marc Brugger
fb38741036 chore(deps): update module github.com/prometheus/client_golang to v1.20.1 (#393)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-08-21 07:07:47 +02:00
Marc Brugger
5a07feaffd chore(deps): update module github.com/prometheus/client_golang to v1.20.0 (#392)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-08-14 18:26:21 +02:00
Marc Brugger
e555c287bf chore(deps): update module k8s.io/apimachinery to v0.31.0 (#390)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-08-13 19:06:53 +02:00
Marc Brugger
ad52f32a3b chore(deps): update module github.com/caarlos0/env/v11 to v11.2.2 (#380)
* chore(deps): update module github.com/caarlos0/env/v11 to v11.2.2

* fix replica handling

---------

Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-08-09 10:10:32 +02:00
bakito
665b27cfbe cleanup dependencies 2024-08-09 09:24:23 +02:00
Marc Brugger
871d558ffd chore(deps): update golang.org/x/exp digest to 0cdaa3a (#388)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-08-09 08:46:05 +02:00
Marc Brugger
881e00e7e3 chore(deps): update module github.com/onsi/ginkgo/v2 to v2.20.0 (#386)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-08-08 08:02:08 +02:00
Marc Brugger
29963b9d75 chore(deps): update module golang.org/x/mod to v0.20.0 (#385)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-08-05 23:20:26 +02:00
Marc Brugger
bea8ec2d98 chore(deps): update module github.com/go-resty/resty/v2 to v2.14.0 (#384)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-08-05 23:20:01 +02:00
Marc Brugger
851f5fad58 chore(deps): update module github.com/onsi/gomega to v1.34.1 (#379)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-07-30 07:59:58 +02:00
Marc Brugger
1125837420 chore(deps): update module github.com/onsi/ginkgo/v2 to v2.19.1 (#378)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-07-27 08:09:13 +02:00
Marc Brugger
34f9a13da3 chore(deps): update module github.com/onsi/gomega to v1.34.0 (#376)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-07-25 20:14:34 +02:00
Marc Brugger
1432ab4b52 Build more archs (#375)
* Build more archs
2024-07-24 08:59:36 +02:00
Marc Brugger
8f3a8e3572 Build image for linux/arm/v8 #372 (#374) 2024-07-23 20:25:55 +02:00
Marc Brugger
87d5903cfc extend bug issue template with os info (#373) 2024-07-23 06:38:36 +02:00
Marc Brugger
a50639af23 chore(deps): update module github.com/caarlos0/env/v10 to v11 (#371)
* chore(deps): update module github.com/caarlos0/env/v10 to v11

* update code

---------

Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-07-22 00:02:14 +02:00
Marc Brugger
c4b1a70dac chore(deps): update module k8s.io/apimachinery to v0.30.3 (#369)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-07-21 23:27:02 +02:00
Marc Brugger
94677c7a39 chore(deps): update golang.org/x/exp digest to 8a7402a (#368)
* chore(deps): update golang.org/x/exp digest to 8a7402a

---------

Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-07-21 23:22:31 +02:00
Marc Brugger
cd2295ef05 Add renovate.json (#367)
Co-authored-by: Renovate Bot <renovate@whitesourcesoftware.com>
2024-07-21 23:14:45 +02:00
bakito
944bb42074 update schema base version 2024-07-08 21:30:10 +02:00
bakito
1350364804 allow e2e test bin files in .gitognore 2024-07-08 21:25:34 +02:00
Marc Brugger
3625395d32 print e2e logs (#365)
* keep origin pre and post logs

* print origin pre and post logs
2024-07-08 21:23:08 +02:00
dependabot[bot]
c32ed90a2e Bump golang.org/x/mod from 0.18.0 to 0.19.0 (#363)
Bumps [golang.org/x/mod](https://github.com/golang/mod) from 0.18.0 to 0.19.0.
- [Commits](https://github.com/golang/mod/compare/v0.18.0...v0.19.0)

---
updated-dependencies:
- dependency-name: golang.org/x/mod
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-07-08 21:05:43 +02:00
Marc Brugger
9af8c00bca fix e2e test for newes agh version (#364) 2024-07-08 20:58:34 +02:00
bakito
0af476ac8e update tools 2024-07-03 07:14:23 +02:00
dependabot[bot]
3b58e8ce3c Bump docker/build-push-action from 5 to 6 (#362)
Bumps [docker/build-push-action](https://github.com/docker/build-push-action) from 5 to 6.
- [Release notes](https://github.com/docker/build-push-action/releases)
- [Commits](https://github.com/docker/build-push-action/compare/v5...v6)

---
updated-dependencies:
- dependency-name: docker/build-push-action
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-24 07:01:37 +02:00
Wei Feng
1fffb80066 docs: add "Run as Linux Service via Systemd" to README (#359)
* docs: add "Run as Linux Service via Systemd" to README

* fix: update config file anchor

* chore: add a section on testing details

* fix: web ui url
2024-06-17 07:10:07 +02:00
dependabot[bot]
5f7e6e69e3 Bump github.com/spf13/cobra from 1.8.0 to 1.8.1 (#358)
Bumps [github.com/spf13/cobra](https://github.com/spf13/cobra) from 1.8.0 to 1.8.1.
- [Release notes](https://github.com/spf13/cobra/releases)
- [Commits](https://github.com/spf13/cobra/compare/v1.8.0...v1.8.1)

---
updated-dependencies:
- dependency-name: github.com/spf13/cobra
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-17 07:02:30 +02:00
dependabot[bot]
14e84b23d1 Bump k8s.io/apimachinery from 0.30.1 to 0.30.2 in the k8s group (#357)
Bumps the k8s group with 1 update: [k8s.io/apimachinery](https://github.com/kubernetes/apimachinery).


Updates `k8s.io/apimachinery` from 0.30.1 to 0.30.2
- [Commits](https://github.com/kubernetes/apimachinery/compare/v0.30.1...v0.30.2)

---
updated-dependencies:
- dependency-name: k8s.io/apimachinery
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: k8s
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-17 07:02:23 +02:00
bakito
562576b8d4 correct docker compose example #356 2024-06-13 07:38:06 +02:00
bakito
532962527f correct docker compose example #356 2024-06-13 07:16:28 +02:00
Marc Brugger
99d1914542 correct deprecated lint flag 2024-06-10 07:55:47 +02:00
dependabot[bot]
6fa534dac1 Replace goreleaser action with make
* Use make

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Marc Brugger <github@bakito.ch>
2024-06-10 06:50:33 +02:00
dependabot[bot]
3b6da33535 Bump golang.org/x/mod from 0.17.0 to 0.18.0 (#353)
Bumps [golang.org/x/mod](https://github.com/golang/mod) from 0.17.0 to 0.18.0.
- [Commits](https://github.com/golang/mod/compare/v0.17.0...v0.18.0)

---
updated-dependencies:
- dependency-name: golang.org/x/mod
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-06-10 06:34:27 +02:00
dependabot[bot]
ded4a22a67 Bump github.com/onsi/ginkgo/v2 from 2.17.3 to 2.19.0 in the onsi group (#350)
Bumps the onsi group with 1 update: [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo).


Updates `github.com/onsi/ginkgo/v2` from 2.17.3 to 2.19.0
- [Release notes](https://github.com/onsi/ginkgo/releases)
- [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md)
- [Commits](https://github.com/onsi/ginkgo/compare/v2.17.3...v2.19.0)

---
updated-dependencies:
- dependency-name: github.com/onsi/ginkgo/v2
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: onsi
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-05-27 07:06:05 +02:00
bakito
ab0589916f only return 200 for clear log requests 2024-05-25 08:21:49 +02:00
55 changed files with 1633 additions and 700 deletions

2
.dockerignore Normal file
View File

@@ -0,0 +1,2 @@
dist
bin

View File

@@ -17,7 +17,9 @@ body:
id: adguardhome-sync-version
attributes:
label: AdguardHome-Sync Version
description: What version of adguardhome-sync was running when you discovered this issue?
description: |
- What version of adguardhome-sync was running when you discovered this issue?
- Are you running the docker or binary version?
validations:
required: true
- type: textarea
@@ -27,6 +29,15 @@ body:
description: What version of adguardhome was running when you discovered this issue?
validations:
required: true
- type: textarea
id: os-information
attributes:
label: OS Information
description: |
- What Operating System are you running? `cat /etc/os-release`
- What is the architecture of your CPU? `uname -m`
validations:
required: true
- type: textarea
id: config
attributes:

View File

@@ -1,28 +0,0 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
version: 2
updates:
- package-ecosystem: "gomod" # See documentation for possible values
directory: "/" # Location of package manifests
schedule:
interval: "weekly"
groups:
k8s:
patterns:
- "k8s.io/*"
update-types:
- "minor"
- "patch"
onsi:
patterns:
- "github.com/onsi/*"
update-types:
- "minor"
- "patch"
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "weekly"

View File

@@ -20,6 +20,10 @@ on:
schedule:
- cron: '32 19 * * 6'
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
analyze:
name: Analyze

View File

@@ -1,13 +1,20 @@
name: docker-image
name: docker-images
on:
workflow_dispatch: # allows manual triggering
schedule:
- cron: '0 0 * * *'
#pull_request:
# branches:
# - main
release:
types:
- published
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
images:
runs-on: ubuntu-latest
@@ -44,16 +51,16 @@ jobs:
run: |
sed -i -e "s|FROM scratch|FROM ${{ matrix.build.fromImage }}|g" Dockerfile
- name: Build and push ${{github.event.release.tag_name }}
- name: Build images ${{github.event.release.tag_name }}
id: docker_build_release
uses: docker/build-push-action@v5
uses: docker/build-push-action@v6
if: ${{ github.event.release.tag_name != '' }}
with:
context: .
pull: true
push: true
tags: quay.io/bakito/adguardhome-sync:${{ matrix.build.tagPrefix }}latest,quay.io/bakito/adguardhome-sync:${{ matrix.build.tagPrefix }}${{ github.event.release.tag_name }},ghcr.io/bakito/adguardhome-sync:${{ matrix.build.tagPrefix }}latest,ghcr.io/bakito/adguardhome-sync:${{ matrix.build.tagPrefix }}${{ github.event.release.tag_name }}
platforms: linux/amd64,linux/arm64,linux/arm/v7
platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/arm64,linux/ppc64le
provenance: false
build-args: |
VERSION=${{ github.event.release.tag_name }}
@@ -63,16 +70,16 @@ jobs:
run: echo "NEW_COMMIT_COUNT=$(git log --oneline --since '24 hours ago' | wc -l)" >> $GITHUB_ENV
if: ${{ github.event.release.tag_name == '' }}
- name: Build and push main
- name: Build images
id: docker_build_main
uses: docker/build-push-action@v5
uses: docker/build-push-action@v6
if: ${{ github.event.release.tag_name == '' && env.NEW_COMMIT_COUNT > 0 }}
with:
context: .
pull: true
push: true
push: ${{ github.ref == 'refs/heads/main' }}
tags: quay.io/bakito/adguardhome-sync:${{ matrix.build.tagPrefix }}main,ghcr.io/bakito/adguardhome-sync:${{ matrix.build.tagPrefix }}main
platforms: linux/amd64,linux/arm64,linux/arm/v7
platforms: linux/amd64,linux/arm/v6,linux/arm/v7,linux/arm64/v8,linux/arm64,linux/ppc64le
provenance: false
build-args: |
VERSION=main
@@ -80,4 +87,3 @@ jobs:
- name: Image digest
run: echo ${{ steps.docker_build.outputs.digest }}

View File

@@ -8,6 +8,10 @@ on:
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
e2e:
runs-on: ubuntu-latest
@@ -23,7 +27,7 @@ jobs:
uses: actions/checkout@v4
- name: Setup jq
uses: dcarbone/install-jq-action@v2
uses: dcarbone/install-jq-action@v3
- name: Install kind with registry
uses: bakito/kind-with-registry-action@main
@@ -33,10 +37,14 @@ jobs:
- name: Install Helm Chart
run: ./testdata/e2e/bin/install-chart.sh ${{ matrix.build.mode }}
- name: Wait for pod to start
run: ./testdata/e2e/bin/wait-for-start.sh ${{ matrix.build.protocol }}
- name: Show origin pre Logs
run: ./testdata/e2e/bin/show-origin-logs.sh pre
- name: Wait for sync to finish
run: ./testdata/e2e/bin/wait-for-sync.sh ${{ matrix.build.protocol }}
- name: Show origin Logs
run: ./testdata/e2e/bin/show-origin-logs.sh
- name: Show origin post Logs
run: ./testdata/e2e/bin/show-origin-logs.sh post
- name: Show Replica Logs
run: ./testdata/e2e/bin/show-replica-logs.sh
- name: Show Sync Logs

View File

@@ -6,6 +6,10 @@ on:
pull_request:
branches: [ main ]
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
cancel-in-progress: true
jobs:
golangci:
name: lint
@@ -21,7 +25,7 @@ jobs:
- name: golangci-lint
uses: golangci/golangci-lint-action@v6
with:
skip-pkg-cache: true
skip-cache: true
test:
name: test
@@ -36,6 +40,9 @@ jobs:
with:
go-version-file: "go.mod"
- name: Model
run: make model
- name: Test
run: make test-ci
@@ -58,7 +65,4 @@ jobs:
go-version-file: "go.mod"
- name: Run GoReleaser
uses: goreleaser/goreleaser-action@v5
with:
version: latest
args: --skip-publish --snapshot --rm-dist
run: make test-release

2
.gitignore vendored
View File

@@ -9,7 +9,7 @@ main
.adguardhome-sync.yaml
tmp
bin
!testdata/e2e/bin
config*.yaml
*.log
wiki
Taskfile.yml

View File

@@ -18,7 +18,6 @@ linters:
- govet
- importas
- ineffassign
- megacheck
- misspell
- nakedret
- nolintlint

View File

@@ -1,3 +1,4 @@
version: 2
# This is an example goreleaser.yaml file with some sane defaults.
# Make sure to check the documentation at http://goreleaser.com
builds:
@@ -34,12 +35,13 @@ builds:
checksum:
name_template: 'checksums.txt'
snapshot:
name_template: "{{ .Tag }}-next"
version_template: "{{ .Tag }}-next"
changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'
- '^chore'
release:
prerelease: auto

104
.toolbox.mk Normal file
View File

@@ -0,0 +1,104 @@
## toolbox - start
## Generated with https://github.com/bakito/toolbox
## Current working directory
TB_LOCALDIR ?= $(shell which cygpath > /dev/null 2>&1 && cygpath -m $$(pwd) || pwd)
## Location to install dependencies to
TB_LOCALBIN ?= $(TB_LOCALDIR)/bin
$(TB_LOCALBIN):
mkdir -p $(TB_LOCALBIN)
## Tool Binaries
TB_DEEPCOPY_GEN ?= $(TB_LOCALBIN)/deepcopy-gen
TB_GINKGO ?= $(TB_LOCALBIN)/ginkgo
TB_GOFUMPT ?= $(TB_LOCALBIN)/gofumpt
TB_GOLANGCI_LINT ?= $(TB_LOCALBIN)/golangci-lint
TB_GOLINES ?= $(TB_LOCALBIN)/golines
TB_GORELEASER ?= $(TB_LOCALBIN)/goreleaser
TB_MOCKGEN ?= $(TB_LOCALBIN)/mockgen
TB_OAPI_CODEGEN ?= $(TB_LOCALBIN)/oapi-codegen
TB_SEMVER ?= $(TB_LOCALBIN)/semver
## Tool Versions
# renovate: packageName=k8s.io/code-generator/cmd/deepcopy-gen
TB_DEEPCOPY_GEN_VERSION ?= v0.32.2
# renovate: packageName=mvdan.cc/gofumpt
TB_GOFUMPT_VERSION ?= v0.7.0
# renovate: packageName=github.com/golangci/golangci-lint/cmd/golangci-lint
TB_GOLANGCI_LINT_VERSION ?= v1.64.5
# renovate: packageName=github.com/segmentio/golines
TB_GOLINES_VERSION ?= v0.12.2
# renovate: packageName=github.com/goreleaser/goreleaser/v2
TB_GORELEASER_VERSION ?= v2.7.0
# renovate: packageName=go.uber.org/mock/mockgen
TB_MOCKGEN_VERSION ?= v0.5.0
# renovate: packageName=github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen
TB_OAPI_CODEGEN_VERSION ?= v2.4.1
# renovate: packageName=github.com/bakito/semver
TB_SEMVER_VERSION ?= v1.1.3
## Tool Installer
.PHONY: tb.deepcopy-gen
tb.deepcopy-gen: $(TB_DEEPCOPY_GEN) ## Download deepcopy-gen locally if necessary.
$(TB_DEEPCOPY_GEN): $(TB_LOCALBIN)
test -s $(TB_LOCALBIN)/deepcopy-gen || GOBIN=$(TB_LOCALBIN) go install k8s.io/code-generator/cmd/deepcopy-gen@$(TB_DEEPCOPY_GEN_VERSION)
.PHONY: tb.ginkgo
tb.ginkgo: $(TB_GINKGO) ## Download ginkgo locally if necessary.
$(TB_GINKGO): $(TB_LOCALBIN)
test -s $(TB_LOCALBIN)/ginkgo || GOBIN=$(TB_LOCALBIN) go install github.com/onsi/ginkgo/v2/ginkgo
.PHONY: tb.gofumpt
tb.gofumpt: $(TB_GOFUMPT) ## Download gofumpt locally if necessary.
$(TB_GOFUMPT): $(TB_LOCALBIN)
test -s $(TB_LOCALBIN)/gofumpt || GOBIN=$(TB_LOCALBIN) go install mvdan.cc/gofumpt@$(TB_GOFUMPT_VERSION)
.PHONY: tb.golangci-lint
tb.golangci-lint: $(TB_GOLANGCI_LINT) ## Download golangci-lint locally if necessary.
$(TB_GOLANGCI_LINT): $(TB_LOCALBIN)
test -s $(TB_LOCALBIN)/golangci-lint || GOBIN=$(TB_LOCALBIN) go install github.com/golangci/golangci-lint/cmd/golangci-lint@$(TB_GOLANGCI_LINT_VERSION)
.PHONY: tb.golines
tb.golines: $(TB_GOLINES) ## Download golines locally if necessary.
$(TB_GOLINES): $(TB_LOCALBIN)
test -s $(TB_LOCALBIN)/golines || GOBIN=$(TB_LOCALBIN) go install github.com/segmentio/golines@$(TB_GOLINES_VERSION)
.PHONY: tb.goreleaser
tb.goreleaser: $(TB_GORELEASER) ## Download goreleaser locally if necessary.
$(TB_GORELEASER): $(TB_LOCALBIN)
test -s $(TB_LOCALBIN)/goreleaser || GOBIN=$(TB_LOCALBIN) go install github.com/goreleaser/goreleaser/v2@$(TB_GORELEASER_VERSION)
.PHONY: tb.mockgen
tb.mockgen: $(TB_MOCKGEN) ## Download mockgen locally if necessary.
$(TB_MOCKGEN): $(TB_LOCALBIN)
test -s $(TB_LOCALBIN)/mockgen || GOBIN=$(TB_LOCALBIN) go install go.uber.org/mock/mockgen@$(TB_MOCKGEN_VERSION)
.PHONY: tb.oapi-codegen
tb.oapi-codegen: $(TB_OAPI_CODEGEN) ## Download oapi-codegen locally if necessary.
$(TB_OAPI_CODEGEN): $(TB_LOCALBIN)
test -s $(TB_LOCALBIN)/oapi-codegen || GOBIN=$(TB_LOCALBIN) go install github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen@$(TB_OAPI_CODEGEN_VERSION)
.PHONY: tb.semver
tb.semver: $(TB_SEMVER) ## Download semver locally if necessary.
$(TB_SEMVER): $(TB_LOCALBIN)
test -s $(TB_LOCALBIN)/semver || GOBIN=$(TB_LOCALBIN) go install github.com/bakito/semver@$(TB_SEMVER_VERSION)
## Reset Tools
.PHONY: tb.reset
tb.reset:
@rm -f \
$(TB_LOCALBIN)/deepcopy-gen \
$(TB_LOCALBIN)/ginkgo \
$(TB_LOCALBIN)/gofumpt \
$(TB_LOCALBIN)/golangci-lint \
$(TB_LOCALBIN)/golines \
$(TB_LOCALBIN)/goreleaser \
$(TB_LOCALBIN)/mockgen \
$(TB_LOCALBIN)/oapi-codegen \
$(TB_LOCALBIN)/semver
## Update Tools
.PHONY: tb.update
tb.update: tb.reset
toolbox makefile --renovate -f $(TB_LOCALDIR)/Makefile \
k8s.io/code-generator/cmd/deepcopy-gen@github.com/kubernetes/code-generator \
mvdan.cc/gofumpt@github.com/mvdan/gofumpt \
github.com/golangci/golangci-lint/cmd/golangci-lint \
github.com/segmentio/golines \
github.com/goreleaser/goreleaser/v2 \
go.uber.org/mock/mockgen@github.com/uber-go/mock \
github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen \
github.com/bakito/semver
## toolbox - end

View File

@@ -1,10 +1,8 @@
FROM golang:1.22-bullseye as builder
FROM golang:1.24-alpine AS builder
WORKDIR /go/src/app
RUN apt-get update && \
apt-get install -y upx ca-certificates tzdata && \
apt-get upgrade -y # upgrade to get latest ca-certs
RUN apk update && apk add upx ca-certificates tzdata
ARG VERSION=main
ARG BUILD="N/A"
@@ -15,8 +13,10 @@ ENV GO111MODULE=on \
COPY . /go/src/app/
RUN go build -a -installsuffix cgo -ldflags="-w -s -X github.com/bakito/adguardhome-sync/version.Version=${VERSION} -X github.com/bakito/adguardhome-sync/version.Build=${BUILD}" -o adguardhome-sync . \
&& upx -q adguardhome-sync
RUN go build -a -installsuffix cgo -ldflags="-w -s -X github.com/bakito/adguardhome-sync/version.Version=${VERSION} -X github.com/bakito/adguardhome-sync/version.Build=${BUILD}" -o adguardhome-sync .
RUN go version && upx -q adguardhome-sync
# application image
FROM scratch

124
Makefile
View File

@@ -1,113 +1,42 @@
# Include toolbox tasks
include ./.toolbox.mk
# Run go lint against code
lint: golangci-lint
$(GOLANGCI_LINT) run --fix
lint: tb.golangci-lint
$(TB_GOLANGCI_LINT) run --fix
# Run go mod tidy
tidy:
go mod tidy
generate: deepcopy-gen
generate: tb.deepcopy-gen
@mkdir -p ./tmp
@touch ./tmp/deepcopy-gen-boilerplate.go.txt
$(DEEPCOPY_GEN) --go-header-file ./tmp/deepcopy-gen-boilerplate.go.txt --bounding-dirs ./pkg/types
$(TB_DEEPCOPY_GEN) --go-header-file ./tmp/deepcopy-gen-boilerplate.go.txt --bounding-dirs ./pkg/types
fmt: tb.golines tb.gofumpt
$(TB_GOLINES) --base-formatter="$(TB_GOFUMPT)" --max-len=120 --write-output .
# Run tests
test: generate lint test-ci
test: generate fmt lint test-ci
# Run ci tests
test-ci: mocks tidy ginkgo
$(GINKGO) --cover --coverprofile coverage.out.tmp ./...
test-ci: mocks tidy tb.ginkgo
$(TB_GINKGO) --cover --coverprofile coverage.out.tmp ./...
cat coverage.out.tmp | grep -v "_generated.go" > coverage.out
go tool cover -func=coverage.out
mocks: mockgen
$(MOCKGEN) -package client -destination pkg/mocks/client/mock.go github.com/bakito/adguardhome-sync/pkg/client Client
$(MOCKGEN) -package client -destination pkg/mocks/flags/mock.go github.com/bakito/adguardhome-sync/pkg/config Flags
mocks: tb.mockgen
$(TB_MOCKGEN) -package client -destination pkg/mocks/client/mock.go github.com/bakito/adguardhome-sync/pkg/client Client
$(TB_MOCKGEN) -package client -destination pkg/mocks/flags/mock.go github.com/bakito/adguardhome-sync/pkg/config Flags
release: semver goreleaser
@version=$$($(LOCALBIN)/semver); \
release: tb.semver tb.goreleaser
@version=$$($(TB_SEMVER)); \
git tag -s $$version -m"Release $$version"
$(GORELEASER) --clean
$(TB_GORELEASER) --clean
test-release: goreleaser
$(GORELEASER) --skip=publish --snapshot --clean
## toolbox - start
## Current working directory
LOCALDIR ?= $(shell which cygpath > /dev/null 2>&1 && cygpath -m $$(pwd) || pwd)
## Location to install dependencies to
LOCALBIN ?= $(LOCALDIR)/bin
$(LOCALBIN):
mkdir -p $(LOCALBIN)
## Tool Binaries
DEEPCOPY_GEN ?= $(LOCALBIN)/deepcopy-gen
GINKGO ?= $(LOCALBIN)/ginkgo
GOLANGCI_LINT ?= $(LOCALBIN)/golangci-lint
GORELEASER ?= $(LOCALBIN)/goreleaser
MOCKGEN ?= $(LOCALBIN)/mockgen
OAPI_CODEGEN ?= $(LOCALBIN)/oapi-codegen
SEMVER ?= $(LOCALBIN)/semver
## Tool Versions
DEEPCOPY_GEN_VERSION ?= v0.30.1
GINKGO_VERSION ?= v2.19.0
GOLANGCI_LINT_VERSION ?= v1.58.2
GORELEASER_VERSION ?= v1.26.2
MOCKGEN_VERSION ?= v0.4.0
OAPI_CODEGEN_VERSION ?= v2.1.0
SEMVER_VERSION ?= v1.1.3
## Tool Installer
.PHONY: deepcopy-gen
deepcopy-gen: $(DEEPCOPY_GEN) ## Download deepcopy-gen locally if necessary.
$(DEEPCOPY_GEN): $(LOCALBIN)
test -s $(LOCALBIN)/deepcopy-gen || GOBIN=$(LOCALBIN) go install k8s.io/code-generator/cmd/deepcopy-gen@$(DEEPCOPY_GEN_VERSION)
.PHONY: ginkgo
ginkgo: $(GINKGO) ## Download ginkgo locally if necessary.
$(GINKGO): $(LOCALBIN)
test -s $(LOCALBIN)/ginkgo || GOBIN=$(LOCALBIN) go install github.com/onsi/ginkgo/v2/ginkgo@$(GINKGO_VERSION)
.PHONY: golangci-lint
golangci-lint: $(GOLANGCI_LINT) ## Download golangci-lint locally if necessary.
$(GOLANGCI_LINT): $(LOCALBIN)
test -s $(LOCALBIN)/golangci-lint || GOBIN=$(LOCALBIN) go install github.com/golangci/golangci-lint/cmd/golangci-lint@$(GOLANGCI_LINT_VERSION)
.PHONY: goreleaser
goreleaser: $(GORELEASER) ## Download goreleaser locally if necessary.
$(GORELEASER): $(LOCALBIN)
test -s $(LOCALBIN)/goreleaser || GOBIN=$(LOCALBIN) go install github.com/goreleaser/goreleaser@$(GORELEASER_VERSION)
.PHONY: mockgen
mockgen: $(MOCKGEN) ## Download mockgen locally if necessary.
$(MOCKGEN): $(LOCALBIN)
test -s $(LOCALBIN)/mockgen || GOBIN=$(LOCALBIN) go install go.uber.org/mock/mockgen@$(MOCKGEN_VERSION)
.PHONY: oapi-codegen
oapi-codegen: $(OAPI_CODEGEN) ## Download oapi-codegen locally if necessary.
$(OAPI_CODEGEN): $(LOCALBIN)
test -s $(LOCALBIN)/oapi-codegen || GOBIN=$(LOCALBIN) go install github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen@$(OAPI_CODEGEN_VERSION)
.PHONY: semver
semver: $(SEMVER) ## Download semver locally if necessary.
$(SEMVER): $(LOCALBIN)
test -s $(LOCALBIN)/semver || GOBIN=$(LOCALBIN) go install github.com/bakito/semver@$(SEMVER_VERSION)
## Update Tools
.PHONY: update-toolbox-tools
update-toolbox-tools:
@rm -f \
$(LOCALBIN)/deepcopy-gen \
$(LOCALBIN)/ginkgo \
$(LOCALBIN)/golangci-lint \
$(LOCALBIN)/goreleaser \
$(LOCALBIN)/mockgen \
$(LOCALBIN)/oapi-codegen \
$(LOCALBIN)/semver
toolbox makefile -f $(LOCALDIR)/Makefile \
k8s.io/code-generator/cmd/deepcopy-gen@github.com/kubernetes/code-generator \
github.com/onsi/ginkgo/v2/ginkgo \
github.com/golangci/golangci-lint/cmd/golangci-lint \
github.com/goreleaser/goreleaser \
go.uber.org/mock/mockgen@github.com/uber-go/mock \
github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen \
github.com/bakito/semver
## toolbox - end
test-release: tb.goreleaser
$(TB_GORELEASER) --skip=publish --snapshot --clean
start-replica:
docker run --pull always --name adguardhome-replica -p 9091:3000 --rm adguard/adguardhome:latest
@@ -138,12 +67,15 @@ kind-create:
kind-test:
@./testdata/e2e/bin/install-chart.sh
model: oapi-codegen
# renovate: packageName=AdguardTeam/AdGuardHome
ADGUARD_HOME_VERSION ?= v0.107.57
model: tb.oapi-codegen
@mkdir -p tmp
go run openapi/main.go v0.107.50
$(OAPI_CODEGEN) -package model -generate types,client -config .oapi-codegen.yaml tmp/schema.yaml > pkg/client/model/model_generated.go
go run openapi/main.go $(ADGUARD_HOME_VERSION)
$(TB_OAPI_CODEGEN) -package model -generate types,client -config .oapi-codegen.yaml tmp/schema.yaml > pkg/client/model/model_generated.go
model-diff:
go run openapi/main.go v0.107.50
go run openapi/main.go $(ADGUARD_HOME_VERSION)
go run openapi/main.go
diff tmp/schema.yaml tmp/schema-master.yaml

View File

@@ -22,6 +22,7 @@ and [Deprecations](https://github.com/bakito/adguardhome-sync/wiki/Deprecations)
- Clients
- DNS Config
- DHCP Config
- Theme
By default, all features are enabled. Single features can be disabled in the config.
@@ -74,6 +75,51 @@ adguardhome-sync run
adguardhome-sync run --cron "0 */2 * * *"
```
### Run as Linux Service via Systemd
> Verified on Ubuntu Linux 24.04
Assume you have downloaded the the `adguardhome-sync` binary to `/opt/adguardhome-sync`.
Create systemd service file `/opt/adguardhome-sync/adguardhome-sync.service`:
```
[Unit]
Description = AdGuardHome Sync
After = network.target
[Service]
ExecStart = /opt/adguardhome-sync/adguardhome-sync --config /opt/adguardhome-sync/adguardhome-sync.yaml run
[Install]
WantedBy = multi-user.target
```
Create a configuration file `/opt/adguardhome-sync/adguardhome-sync.yaml`, please follow [Config file](#config-file-1)
section below for details.
Install and enable service:
```bash
sudo cp /opt/adguardhome-sync/adguardhome-sync.service /etc/systemd/system/
sudo systemctl enable adguardhome-sync.service
sudo systemctl start adguardhome-sync.service
```
Then you can check the status:
```bash
sudo systemctl status adguardhome-sync.service
```
If web UI has been enabled in configuration (default port is 8080), can also check the status via
`http://<server-IP>:8080`
## Run Windows
```bash
@@ -164,13 +210,13 @@ services:
# REPLICA2_AUTO_SETUP: true # if true, AdGuardHome is automatically initialized.
# REPLICA2_INTERFACE_NAME: 'ens18' # use custom dhcp interface name
# REPLICA2_DHCP_SERVER_ENABLED: true/false (optional) enables/disables the dhcp server on the replica
CRON: "0 */2 * * *" # run every 10 minutes
RUNONSTART: true
CRON: "0 */2 * * *" # run every 2 hours
RUN_ON_START: "true"
# CONTINUE_ON_ERROR: false # If enabled, the synchronisation task will not fail on single errors, but will log the errors and continue
# Configure the sync API server, disabled if api port is 0
API_PORT: 8080
# API_DARK_MODE: true
# API_DARK_MODE: "true"
# API_USERNAME: admin
# API_PASSWORD: secret
# the directory of the provided tls certs
@@ -179,19 +225,21 @@ services:
# API_TLS_CERT_NAME: foo.crt
# the name of the key file (default: tls.key)
# API_TLS_KEY_NAME: bar.key
# API_METRICS_ENABLED: "true"
# Configure sync features; by default all features are enabled.
# FEATURES_GENERAL_SETTINGS: true
# FEATURES_QUERY_LOG_CONFIG: true
# FEATURES_STATS_CONFIG: true
# FEATURES_CLIENT_SETTINGS: true
# FEATURES_SERVICES: true
# FEATURES_FILTERS: true
# FEATURES_DHCP_SERVER_CONFIG: true
# FEATURES_DHCP_STATIC_LEASES: true
# FEATURES_DNS_SERVER_CONFIG: true
# FEATURES_DNS_ACCESS_LISTS: true
# FEATURES_DNS_REWRITES: true
# FEATURES_GENERAL_SETTINGS: "true"
# FEATURES_QUERY_LOG_CONFIG: "true"
# FEATURES_STATS_CONFIG: "true"
# FEATURES_CLIENT_SETTINGS: "true"
# FEATURES_SERVICES: "true"
# FEATURES_FILTERS: "true"
# FEATURES_DHCP_SERVER_CONFIG: "true"
# FEATURES_DHCP_STATIC_LEASES: "true"
# FEATURES_DNS_SERVER_CONFIG: "true"
# FEATURES_DNS_ACCESS_LISTS: "true"
# FEATURES_DNS_REWRITES: "true"
# FEATURES_THEME: "true" # if false the UI theme is not synced
ports:
- 8080:8080
restart: unless-stopped
@@ -290,4 +338,9 @@ The following log levels are supported (default: info)
## Log Format
Default log format is `console`.
It can be changed to `json`by setting the environment variable: `LOG_FORMAT=json`
It can be changed to `json` by setting the environment variable: `LOG_FORMAT=json`.
## Video Tutorials
- [Como replicar la configuración de tu servidor DNS Adguard automáticamente - Tu servidor Part #12](https://www.youtube.com/watch?v=1LPeu_JG064) (
Spanish) by [Jonatan Castro](https://github.com/jcastro)

View File

@@ -1,135 +0,0 @@
version: '3'
env:
AGH_MODEL_VERSION: v0.107.43
GOBIN: '{{.USER_WORKING_DIR}}/bin'
tasks:
install-go-tool:
label: "Install {{ .TOOL_NAME }}"
cmds:
- go install {{ .TOOL_MODULE }}
status:
- test -f {{.GOBIN}}/{{.TOOL_NAME}}
deepcopy-gen:
desc: Install deepcopy-gen
cmd:
task: install-go-tool
vars:
TOOL_NAME: deepcopy-gen
TOOL_MODULE: k8s.io/code-generator/cmd/deepcopy-gen
ginkgo:
cmd:
task: install-go-tool
vars:
TOOL_NAME: ginkgo
TOOL_MODULE: github.com/onsi/ginkgo/v2/ginkgo
goreleaser:
cmd:
task: install-go-tool
vars:
TOOL_NAME: goreleaser
TOOL_MODULE: github.com/goreleaser/goreleaser
golangci-lint:
cmd:
task: install-go-tool
vars:
TOOL_NAME: golangci-lint
TOOL_MODULE: github.com/golangci/golangci-lint/cmd/golangci-lint
mockgen:
cmd:
task: install-go-tool
vars:
TOOL_NAME: mockgen
TOOL_MODULE: go.uber.org/mock/mockgen
oapi-codegen:
cmd:
task: install-go-tool
vars:
TOOL_NAME: oapi-codegen
TOOL_MODULE: github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen
semver:
cmd:
task: install-go-tool
vars:
TOOL_NAME: semver
TOOL_MODULE: github.com/bakito/semver
lint:
deps:
- golangci-lint
cmds:
- '{{.GOBIN}}/golangci-lint run --fix'
tidy:
desc: Run go mod tidy
cmd: go mod tidy
generate:
deps:
- deepcopy-gen
cmds:
- mkdir -p ./tmp
- touch ./tmp/deepcopy-gen-boilerplate.go.txt
- '{{.GOBIN}}/deepcopy-gen -h ./tmp/deepcopy-gen-boilerplate.go.txt -i ./pkg/types'
mocks:
deps:
- mockgen
cmds:
- '{{.GOBIN}}/mockgen -package client -destination pkg/mocks/client/mock.go github.com/bakito/adguardhome-sync/pkg/client Client'
- '{{.GOBIN}}/mockgen -package client -destination pkg/mocks/flags/mock.go github.com/bakito/adguardhome-sync/pkg/config Flags'
test:
cmds:
- task: generate
- task: lint
- task: test-ci
test-ci:
deps:
- ginkgo
- tidy
- mocks
cmds:
- '{{.GOBIN}}/ginkgo --cover --coverprofile coverage.out.tmp ./...'
- cat coverage.out.tmp | grep -v "_generated.go" > coverage.out
- go tool cover -func=coverage.out
release:
deps:
- semver
- goreleaser
cmds:
- git tag -s $$version -m"Release $({{.GOBIN}}/semver)
- '{{.GOBIN}}/goreleaser --clean'
test-release:
deps:
- goreleaser
- semver
cmds:
- '{{.GOBIN}}/goreleaser --skip=publish --snapshot --clean'
model:
deps:
- oapi-codegen
cmds:
- mkdir -p tmp
- go run openapi/main.go {{.AGH_MODEL_VERSION}}
- '{{.GOBIN}}/oapi-codegen -package model -generate types,client -config .oapi-codegen.yaml tmp/schema.yaml > pkg/client/model/model_generated.go'
model-diff:
deps:
- oapi-codegen
cmds:
- go run openapi/main.go {{.AGH_MODEL_VERSION}}
- go run openapi/main.go
- diff tmp/schema.yaml tmp/schema-master.yaml

View File

@@ -50,7 +50,8 @@ func init() {
doCmd.PersistentFlags().Bool(config.FlagContinueOnError, false, "If enabled, the synchronisation task "+
"will not fail on single errors, but will log the errors and continue.")
doCmd.PersistentFlags().Int(config.FlagApiPort, 8080, "Sync API Port, the API endpoint will be started to enable remote triggering; if 0 port API is disabled.")
doCmd.PersistentFlags().
Int(config.FlagApiPort, 8080, "Sync API Port, the API endpoint will be started to enable remote triggering; if 0 port API is disabled.")
doCmd.PersistentFlags().String(config.FlagApiUsername, "", "Sync API username")
doCmd.PersistentFlags().String(config.FlagApiPassword, "", "Sync API password")
doCmd.PersistentFlags().String(config.FlagApiDarkMode, "", "API UI in dark mode")
@@ -70,7 +71,8 @@ func init() {
doCmd.PersistentFlags().Bool(config.FlagFeatureFilters, true, "Enable filters sync feature")
doCmd.PersistentFlags().String(config.FlagOriginURL, "", "Origin instance url")
doCmd.PersistentFlags().String(config.FlagOriginWebURL, "", "Origin instance web url used in the web interface (default: <origin-url>)")
doCmd.PersistentFlags().
String(config.FlagOriginWebURL, "", "Origin instance web url used in the web interface (default: <origin-url>)")
doCmd.PersistentFlags().String(config.FlagOriginApiPath, "/control", "Origin instance API path")
doCmd.PersistentFlags().String(config.FlagOriginUsername, "", "Origin instance username")
doCmd.PersistentFlags().String(config.FlagOriginPassword, "", "Origin instance password")
@@ -78,12 +80,15 @@ func init() {
doCmd.PersistentFlags().Bool(config.FlagOriginISV, false, "Enable Origin instance InsecureSkipVerify")
doCmd.PersistentFlags().String(config.FlagReplicaURL, "", "Replica instance url")
doCmd.PersistentFlags().String(config.FlagReplicaWebURL, "", "Replica instance web url used in the web interface (default: <replica-url>)")
doCmd.PersistentFlags().
String(config.FlagReplicaWebURL, "", "Replica instance web url used in the web interface (default: <replica-url>)")
doCmd.PersistentFlags().String(config.FlagReplicaApiPath, "/control", "Replica instance API path")
doCmd.PersistentFlags().String(config.FlagReplicaUsername, "", "Replica instance username")
doCmd.PersistentFlags().String(config.FlagReplicaPassword, "", "Replica instance password")
doCmd.PersistentFlags().String(config.FlagReplicaCookie, "", "If Set, uses a cookie for authentication")
doCmd.PersistentFlags().Bool(config.FlagReplicaISV, false, "Enable Replica instance InsecureSkipVerify")
doCmd.PersistentFlags().Bool(config.FlagReplicaAutoSetup, false, "Enable automatic setup of new AdguardHome instances. This replaces the setup wizard.")
doCmd.PersistentFlags().String(config.FlagReplicaInterfaceName, "", "Optional change the interface name of the replica if it differs from the master")
doCmd.PersistentFlags().
Bool(config.FlagReplicaAutoSetup, false, "Enable automatic setup of new AdguardHome instances. This replaces the setup wizard.")
doCmd.PersistentFlags().
String(config.FlagReplicaInterfaceName, "", "Optional change the interface name of the replica if it differs from the master")
}

67
go.mod
View File

@@ -1,27 +1,27 @@
module github.com/bakito/adguardhome-sync
go 1.22.0
toolchain go1.22.2
go 1.24.0
require (
github.com/caarlos0/env/v10 v10.0.0
github.com/caarlos0/env/v11 v11.3.1
github.com/gin-gonic/gin v1.10.0
github.com/go-resty/resty/v2 v2.13.1
github.com/go-faker/faker/v4 v4.6.0
github.com/go-resty/resty/v2 v2.16.5
github.com/google/uuid v1.6.0
github.com/jinzhu/copier v0.4.0
github.com/oapi-codegen/runtime v1.1.1
github.com/onsi/ginkgo/v2 v2.17.3
github.com/onsi/gomega v1.33.1
github.com/prometheus/client_golang v1.19.1
github.com/onsi/ginkgo/v2 v2.22.2
github.com/onsi/gomega v1.36.2
github.com/prometheus/client_golang v1.21.0
github.com/robfig/cron/v3 v3.0.1
github.com/spf13/cobra v1.8.0
go.uber.org/mock v0.4.0
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1
github.com/spf13/cobra v1.9.1
go.uber.org/mock v0.5.0
go.uber.org/zap v1.27.0
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc
golang.org/x/mod v0.17.0
golang.org/x/mod v0.23.0
gopkg.in/yaml.v3 v3.0.1
k8s.io/apimachinery v0.30.1
k8s.io/apimachinery v0.32.2
k8s.io/utils v0.0.0-20241210054802-24370beab758
)
require (
@@ -29,13 +29,13 @@ require (
github.com/beorn7/perks v1.0.1 // indirect
github.com/bytedance/sonic v1.11.6 // indirect
github.com/bytedance/sonic/loader v0.1.1 // indirect
github.com/cespare/xxhash/v2 v2.2.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/cloudwego/base64x v0.1.4 // indirect
github.com/cloudwego/iasm v0.2.0 // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.20.0 // indirect
@@ -44,36 +44,35 @@ require (
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/go-cmp v0.6.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 // indirect
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.17.11 // indirect
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/prometheus/client_model v0.5.0 // indirect
github.com/prometheus/common v0.48.0 // indirect
github.com/prometheus/procfs v0.12.0 // indirect
github.com/rogpeppe/go-internal v1.12.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.62.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/spf13/pflag v1.0.6 // indirect
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.12 // indirect
github.com/x448/float16 v0.8.4 // indirect
go.uber.org/multierr v1.11.0 // indirect
golang.org/x/arch v0.8.0 // indirect
golang.org/x/crypto v0.23.0 // indirect
golang.org/x/net v0.25.0 // indirect
golang.org/x/sys v0.20.0 // indirect
golang.org/x/text v0.15.0 // indirect
golang.org/x/tools v0.20.0 // indirect
google.golang.org/protobuf v1.34.1 // indirect
golang.org/x/crypto v0.31.0 // indirect
golang.org/x/net v0.33.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/text v0.22.0 // indirect
golang.org/x/tools v0.28.0 // indirect
google.golang.org/protobuf v1.36.1 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/klog/v2 v2.120.1 // indirect
k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
k8s.io/klog/v2 v2.130.1 // indirect
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect
sigs.k8s.io/yaml v1.4.0 // indirect
)

168
go.sum
View File

@@ -8,27 +8,33 @@ github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
github.com/caarlos0/env/v10 v10.0.0 h1:yIHUBZGsyqCnpTkbjk8asUlx6RFhhEs+h7TOBdgdzXA=
github.com/caarlos0/env/v10 v10.0.0/go.mod h1:ZfulV76NvVPw3tm591U4SwL3Xx9ldzBP9aGxzeN7G18=
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/caarlos0/env/v11 v11.3.1 h1:cArPWC15hWmEt+gWk7YBi7lEXTXCvpaSdCiZE2X5mCA=
github.com/caarlos0/env/v11 v11.3.1/go.mod h1:qupehSf/Y0TUTsxKywqRt/vJjN5nz6vauiYEUUr8P4U=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ=
github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-faker/faker/v4 v4.6.0 h1:6aOPzNptRiDwD14HuAnEtlTa+D1IfFuEHO8+vEFwjTs=
github.com/go-faker/faker/v4 v4.6.0/go.mod h1:ZmrHuVtTTm2Em9e0Du6CJ9CADaLEzGXW62z1YqFH0m0=
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
@@ -37,8 +43,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-resty/resty/v2 v2.13.1 h1:x+LHXBI2nMB1vqndymf26quycC4aggYJ7DECYbiz03g=
github.com/go-resty/resty/v2 v2.13.1/go.mod h1:GznXlLxkq6Nh4sU59rPmUw3VtgpO3aS96ORAI6Q7d+0=
github.com/go-resty/resty/v2 v2.16.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptdhTM=
github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
@@ -51,8 +57,8 @@ github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6 h1:k7nVchz72niMH6YLQNvHSdIE7iqsQxK1P41mySCvssg=
github.com/google/pprof v0.0.0-20240424215950-a892ee059fd6/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg=
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
@@ -64,6 +70,8 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
@@ -72,6 +80,8 @@ github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
@@ -81,34 +91,38 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro=
github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg=
github.com/onsi/ginkgo/v2 v2.17.3 h1:oJcvKpIb7/8uLpDDtnQuf18xVnwKp8DTD7DQ6gTd/MU=
github.com/onsi/ginkgo/v2 v2.17.3/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc=
github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk=
github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0=
github.com/onsi/ginkgo/v2 v2.22.2 h1:/3X8Panh8/WwhU/3Ssa6rCKqPLuAkVY2I0RoyDLySlU=
github.com/onsi/ginkgo/v2 v2.22.2/go.mod h1:oeMosUL+8LtarXBHu/c0bx2D/K9zyQ6uX3cTyztHwsk=
github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_golang v1.19.1 h1:wZWJDwK+NameRJuPGDhlnFgx8e8HN3XHQeLaYJFJBOE=
github.com/prometheus/client_golang v1.19.1/go.mod h1:mP78NwGzrVks5S2H6ab8+ZZGJLZUq1hoULYBAYBw1Ho=
github.com/prometheus/client_model v0.5.0 h1:VQw1hfvPvk3Uv6Qf29VrPF32JB6rtbgI6cYPYQjL0Qw=
github.com/prometheus/client_model v0.5.0/go.mod h1:dTiFglRmd66nLR9Pv9f0mZi7B7fk5Pm3gvsjB5tr+kI=
github.com/prometheus/common v0.48.0 h1:QO8U2CdOzSn1BBsmXJXduaaW+dY/5QLjfB8svtSzKKE=
github.com/prometheus/common v0.48.0/go.mod h1:0/KsvlIEfPQCQ5I2iNSAWKPZziNCvRs5EC6ILDTlAPc=
github.com/prometheus/procfs v0.12.0 h1:jluTpSng7V9hY0O2R9DzzJHYb2xULk9VTR1V1R/k6Bo=
github.com/prometheus/procfs v0.12.0/go.mod h1:pcuDEFsWDnvcgNzo4EEweacyhjeA9Zk3cnaOZAZEfOo=
github.com/prometheus/client_golang v1.21.0 h1:DIsaGmiaBkSangBgMtWdNfxbMNdku5IK6iNhrEqWvdA=
github.com/prometheus/client_golang v1.21.0/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1 h1:PKK9DyHxif4LZo+uQSgXNqs0jj5+xZwwfKHgph2lxBw=
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0=
github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o=
github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
@@ -120,19 +134,21 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
@@ -143,99 +159,65 @@ golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
golang.org/x/crypto v0.23.0 h1:dIJU/v2J8Mdglj/8rJ6UUOM3Zc9zLZxVZwwxMooUSAI=
golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc h1:ao2WRsKSzW6KuUY9IWPwWahcHCgR0s52IfwutMfEbdM=
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/mod v0.23.0 h1:Zb7khfcRGKk+kqfxFaP5tZqCnDZMjC5VtUBs87Hr6QM=
golang.org/x/mod v0.23.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.20.0 h1:Od9JTbYCk261bKm4M/mw7AklTlFYIa0bIp9BgSm1S8Y=
golang.org/x/sys v0.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
golang.org/x/term v0.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.15.0 h1:h1V/4gjBv8v9cjcR6+AR5+/cIYK5N/WAgiv4xlsEtAk=
golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/tools v0.20.0 h1:hz/CVckiOxybQvFw6h7b/q80NTr9IUQb4s1IIzW7KNY=
golang.org/x/tools v0.20.0/go.mod h1:WvitBU7JJf6A4jOdg4S1tviW9bhUxkgeCui/0JHctQg=
golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8=
golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg=
google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
k8s.io/apimachinery v0.30.1 h1:ZQStsEfo4n65yAdlGTfP/uSHMQSoYzU/oeEbkmF7P2U=
k8s.io/apimachinery v0.30.1/go.mod h1:iexa2somDaxdnj7bha06bhb43Zpa6eWH8N8dbqVjTUc=
k8s.io/klog/v2 v2.120.1 h1:QXU6cPEOIslTGvZaXvFWiP9VKyeet3sawzTOvdXb4Vw=
k8s.io/klog/v2 v2.120.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI=
k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
k8s.io/apimachinery v0.32.2 h1:yoQBR9ZGkA6Rgmhbp/yuT9/g+4lxtsGYwW6dR6BDPLQ=
k8s.io/apimachinery v0.32.2/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0=
k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8=
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo=
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA=
sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4=
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=

View File

@@ -20,7 +20,9 @@ func main() {
}
log.Printf("Patching schema version %s\n", version)
resp, err := http.Get(fmt.Sprintf("https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/%s/openapi/openapi.yaml", version))
resp, err := http.Get(
fmt.Sprintf("https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/%s/openapi/openapi.yaml", version),
)
if err != nil {
log.Fatalln(err)
}

View File

@@ -166,7 +166,10 @@ func (cl *client) Stats() (*model.Stats, error) {
func (cl *client) QueryLog(limit int) (*model.QueryLog, error) {
ql := &model.QueryLog{}
err := cl.doGet(cl.client.R().EnableTrace().SetResult(ql), fmt.Sprintf(`querylog?limit=%d&response_status="all"`, limit))
err := cl.doGet(
cl.client.R().EnableTrace().SetResult(ql),
fmt.Sprintf(`querylog?limit=%d&response_status="all"`, limit),
)
return ql, err
}
@@ -260,7 +263,10 @@ func (cl *client) UpdateFilter(whitelist bool, f model.Filter) error {
func (cl *client) RefreshFilters(whitelist bool) error {
cl.log.With("whitelist", whitelist).Info("Refresh filter")
return cl.doPost(cl.client.R().EnableTrace().SetBody(&model.FilterRefreshRequest{Whitelist: utils.Ptr(whitelist)}), "/filtering/refresh")
return cl.doPost(
cl.client.R().EnableTrace().SetBody(&model.FilterRefreshRequest{Whitelist: utils.Ptr(whitelist)}),
"/filtering/refresh",
)
}
func (cl *client) ToggleProtection(enable bool) error {
@@ -309,7 +315,10 @@ func (cl *client) AddClient(client *model.Client) error {
func (cl *client) UpdateClient(client *model.Client) error {
cl.log.With("name", *client.Name).Info("Update client settings")
return cl.doPost(cl.client.R().EnableTrace().SetBody(&model.ClientUpdate{Name: client.Name, Data: client}), "/clients/update")
return cl.doPost(
cl.client.R().EnableTrace().SetBody(&model.ClientUpdate{Name: client.Name, Data: client}),
"/clients/update",
)
}
func (cl *client) DeleteClient(client *model.Client) error {
@@ -324,7 +333,8 @@ func (cl *client) QueryLogConfig() (*model.QueryLogConfigWithIgnored, error) {
}
func (cl *client) SetQueryLogConfig(qlc *model.QueryLogConfigWithIgnored) error {
cl.log.With("enabled", *qlc.Enabled, "interval", *qlc.Interval, "anonymizeClientIP", *qlc.AnonymizeClientIp).Info("Set query log config")
cl.log.With("enabled", *qlc.Enabled, "interval", *qlc.Interval, "anonymizeClientIP", *qlc.AnonymizeClientIp).
Info("Set query log config")
return cl.doPut(cl.client.R().EnableTrace().SetBody(qlc), "/querylog/config/update")
}

View File

@@ -137,7 +137,14 @@ var _ = Describe("Client", func() {
Context("Setup", func() {
It("should add setup the instance", func() {
ts, cl = ClientPost("/install/configure", fmt.Sprintf(`{"web":{"ip":"0.0.0.0","port":3000,"status":"","can_autofix":false},"dns":{"ip":"0.0.0.0","port":53,"status":"","can_autofix":false},"username":"%s","password":"%s"}`, username, password))
ts, cl = ClientPost(
"/install/configure",
fmt.Sprintf(
`{"web":{"ip":"0.0.0.0","port":3000,"status":"","can_autofix":false},"dns":{"ip":"0.0.0.0","port":53,"status":"","can_autofix":false},"username":"%s","password":"%s"}`,
username,
password,
),
)
err := cl.Setup()
Ω(err).ShouldNot(HaveOccurred())
})
@@ -303,7 +310,10 @@ var _ = Describe("Client", func() {
Ω(*qlc.Interval).Should(Equal(model.QueryLogConfigInterval(90)))
})
It("should set QueryLogConfig", func() {
ts, cl = ClientPut("/querylog/config/update", `{"anonymize_client_ip":true,"enabled":true,"interval":123,"ignored":["foo.bar"]}`)
ts, cl = ClientPut(
"/querylog/config/update",
`{"anonymize_client_ip":true,"enabled":true,"interval":123,"ignored":["foo.bar"]}`,
)
var interval model.QueryLogConfigInterval = 123
err := cl.SetQueryLogConfig(&model.QueryLogConfigWithIgnored{

View File

@@ -8,6 +8,7 @@ import (
"github.com/bakito/adguardhome-sync/pkg/utils"
"github.com/jinzhu/copier"
"go.uber.org/zap"
"k8s.io/utils/ptr"
)
// Clone the config
@@ -398,23 +399,22 @@ func (ssc *SafeSearchConfig) Equals(o *SafeSearchConfig) bool {
ptrEquals(ssc.Youtube, o.Youtube)
}
func (pi *ProfileInfo) Equals(o *ProfileInfo) bool {
return pi.Language == o.Language &&
pi.Theme == o.Theme
func (pi *ProfileInfo) Equals(o *ProfileInfo, withTheme bool) bool {
return pi.Language == o.Language && (!withTheme || pi.Theme == o.Theme)
}
func (pi *ProfileInfo) ShouldSyncFor(o *ProfileInfo) *ProfileInfo {
if pi.Equals(o) {
func (pi *ProfileInfo) ShouldSyncFor(o *ProfileInfo, withTheme bool) *ProfileInfo {
if pi.Equals(o, withTheme) {
return nil
}
merged := &ProfileInfo{Name: pi.Name, Language: pi.Language, Theme: pi.Theme}
if o.Language != "" {
merged.Language = o.Language
}
if o.Theme != "" {
if withTheme && o.Theme != "" {
merged.Theme = o.Theme
}
if merged.Name == "" || merged.Language == "" || merged.Theme == "" || merged.Equals(pi) {
if merged.Name == "" || merged.Language == "" || merged.Equals(pi, false) {
return nil
}
return merged
@@ -442,7 +442,9 @@ func (c *DNSConfig) Sanitize(l *zap.SugaredLogger) {
// https://github.com/AdguardTeam/AdGuardHome/issues/6820
if c.UsePrivatePtrResolvers != nil && *c.UsePrivatePtrResolvers &&
(c.LocalPtrUpstreams == nil || len(*c.LocalPtrUpstreams) == 0) {
l.Warn("disabling replica 'Use private reverse DNS resolvers' as no 'Private reverse DNS servers' are configured on origin")
l.Warn(
"disabling replica 'Use private reverse DNS resolvers' as no 'Private reverse DNS servers' are configured on origin",
)
c.UsePrivatePtrResolvers = utils.Ptr(false)
}
}
@@ -451,3 +453,53 @@ func (c *DNSConfig) Sanitize(l *zap.SugaredLogger) {
func (sc *GetStatsConfigResponse) Equals(o *GetStatsConfigResponse) bool {
return utils.JsonEquals(sc, o)
}
func NewStats() *Stats {
return &Stats{
NumBlockedFiltering: ptr.To(0),
NumReplacedParental: ptr.To(0),
NumReplacedSafesearch: ptr.To(0),
NumReplacedSafebrowsing: ptr.To(0),
NumDnsQueries: ptr.To(0),
BlockedFiltering: ptr.To(make([]int, 24)),
DnsQueries: ptr.To(make([]int, 24)),
ReplacedParental: ptr.To(make([]int, 24)),
ReplacedSafebrowsing: ptr.To(make([]int, 24)),
}
}
func (s *Stats) Add(other *Stats) {
s.NumBlockedFiltering = addInt(s.NumBlockedFiltering, other.NumBlockedFiltering)
s.NumReplacedSafebrowsing = addInt(s.NumReplacedSafebrowsing, other.NumReplacedSafebrowsing)
s.NumDnsQueries = addInt(s.NumDnsQueries, other.NumDnsQueries)
s.NumReplacedSafesearch = addInt(s.NumReplacedSafesearch, other.NumReplacedSafesearch)
s.NumReplacedParental = addInt(s.NumReplacedParental, other.NumReplacedParental)
s.BlockedFiltering = sumUp(s.BlockedFiltering, other.BlockedFiltering)
s.DnsQueries = sumUp(s.DnsQueries, other.DnsQueries)
s.ReplacedParental = sumUp(s.ReplacedParental, other.ReplacedParental)
s.ReplacedSafebrowsing = sumUp(s.ReplacedSafebrowsing, other.ReplacedSafebrowsing)
}
func addInt(t *int, add *int) *int {
if add != nil {
return ptr.To(*t + *add)
}
return t
}
func sumUp(t *[]int, o *[]int) *[]int {
if o != nil {
tt := *t
oo := *o
var sum []int
for i := 0; i < len(tt); i++ {
if len(oo) >= i {
sum = append(sum, tt[i]+oo[i])
}
}
return &sum
}
return t
}

View File

@@ -1,6 +1,6 @@
// Package model provides primitives to interact with the openapi HTTP API.
//
// Code generated by github.com/deepmap/oapi-codegen/v2 version v2.1.0 DO NOT EDIT.
// Code generated by github.com/oapi-codegen/oapi-codegen/v2 version v2.4.1 DO NOT EDIT.
package model
import (
@@ -397,6 +397,17 @@ type ClientsFindEntry map[string]ClientFindSubEntry
// ClientsFindResponse Client search results.
type ClientsFindResponse = []ClientsFindEntry
// ClientsSearchRequest Client search request
type ClientsSearchRequest struct {
Clients *[]ClientsSearchRequestItem `json:"clients,omitempty"`
}
// ClientsSearchRequestItem defines model for ClientsSearchRequestItem.
type ClientsSearchRequestItem struct {
// Id Client IP address, CIDR, MAC address, or ClientID
Id *string `json:"id,omitempty"`
}
// DNSConfig DNS server configuration
type DNSConfig struct {
// BlockedResponseTtl TTL for blocked responses.
@@ -444,6 +455,9 @@ type DNSConfig struct {
// UpstreamMode Upstream modes enumeration.
UpstreamMode *DNSConfigUpstreamMode `json:"upstream_mode,omitempty"`
// UpstreamTimeout The number of seconds to wait for a response from the upstream server
UpstreamTimeout *int `json:"upstream_timeout,omitempty"`
UsePrivatePtrResolvers *bool `json:"use_private_ptr_resolvers,omitempty"`
}
@@ -726,9 +740,16 @@ type Login struct {
type NetInterface struct {
// Flags Flags could be any combination of the following values, divided by the "|" character: "up", "broadcast", "loopback", "pointtopoint" and "multicast".
Flags string `json:"flags"`
// GatewayIp The IP address of the gateway.
GatewayIp string `json:"gateway_ip"`
HardwareAddress string `json:"hardware_address"`
IpAddresses *[]string `json:"ip_addresses,omitempty"`
Mtu int `json:"mtu"`
// Ipv4Addresses The addresses of the interface of v4 family.
Ipv4Addresses []string `json:"ipv4_addresses"`
// Ipv6Addresses The addresses of the interface of v6 family.
Ipv6Addresses []string `json:"ipv6_addresses"`
Name string `json:"name"`
}
@@ -904,6 +925,7 @@ type RewriteUpdate struct {
type SafeSearchConfig struct {
Bing *bool `json:"bing,omitempty"`
Duckduckgo *bool `json:"duckduckgo,omitempty"`
Ecosia *bool `json:"ecosia,omitempty"`
Enabled *bool `json:"enabled,omitempty"`
Google *bool `json:"google,omitempty"`
Pixabay *bool `json:"pixabay,omitempty"`
@@ -1204,6 +1226,9 @@ type ClientsAddJSONRequestBody = Client
// ClientsDeleteJSONRequestBody defines body for ClientsDelete for application/json ContentType.
type ClientsDeleteJSONRequestBody = ClientDelete
// ClientsSearchJSONRequestBody defines body for ClientsSearch for application/json ContentType.
type ClientsSearchJSONRequestBody = ClientsSearchRequest
// ClientsUpdateJSONRequestBody defines body for ClientsUpdate for application/json ContentType.
type ClientsUpdateJSONRequestBody = ClientUpdate
@@ -1493,6 +1518,11 @@ type ClientInterface interface {
// ClientsFind request
ClientsFind(ctx context.Context, params *ClientsFindParams, reqEditors ...RequestEditorFn) (*http.Response, error)
// ClientsSearchWithBody request with any body
ClientsSearchWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
ClientsSearch(ctx context.Context, body ClientsSearchJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error)
// ClientsUpdateWithBody request with any body
ClientsUpdateWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
@@ -1985,6 +2015,30 @@ func (c *AdguardHomeClient) ClientsFind(ctx context.Context, params *ClientsFind
return c.Client.Do(req)
}
func (c *AdguardHomeClient) ClientsSearchWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewClientsSearchRequestWithBody(c.Server, contentType, body)
if err != nil {
return nil, err
}
req = req.WithContext(ctx)
if err := c.applyEditors(ctx, req, reqEditors); err != nil {
return nil, err
}
return c.Client.Do(req)
}
func (c *AdguardHomeClient) ClientsSearch(ctx context.Context, body ClientsSearchJSONRequestBody, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewClientsSearchRequest(c.Server, body)
if err != nil {
return nil, err
}
req = req.WithContext(ctx)
if err := c.applyEditors(ctx, req, reqEditors); err != nil {
return nil, err
}
return c.Client.Do(req)
}
func (c *AdguardHomeClient) ClientsUpdateWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
req, err := NewClientsUpdateRequestWithBody(c.Server, contentType, body)
if err != nil {
@@ -3673,6 +3727,46 @@ func NewClientsFindRequest(server string, params *ClientsFindParams) (*http.Requ
return req, nil
}
// NewClientsSearchRequest calls the generic ClientsSearch builder with application/json body
func NewClientsSearchRequest(server string, body ClientsSearchJSONRequestBody) (*http.Request, error) {
var bodyReader io.Reader
buf, err := json.Marshal(body)
if err != nil {
return nil, err
}
bodyReader = bytes.NewReader(buf)
return NewClientsSearchRequestWithBody(server, "application/json", bodyReader)
}
// NewClientsSearchRequestWithBody generates requests for ClientsSearch with any type of body
func NewClientsSearchRequestWithBody(server string, contentType string, body io.Reader) (*http.Request, error) {
var err error
serverURL, err := url.Parse(server)
if err != nil {
return nil, err
}
operationPath := fmt.Sprintf("/clients/search")
if operationPath[0] == '/' {
operationPath = "." + operationPath
}
queryURL, err := serverURL.Parse(operationPath)
if err != nil {
return nil, err
}
req, err := http.NewRequest("POST", queryURL.String(), body)
if err != nil {
return nil, err
}
req.Header.Add("Content-Type", contentType)
return req, nil
}
// NewClientsUpdateRequest calls the generic ClientsUpdate builder with application/json body
func NewClientsUpdateRequest(server string, body ClientsUpdateJSONRequestBody) (*http.Request, error) {
var bodyReader io.Reader
@@ -5983,6 +6077,11 @@ type ClientWithResponsesInterface interface {
// ClientsFindWithResponse request
ClientsFindWithResponse(ctx context.Context, params *ClientsFindParams, reqEditors ...RequestEditorFn) (*ClientsFindResp, error)
// ClientsSearchWithBodyWithResponse request with any body
ClientsSearchWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*ClientsSearchResp, error)
ClientsSearchWithResponse(ctx context.Context, body ClientsSearchJSONRequestBody, reqEditors ...RequestEditorFn) (*ClientsSearchResp, error)
// ClientsUpdateWithBodyWithResponse request with any body
ClientsUpdateWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*ClientsUpdateResp, error)
@@ -6559,6 +6658,28 @@ func (r ClientsFindResp) StatusCode() int {
return 0
}
type ClientsSearchResp struct {
Body []byte
HTTPResponse *http.Response
JSON200 *ClientsFindResponse
}
// Status returns HTTPResponse.Status
func (r ClientsSearchResp) Status() string {
if r.HTTPResponse != nil {
return r.HTTPResponse.Status
}
return http.StatusText(0)
}
// StatusCode returns HTTPResponse.StatusCode
func (r ClientsSearchResp) StatusCode() int {
if r.HTTPResponse != nil {
return r.HTTPResponse.StatusCode
}
return 0
}
type ClientsUpdateResp struct {
Body []byte
HTTPResponse *http.Response
@@ -8098,6 +8219,23 @@ func (c *ClientWithResponses) ClientsFindWithResponse(ctx context.Context, param
return ParseClientsFindResp(rsp)
}
// ClientsSearchWithBodyWithResponse request with arbitrary body returning *ClientsSearchResp
func (c *ClientWithResponses) ClientsSearchWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*ClientsSearchResp, error) {
rsp, err := c.ClientsSearchWithBody(ctx, contentType, body, reqEditors...)
if err != nil {
return nil, err
}
return ParseClientsSearchResp(rsp)
}
func (c *ClientWithResponses) ClientsSearchWithResponse(ctx context.Context, body ClientsSearchJSONRequestBody, reqEditors ...RequestEditorFn) (*ClientsSearchResp, error) {
rsp, err := c.ClientsSearch(ctx, body, reqEditors...)
if err != nil {
return nil, err
}
return ParseClientsSearchResp(rsp)
}
// ClientsUpdateWithBodyWithResponse request with arbitrary body returning *ClientsUpdateResp
func (c *ClientWithResponses) ClientsUpdateWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*ClientsUpdateResp, error) {
rsp, err := c.ClientsUpdateWithBody(ctx, contentType, body, reqEditors...)
@@ -9243,6 +9381,32 @@ func ParseClientsFindResp(rsp *http.Response) (*ClientsFindResp, error) {
return response, nil
}
// ParseClientsSearchResp parses an HTTP response from a ClientsSearchWithResponse call
func ParseClientsSearchResp(rsp *http.Response) (*ClientsSearchResp, error) {
bodyBytes, err := io.ReadAll(rsp.Body)
defer func() { _ = rsp.Body.Close() }()
if err != nil {
return nil, err
}
response := &ClientsSearchResp{
Body: bodyBytes,
HTTPResponse: rsp,
}
switch {
case strings.Contains(rsp.Header.Get("Content-Type"), "json") && rsp.StatusCode == 200:
var dest ClientsFindResponse
if err := json.Unmarshal(bodyBytes, &dest); err != nil {
return nil, err
}
response.JSON200 = &dest
}
return response, nil
}
// ParseClientsUpdateResp parses an HTTP response from a ClientsUpdateWithResponse call
func ParseClientsUpdateResp(rsp *http.Response) (*ClientsUpdateResp, error) {
bodyBytes, err := io.ReadAll(rsp.Body)

View File

@@ -242,7 +242,10 @@ var _ = Describe("Types", func() {
})
It("should return 3 one replicas if urls are different", func() {
cfg.Replica = &types.AdGuardInstance{URL: url, APIPath: apiPath}
cfg.Replicas = []types.AdGuardInstance{{URL: url + "1", APIPath: apiPath}, {URL: url, APIPath: apiPath + "1"}}
cfg.Replicas = []types.AdGuardInstance{
{URL: url + "1", APIPath: apiPath},
{URL: url, APIPath: apiPath + "1"},
}
r := cfg.UniqueReplicas()
Ω(r).Should(HaveLen(3))
})
@@ -311,8 +314,14 @@ var _ = Describe("Types", func() {
cl2 *model.Client
)
BeforeEach(func() {
cl1 = &model.Client{Name: utils.Ptr("foo"), BlockedServicesSchedule: &model.Schedule{TimeZone: utils.Ptr("UTC")}}
cl2 = &model.Client{Name: utils.Ptr("foo"), BlockedServicesSchedule: &model.Schedule{TimeZone: utils.Ptr("Local")}}
cl1 = &model.Client{
Name: utils.Ptr("foo"),
BlockedServicesSchedule: &model.Schedule{TimeZone: utils.Ptr("UTC")},
}
cl2 = &model.Client{
Name: utils.Ptr("foo"),
BlockedServicesSchedule: &model.Schedule{TimeZone: utils.Ptr("Local")},
}
})
It("should equal if only timezone differs on empty blocked service schedule", func() {

View File

@@ -0,0 +1,175 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"definitions": {
"Instance": {
"additionalProperties": false,
"properties": {
"apiPath": {
"type": "string"
},
"autoSetup": {
"type": "boolean"
},
"cookie": {
"type": "string"
},
"dhcpServerEnabled": {
"type": "boolean"
},
"insecureSkipVerify": {
"type": "boolean"
},
"interfaceName": {
"type": "string"
},
"password": {
"type": "string"
},
"url": {
"format": "uri",
"type": "string"
},
"username": {
"type": "string"
},
"webURL": {
"format": "uri",
"type": "string"
}
},
"type": "object"
}
},
"description": "validates only for valid schema. No required fields, as the can be defined via env ars afterwards.",
"properties": {
"api": {
"additionalProperties": false,
"properties": {
"darkMode": {
"type": "boolean"
},
"metrics": {
"additionalProperties": false,
"properties": {
"enabled": {
"type": "boolean"
},
"queryLogLimit": {
"type": "integer"
},
"scrapeInterval": {
"type": "string"
}
},
"type": "object"
},
"password": {
"type": "string"
},
"port": {
"type": "number"
},
"tls": {
"additionalProperties": false,
"properties": {
"certDir": {
"type": "string"
},
"certName": {
"type": "string"
},
"keyName": {
"type": "string"
}
},
"type": "object"
},
"username": {
"type": "string"
}
},
"type": "object"
},
"continueOnError": {
"type": "boolean"
},
"cron": {
"type": "string"
},
"features": {
"additionalProperties": false,
"properties": {
"clientSettings": {
"type": "boolean"
},
"dhcp": {
"additionalProperties": false,
"properties": {
"serverConfig": {
"type": "boolean"
},
"staticLeases": {
"type": "boolean"
}
},
"type": "object"
},
"dns": {
"additionalProperties": false,
"properties": {
"accessLists": {
"type": "boolean"
},
"rewrites": {
"type": "boolean"
},
"serverConfig": {
"type": "boolean"
}
},
"type": "object"
},
"filters": {
"type": "boolean"
},
"generalSettings": {
"type": "boolean"
},
"queryLogConfig": {
"type": "boolean"
},
"services": {
"type": "boolean"
},
"statsConfig": {
"type": "boolean"
},
"theme": {
"type": "boolean"
}
},
"type": "object"
},
"origin": {
"$ref": "#/definitions/Instance"
},
"printConfigOnly": {
"type": "boolean"
},
"replica": {
"$ref": "#/definitions/Instance"
},
"replicas": {
"items": {
"$ref": "#/definitions/Instance"
},
"type": "array"
},
"runOnStart": {
"type": "boolean"
}
},
"title": "adguardhome-sync Configuration",
"type": "object"
}

View File

@@ -6,7 +6,7 @@ import (
"github.com/bakito/adguardhome-sync/pkg/log"
"github.com/bakito/adguardhome-sync/pkg/types"
"github.com/caarlos0/env/v10"
"github.com/caarlos0/env/v11"
)
var (
@@ -20,6 +20,10 @@ func Get(configFile string, flags Flags) (*types.Config, error) {
return nil, err
}
if err = validateSchema(path); err != nil {
return nil, err
}
cfg := initialConfig()
// read yaml config
@@ -39,19 +43,26 @@ func Get(configFile string, flags Flags) (*types.Config, error) {
replicaDhcpServer := cfg.Replica.DHCPServerEnabled
cfg.Replica.DHCPServerEnabled = nil
// ignore replicas form env parsing as they are handled separately
replicas := cfg.Replicas
cfg.Replicas = nil
// overwrite from env vars
if err := env.Parse(cfg); err != nil {
if err = env.Parse(cfg); err != nil {
return nil, err
}
if err := env.ParseWithOptions(cfg.Replica, env.Options{Prefix: "REPLICA_"}); err != nil {
if err = env.ParseWithOptions(cfg.Replica, env.Options{Prefix: "REPLICA_"}); err != nil {
return nil, err
}
// restore the replica
cfg.Replicas = replicas
// if not set from env, use previous value
if cfg.Replica.DHCPServerEnabled == nil {
cfg.Replica.DHCPServerEnabled = replicaDhcpServer
}
if err := env.ParseWithOptions(&cfg.Origin, env.Options{Prefix: "ORIGIN_"}); err != nil {
if err = env.ParseWithOptions(&cfg.Origin, env.Options{Prefix: "ORIGIN_"}); err != nil {
return nil, err
}

View File

@@ -17,6 +17,7 @@ var envVars = []string{
"FEATURES_CLIENT_SETTINGS",
"FEATURES_SERVICES",
"FEATURES_FILTERS",
"FEATURES_THEME",
"FEATURES_DHCP_SERVER_CONFIG",
"FEATURES_DHCP_STATIC_LEASES",
"FEATURES_DNS_SERVER_CONFIG",

View File

@@ -8,7 +8,7 @@ import (
"github.com/bakito/adguardhome-sync/pkg/types"
"github.com/bakito/adguardhome-sync/pkg/utils"
"github.com/caarlos0/env/v10"
"github.com/caarlos0/env/v11"
)
func handleDeprecatedEnvVars(cfg *types.Config) {

52
pkg/config/validate.go Normal file
View File

@@ -0,0 +1,52 @@
package config
import (
_ "embed"
"os"
"strings"
"github.com/santhosh-tekuri/jsonschema/v6"
"gopkg.in/yaml.v3"
)
const schemaURL = "config-schema.json"
//go:embed config-schema.json
var schemaData string
func validateSchema(cfgFile string) error {
// ignore if file not exists
if _, err := os.Stat(cfgFile); err != nil {
return nil
}
// Load YAML file
yamlContent, err := os.ReadFile(cfgFile)
if err != nil {
return err
}
return validateYAML(yamlContent)
}
func validateYAML(yamlContent []byte) error {
// Convert YAML to JSON
var yamlData interface{}
err := yaml.Unmarshal(yamlContent, &yamlData)
if err != nil {
return err
}
// Load JSON schema
sch, err := jsonschema.UnmarshalJSON(strings.NewReader(schemaData))
if err != nil {
return err
}
c := jsonschema.NewCompiler()
if err := c.AddResource(schemaURL, sch); err != nil {
return err
}
schema := c.MustCompile(schemaURL)
// validateSchema
return schema.Validate(yamlData)
}

View File

@@ -0,0 +1,39 @@
package config
import (
"github.com/bakito/adguardhome-sync/pkg/types"
"github.com/go-faker/faker/v4"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"gopkg.in/yaml.v3"
)
var _ = Describe("Config", func() {
Context("validateSchema", func() {
DescribeTable("validateSchema config",
func(configFile string, expectFail bool) {
err := validateSchema(configFile)
if expectFail {
Ω(err).Should(HaveOccurred())
} else {
Ω(err).ShouldNot(HaveOccurred())
}
},
Entry(`Should be valid`, "../../testdata/config/config-valid.yaml", false),
Entry(`Should be valid if file doesn't exist`, "../../testdata/config/foo.bar", false),
Entry(`Should fail if file is not yaml`, "../../go.mod", true),
)
It("validate config with all fields randomly populated", func() {
cfg := &types.Config{}
err := faker.FakeData(cfg)
Ω(err).ShouldNot(HaveOccurred())
data, err := yaml.Marshal(&cfg)
Ω(err).ShouldNot(HaveOccurred())
err = validateYAML(data)
Ω(err).ShouldNot(HaveOccurred())
})
})
})

View File

@@ -4,9 +4,10 @@ import (
"github.com/bakito/adguardhome-sync/pkg/client/model"
"github.com/bakito/adguardhome-sync/pkg/log"
"github.com/prometheus/client_golang/prometheus"
"golang.org/x/exp/constraints"
)
const StatsTotal = "total"
var (
l = log.GetLogger("metrics")
@@ -129,6 +130,8 @@ var (
},
[]string{"hostname"},
)
stats = OverallStats{}
)
// Init initializes all Prometheus metrics made available by AdGuard exporter.
@@ -155,6 +158,7 @@ func initMetric(name string, metric *prometheus.GaugeVec) {
func Update(ims ...InstanceMetrics) {
for _, im := range ims {
update(im)
stats[im.HostName] = im.Stats
}
l.Debug("updated")
@@ -233,13 +237,28 @@ type InstanceMetrics struct {
QueryLog *model.QueryLog
}
func safeMetric[T Number](v *T) float64 {
type OverallStats map[string]*model.Stats
func (os OverallStats) consolidate() OverallStats {
consolidated := OverallStats{StatsTotal: model.NewStats()}
for host, stats := range os {
consolidated[host] = stats
consolidated[StatsTotal].Add(stats)
}
return consolidated
}
func safeMetric[T int | float64 | float32](v *T) float64 {
if v == nil {
return 0
}
return float64(*v)
}
type Number interface {
constraints.Float | constraints.Integer
func GetStats() OverallStats {
return stats.consolidate()
}
func (os OverallStats) Total() *model.Stats {
return os[StatsTotal]
}

View File

@@ -20,6 +20,7 @@ import (
type MockClient struct {
ctrl *gomock.Controller
recorder *MockClientMockRecorder
isgomock struct{}
}
// MockClientMockRecorder is the mock recorder for MockClient.
@@ -55,52 +56,52 @@ func (mr *MockClientMockRecorder) AccessList() *gomock.Call {
}
// AddClient mocks base method.
func (m *MockClient) AddClient(arg0 *model.Client) error {
func (m *MockClient) AddClient(client *model.Client) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AddClient", arg0)
ret := m.ctrl.Call(m, "AddClient", client)
ret0, _ := ret[0].(error)
return ret0
}
// AddClient indicates an expected call of AddClient.
func (mr *MockClientMockRecorder) AddClient(arg0 any) *gomock.Call {
func (mr *MockClientMockRecorder) AddClient(client any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddClient", reflect.TypeOf((*MockClient)(nil).AddClient), arg0)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddClient", reflect.TypeOf((*MockClient)(nil).AddClient), client)
}
// AddDHCPStaticLease mocks base method.
func (m *MockClient) AddDHCPStaticLease(arg0 model.DhcpStaticLease) error {
func (m *MockClient) AddDHCPStaticLease(lease model.DhcpStaticLease) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AddDHCPStaticLease", arg0)
ret := m.ctrl.Call(m, "AddDHCPStaticLease", lease)
ret0, _ := ret[0].(error)
return ret0
}
// AddDHCPStaticLease indicates an expected call of AddDHCPStaticLease.
func (mr *MockClientMockRecorder) AddDHCPStaticLease(arg0 any) *gomock.Call {
func (mr *MockClientMockRecorder) AddDHCPStaticLease(lease any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddDHCPStaticLease", reflect.TypeOf((*MockClient)(nil).AddDHCPStaticLease), arg0)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddDHCPStaticLease", reflect.TypeOf((*MockClient)(nil).AddDHCPStaticLease), lease)
}
// AddFilter mocks base method.
func (m *MockClient) AddFilter(arg0 bool, arg1 model.Filter) error {
func (m *MockClient) AddFilter(whitelist bool, f model.Filter) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "AddFilter", arg0, arg1)
ret := m.ctrl.Call(m, "AddFilter", whitelist, f)
ret0, _ := ret[0].(error)
return ret0
}
// AddFilter indicates an expected call of AddFilter.
func (mr *MockClientMockRecorder) AddFilter(arg0, arg1 any) *gomock.Call {
func (mr *MockClientMockRecorder) AddFilter(whitelist, f any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddFilter", reflect.TypeOf((*MockClient)(nil).AddFilter), arg0, arg1)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddFilter", reflect.TypeOf((*MockClient)(nil).AddFilter), whitelist, f)
}
// AddRewriteEntries mocks base method.
func (m *MockClient) AddRewriteEntries(arg0 ...model.RewriteEntry) error {
func (m *MockClient) AddRewriteEntries(e ...model.RewriteEntry) error {
m.ctrl.T.Helper()
varargs := []any{}
for _, a := range arg0 {
for _, a := range e {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "AddRewriteEntries", varargs...)
@@ -109,9 +110,9 @@ func (m *MockClient) AddRewriteEntries(arg0 ...model.RewriteEntry) error {
}
// AddRewriteEntries indicates an expected call of AddRewriteEntries.
func (mr *MockClientMockRecorder) AddRewriteEntries(arg0 ...any) *gomock.Call {
func (mr *MockClientMockRecorder) AddRewriteEntries(e ...any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRewriteEntries", reflect.TypeOf((*MockClient)(nil).AddRewriteEntries), arg0...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRewriteEntries", reflect.TypeOf((*MockClient)(nil).AddRewriteEntries), e...)
}
// BlockedServicesSchedule mocks base method.
@@ -160,52 +161,52 @@ func (mr *MockClientMockRecorder) DNSConfig() *gomock.Call {
}
// DeleteClient mocks base method.
func (m *MockClient) DeleteClient(arg0 *model.Client) error {
func (m *MockClient) DeleteClient(client *model.Client) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "DeleteClient", arg0)
ret := m.ctrl.Call(m, "DeleteClient", client)
ret0, _ := ret[0].(error)
return ret0
}
// DeleteClient indicates an expected call of DeleteClient.
func (mr *MockClientMockRecorder) DeleteClient(arg0 any) *gomock.Call {
func (mr *MockClientMockRecorder) DeleteClient(client any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteClient", reflect.TypeOf((*MockClient)(nil).DeleteClient), arg0)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteClient", reflect.TypeOf((*MockClient)(nil).DeleteClient), client)
}
// DeleteDHCPStaticLease mocks base method.
func (m *MockClient) DeleteDHCPStaticLease(arg0 model.DhcpStaticLease) error {
func (m *MockClient) DeleteDHCPStaticLease(lease model.DhcpStaticLease) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "DeleteDHCPStaticLease", arg0)
ret := m.ctrl.Call(m, "DeleteDHCPStaticLease", lease)
ret0, _ := ret[0].(error)
return ret0
}
// DeleteDHCPStaticLease indicates an expected call of DeleteDHCPStaticLease.
func (mr *MockClientMockRecorder) DeleteDHCPStaticLease(arg0 any) *gomock.Call {
func (mr *MockClientMockRecorder) DeleteDHCPStaticLease(lease any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteDHCPStaticLease", reflect.TypeOf((*MockClient)(nil).DeleteDHCPStaticLease), arg0)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteDHCPStaticLease", reflect.TypeOf((*MockClient)(nil).DeleteDHCPStaticLease), lease)
}
// DeleteFilter mocks base method.
func (m *MockClient) DeleteFilter(arg0 bool, arg1 model.Filter) error {
func (m *MockClient) DeleteFilter(whitelist bool, f model.Filter) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "DeleteFilter", arg0, arg1)
ret := m.ctrl.Call(m, "DeleteFilter", whitelist, f)
ret0, _ := ret[0].(error)
return ret0
}
// DeleteFilter indicates an expected call of DeleteFilter.
func (mr *MockClientMockRecorder) DeleteFilter(arg0, arg1 any) *gomock.Call {
func (mr *MockClientMockRecorder) DeleteFilter(whitelist, f any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteFilter", reflect.TypeOf((*MockClient)(nil).DeleteFilter), arg0, arg1)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteFilter", reflect.TypeOf((*MockClient)(nil).DeleteFilter), whitelist, f)
}
// DeleteRewriteEntries mocks base method.
func (m *MockClient) DeleteRewriteEntries(arg0 ...model.RewriteEntry) error {
func (m *MockClient) DeleteRewriteEntries(e ...model.RewriteEntry) error {
m.ctrl.T.Helper()
varargs := []any{}
for _, a := range arg0 {
for _, a := range e {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "DeleteRewriteEntries", varargs...)
@@ -214,9 +215,9 @@ func (m *MockClient) DeleteRewriteEntries(arg0 ...model.RewriteEntry) error {
}
// DeleteRewriteEntries indicates an expected call of DeleteRewriteEntries.
func (mr *MockClientMockRecorder) DeleteRewriteEntries(arg0 ...any) *gomock.Call {
func (mr *MockClientMockRecorder) DeleteRewriteEntries(e ...any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRewriteEntries", reflect.TypeOf((*MockClient)(nil).DeleteRewriteEntries), arg0...)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRewriteEntries", reflect.TypeOf((*MockClient)(nil).DeleteRewriteEntries), e...)
}
// DhcpConfig mocks base method.
@@ -294,18 +295,18 @@ func (mr *MockClientMockRecorder) ProfileInfo() *gomock.Call {
}
// QueryLog mocks base method.
func (m *MockClient) QueryLog(arg0 int) (*model.QueryLog, error) {
func (m *MockClient) QueryLog(limit int) (*model.QueryLog, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "QueryLog", arg0)
ret := m.ctrl.Call(m, "QueryLog", limit)
ret0, _ := ret[0].(*model.QueryLog)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// QueryLog indicates an expected call of QueryLog.
func (mr *MockClientMockRecorder) QueryLog(arg0 any) *gomock.Call {
func (mr *MockClientMockRecorder) QueryLog(limit any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryLog", reflect.TypeOf((*MockClient)(nil).QueryLog), arg0)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "QueryLog", reflect.TypeOf((*MockClient)(nil).QueryLog), limit)
}
// QueryLogConfig mocks base method.
@@ -324,17 +325,17 @@ func (mr *MockClientMockRecorder) QueryLogConfig() *gomock.Call {
}
// RefreshFilters mocks base method.
func (m *MockClient) RefreshFilters(arg0 bool) error {
func (m *MockClient) RefreshFilters(whitelist bool) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "RefreshFilters", arg0)
ret := m.ctrl.Call(m, "RefreshFilters", whitelist)
ret0, _ := ret[0].(error)
return ret0
}
// RefreshFilters indicates an expected call of RefreshFilters.
func (mr *MockClientMockRecorder) RefreshFilters(arg0 any) *gomock.Call {
func (mr *MockClientMockRecorder) RefreshFilters(whitelist any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RefreshFilters", reflect.TypeOf((*MockClient)(nil).RefreshFilters), arg0)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RefreshFilters", reflect.TypeOf((*MockClient)(nil).RefreshFilters), whitelist)
}
// RewriteList mocks base method.
@@ -397,31 +398,31 @@ func (mr *MockClientMockRecorder) SetAccessList(arg0 any) *gomock.Call {
}
// SetBlockedServicesSchedule mocks base method.
func (m *MockClient) SetBlockedServicesSchedule(arg0 *model.BlockedServicesSchedule) error {
func (m *MockClient) SetBlockedServicesSchedule(schedule *model.BlockedServicesSchedule) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SetBlockedServicesSchedule", arg0)
ret := m.ctrl.Call(m, "SetBlockedServicesSchedule", schedule)
ret0, _ := ret[0].(error)
return ret0
}
// SetBlockedServicesSchedule indicates an expected call of SetBlockedServicesSchedule.
func (mr *MockClientMockRecorder) SetBlockedServicesSchedule(arg0 any) *gomock.Call {
func (mr *MockClientMockRecorder) SetBlockedServicesSchedule(schedule any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetBlockedServicesSchedule", reflect.TypeOf((*MockClient)(nil).SetBlockedServicesSchedule), arg0)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetBlockedServicesSchedule", reflect.TypeOf((*MockClient)(nil).SetBlockedServicesSchedule), schedule)
}
// SetCustomRules mocks base method.
func (m *MockClient) SetCustomRules(arg0 *[]string) error {
func (m *MockClient) SetCustomRules(rules *[]string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SetCustomRules", arg0)
ret := m.ctrl.Call(m, "SetCustomRules", rules)
ret0, _ := ret[0].(error)
return ret0
}
// SetCustomRules indicates an expected call of SetCustomRules.
func (mr *MockClientMockRecorder) SetCustomRules(arg0 any) *gomock.Call {
func (mr *MockClientMockRecorder) SetCustomRules(rules any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetCustomRules", reflect.TypeOf((*MockClient)(nil).SetCustomRules), arg0)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetCustomRules", reflect.TypeOf((*MockClient)(nil).SetCustomRules), rules)
}
// SetDNSConfig mocks base method.
@@ -453,17 +454,17 @@ func (mr *MockClientMockRecorder) SetDhcpConfig(arg0 any) *gomock.Call {
}
// SetProfileInfo mocks base method.
func (m *MockClient) SetProfileInfo(arg0 *model.ProfileInfo) error {
func (m *MockClient) SetProfileInfo(settings *model.ProfileInfo) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SetProfileInfo", arg0)
ret := m.ctrl.Call(m, "SetProfileInfo", settings)
ret0, _ := ret[0].(error)
return ret0
}
// SetProfileInfo indicates an expected call of SetProfileInfo.
func (mr *MockClientMockRecorder) SetProfileInfo(arg0 any) *gomock.Call {
func (mr *MockClientMockRecorder) SetProfileInfo(settings any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetProfileInfo", reflect.TypeOf((*MockClient)(nil).SetProfileInfo), arg0)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetProfileInfo", reflect.TypeOf((*MockClient)(nil).SetProfileInfo), settings)
}
// SetQueryLogConfig mocks base method.
@@ -481,31 +482,31 @@ func (mr *MockClientMockRecorder) SetQueryLogConfig(arg0 any) *gomock.Call {
}
// SetSafeSearchConfig mocks base method.
func (m *MockClient) SetSafeSearchConfig(arg0 *model.SafeSearchConfig) error {
func (m *MockClient) SetSafeSearchConfig(settings *model.SafeSearchConfig) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SetSafeSearchConfig", arg0)
ret := m.ctrl.Call(m, "SetSafeSearchConfig", settings)
ret0, _ := ret[0].(error)
return ret0
}
// SetSafeSearchConfig indicates an expected call of SetSafeSearchConfig.
func (mr *MockClientMockRecorder) SetSafeSearchConfig(arg0 any) *gomock.Call {
func (mr *MockClientMockRecorder) SetSafeSearchConfig(settings any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSafeSearchConfig", reflect.TypeOf((*MockClient)(nil).SetSafeSearchConfig), arg0)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSafeSearchConfig", reflect.TypeOf((*MockClient)(nil).SetSafeSearchConfig), settings)
}
// SetStatsConfig mocks base method.
func (m *MockClient) SetStatsConfig(arg0 *model.GetStatsConfigResponse) error {
func (m *MockClient) SetStatsConfig(sc *model.GetStatsConfigResponse) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "SetStatsConfig", arg0)
ret := m.ctrl.Call(m, "SetStatsConfig", sc)
ret0, _ := ret[0].(error)
return ret0
}
// SetStatsConfig indicates an expected call of SetStatsConfig.
func (mr *MockClientMockRecorder) SetStatsConfig(arg0 any) *gomock.Call {
func (mr *MockClientMockRecorder) SetStatsConfig(sc any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetStatsConfig", reflect.TypeOf((*MockClient)(nil).SetStatsConfig), arg0)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetStatsConfig", reflect.TypeOf((*MockClient)(nil).SetStatsConfig), sc)
}
// Setup mocks base method.
@@ -568,85 +569,85 @@ func (mr *MockClientMockRecorder) Status() *gomock.Call {
}
// ToggleFiltering mocks base method.
func (m *MockClient) ToggleFiltering(arg0 bool, arg1 int) error {
func (m *MockClient) ToggleFiltering(enabled bool, interval int) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ToggleFiltering", arg0, arg1)
ret := m.ctrl.Call(m, "ToggleFiltering", enabled, interval)
ret0, _ := ret[0].(error)
return ret0
}
// ToggleFiltering indicates an expected call of ToggleFiltering.
func (mr *MockClientMockRecorder) ToggleFiltering(arg0, arg1 any) *gomock.Call {
func (mr *MockClientMockRecorder) ToggleFiltering(enabled, interval any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ToggleFiltering", reflect.TypeOf((*MockClient)(nil).ToggleFiltering), arg0, arg1)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ToggleFiltering", reflect.TypeOf((*MockClient)(nil).ToggleFiltering), enabled, interval)
}
// ToggleParental mocks base method.
func (m *MockClient) ToggleParental(arg0 bool) error {
func (m *MockClient) ToggleParental(enable bool) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ToggleParental", arg0)
ret := m.ctrl.Call(m, "ToggleParental", enable)
ret0, _ := ret[0].(error)
return ret0
}
// ToggleParental indicates an expected call of ToggleParental.
func (mr *MockClientMockRecorder) ToggleParental(arg0 any) *gomock.Call {
func (mr *MockClientMockRecorder) ToggleParental(enable any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ToggleParental", reflect.TypeOf((*MockClient)(nil).ToggleParental), arg0)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ToggleParental", reflect.TypeOf((*MockClient)(nil).ToggleParental), enable)
}
// ToggleProtection mocks base method.
func (m *MockClient) ToggleProtection(arg0 bool) error {
func (m *MockClient) ToggleProtection(enable bool) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ToggleProtection", arg0)
ret := m.ctrl.Call(m, "ToggleProtection", enable)
ret0, _ := ret[0].(error)
return ret0
}
// ToggleProtection indicates an expected call of ToggleProtection.
func (mr *MockClientMockRecorder) ToggleProtection(arg0 any) *gomock.Call {
func (mr *MockClientMockRecorder) ToggleProtection(enable any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ToggleProtection", reflect.TypeOf((*MockClient)(nil).ToggleProtection), arg0)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ToggleProtection", reflect.TypeOf((*MockClient)(nil).ToggleProtection), enable)
}
// ToggleSafeBrowsing mocks base method.
func (m *MockClient) ToggleSafeBrowsing(arg0 bool) error {
func (m *MockClient) ToggleSafeBrowsing(enable bool) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ToggleSafeBrowsing", arg0)
ret := m.ctrl.Call(m, "ToggleSafeBrowsing", enable)
ret0, _ := ret[0].(error)
return ret0
}
// ToggleSafeBrowsing indicates an expected call of ToggleSafeBrowsing.
func (mr *MockClientMockRecorder) ToggleSafeBrowsing(arg0 any) *gomock.Call {
func (mr *MockClientMockRecorder) ToggleSafeBrowsing(enable any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ToggleSafeBrowsing", reflect.TypeOf((*MockClient)(nil).ToggleSafeBrowsing), arg0)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ToggleSafeBrowsing", reflect.TypeOf((*MockClient)(nil).ToggleSafeBrowsing), enable)
}
// UpdateClient mocks base method.
func (m *MockClient) UpdateClient(arg0 *model.Client) error {
func (m *MockClient) UpdateClient(client *model.Client) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "UpdateClient", arg0)
ret := m.ctrl.Call(m, "UpdateClient", client)
ret0, _ := ret[0].(error)
return ret0
}
// UpdateClient indicates an expected call of UpdateClient.
func (mr *MockClientMockRecorder) UpdateClient(arg0 any) *gomock.Call {
func (mr *MockClientMockRecorder) UpdateClient(client any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateClient", reflect.TypeOf((*MockClient)(nil).UpdateClient), arg0)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateClient", reflect.TypeOf((*MockClient)(nil).UpdateClient), client)
}
// UpdateFilter mocks base method.
func (m *MockClient) UpdateFilter(arg0 bool, arg1 model.Filter) error {
func (m *MockClient) UpdateFilter(whitelist bool, f model.Filter) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "UpdateFilter", arg0, arg1)
ret := m.ctrl.Call(m, "UpdateFilter", whitelist, f)
ret0, _ := ret[0].(error)
return ret0
}
// UpdateFilter indicates an expected call of UpdateFilter.
func (mr *MockClientMockRecorder) UpdateFilter(arg0, arg1 any) *gomock.Call {
func (mr *MockClientMockRecorder) UpdateFilter(whitelist, f any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateFilter", reflect.TypeOf((*MockClient)(nil).UpdateFilter), arg0, arg1)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateFilter", reflect.TypeOf((*MockClient)(nil).UpdateFilter), whitelist, f)
}

View File

@@ -19,6 +19,7 @@ import (
type MockFlags struct {
ctrl *gomock.Controller
recorder *MockFlagsMockRecorder
isgomock struct{}
}
// MockFlagsMockRecorder is the mock recorder for MockFlags.
@@ -39,60 +40,60 @@ func (m *MockFlags) EXPECT() *MockFlagsMockRecorder {
}
// Changed mocks base method.
func (m *MockFlags) Changed(arg0 string) bool {
func (m *MockFlags) Changed(name string) bool {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Changed", arg0)
ret := m.ctrl.Call(m, "Changed", name)
ret0, _ := ret[0].(bool)
return ret0
}
// Changed indicates an expected call of Changed.
func (mr *MockFlagsMockRecorder) Changed(arg0 any) *gomock.Call {
func (mr *MockFlagsMockRecorder) Changed(name any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Changed", reflect.TypeOf((*MockFlags)(nil).Changed), arg0)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Changed", reflect.TypeOf((*MockFlags)(nil).Changed), name)
}
// GetBool mocks base method.
func (m *MockFlags) GetBool(arg0 string) (bool, error) {
func (m *MockFlags) GetBool(name string) (bool, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetBool", arg0)
ret := m.ctrl.Call(m, "GetBool", name)
ret0, _ := ret[0].(bool)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetBool indicates an expected call of GetBool.
func (mr *MockFlagsMockRecorder) GetBool(arg0 any) *gomock.Call {
func (mr *MockFlagsMockRecorder) GetBool(name any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBool", reflect.TypeOf((*MockFlags)(nil).GetBool), arg0)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetBool", reflect.TypeOf((*MockFlags)(nil).GetBool), name)
}
// GetInt mocks base method.
func (m *MockFlags) GetInt(arg0 string) (int, error) {
func (m *MockFlags) GetInt(name string) (int, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetInt", arg0)
ret := m.ctrl.Call(m, "GetInt", name)
ret0, _ := ret[0].(int)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetInt indicates an expected call of GetInt.
func (mr *MockFlagsMockRecorder) GetInt(arg0 any) *gomock.Call {
func (mr *MockFlagsMockRecorder) GetInt(name any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetInt", reflect.TypeOf((*MockFlags)(nil).GetInt), arg0)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetInt", reflect.TypeOf((*MockFlags)(nil).GetInt), name)
}
// GetString mocks base method.
func (m *MockFlags) GetString(arg0 string) (string, error) {
func (m *MockFlags) GetString(name string) (string, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetString", arg0)
ret := m.ctrl.Call(m, "GetString", name)
ret0, _ := ret[0].(string)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// GetString indicates an expected call of GetString.
func (mr *MockFlagsMockRecorder) GetString(arg0 any) *gomock.Call {
func (mr *MockFlagsMockRecorder) GetString(name any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetString", reflect.TypeOf((*MockFlags)(nil).GetString), arg0)
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetString", reflect.TypeOf((*MockFlags)(nil).GetString), name)
}

View File

@@ -11,7 +11,7 @@ var (
actionProfileInfo = func(ac *actionContext) error {
if pro, err := ac.client.ProfileInfo(); err != nil {
return err
} else if merged := pro.ShouldSyncFor(ac.origin.profileInfo); merged != nil {
} else if merged := pro.ShouldSyncFor(ac.origin.profileInfo, ac.cfg.Features.Theme); merged != nil {
return ac.client.SetProfileInfo(merged)
}
return nil
@@ -94,10 +94,10 @@ var (
return err
}
if err = syncFilterType(ac.rl, ac.origin.filters.Filters, rf.Filters, false, ac.client, ac.continueOnError); err != nil {
if err = syncFilterType(ac.rl, ac.origin.filters.Filters, rf.Filters, false, ac.client, ac.cfg.ContinueOnError); err != nil {
return err
}
if err = syncFilterType(ac.rl, ac.origin.filters.WhitelistFilters, rf.WhitelistFilters, true, ac.client, ac.continueOnError); err != nil {
if err = syncFilterType(ac.rl, ac.origin.filters.WhitelistFilters, rf.WhitelistFilters, true, ac.client, ac.cfg.ContinueOnError); err != nil {
return err
}
@@ -105,7 +105,8 @@ var (
return ac.client.SetCustomRules(ac.origin.filters.UserRules)
}
if ac.origin.filters.Enabled != rf.Enabled || ac.origin.filters.Interval != rf.Interval {
if !utils.PtrEquals(ac.origin.filters.Enabled, rf.Enabled) ||
!utils.PtrEquals(ac.origin.filters.Interval, rf.Interval) {
return ac.client.ToggleFiltering(*ac.origin.filters.Enabled, *ac.origin.filters.Interval)
}
return nil
@@ -133,7 +134,7 @@ var (
for _, client := range r {
if err := ac.client.DeleteClient(client); err != nil {
ac.rl.With("client-name", client.Name, "error", err).Error("error deleting client setting")
if !ac.continueOnError {
if !ac.cfg.ContinueOnError {
return err
}
}
@@ -142,7 +143,7 @@ var (
for _, client := range a {
if err := ac.client.AddClient(client); err != nil {
ac.rl.With("client-name", client.Name, "error", err).Error("error adding client setting")
if !ac.continueOnError {
if !ac.cfg.ContinueOnError {
return err
}
}
@@ -151,7 +152,7 @@ var (
for _, client := range u {
if err := ac.client.UpdateClient(client); err != nil {
ac.rl.With("client-name", client.Name, "error", err).Error("error updating client setting")
if !ac.continueOnError {
if !ac.cfg.ContinueOnError {
return err
}
}
@@ -218,7 +219,7 @@ var (
for _, lease := range r {
if err := ac.client.DeleteDHCPStaticLease(lease); err != nil {
ac.rl.With("hostname", lease.Hostname, "error", err).Error("error deleting dhcp static lease")
if !ac.continueOnError {
if !ac.cfg.ContinueOnError {
return err
}
}
@@ -227,7 +228,7 @@ var (
for _, lease := range a {
if err := ac.client.AddDHCPStaticLease(lease); err != nil {
ac.rl.With("hostname", lease.Hostname, "error", err).Error("error adding dhcp static lease")
if !ac.continueOnError {
if !ac.cfg.ContinueOnError {
return err
}
}
@@ -236,7 +237,14 @@ var (
}
)
func syncFilterType(rl *zap.SugaredLogger, of *[]model.Filter, rFilters *[]model.Filter, whitelist bool, replica client.Client, continueOnError bool) error {
func syncFilterType(
rl *zap.SugaredLogger,
of *[]model.Filter,
rFilters *[]model.Filter,
whitelist bool,
replica client.Client,
continueOnError bool,
) error {
fa, fu, fd := model.MergeFilters(rFilters, of)
for _, f := range fd {

View File

@@ -17,6 +17,11 @@ func setupActions(cfg *types.Config) (actions []syncAction) {
action("safe browsing", actionSafeBrowsing),
)
}
if cfg.Features.DNS.ServerConfig {
actions = append(actions,
action("DNS server config", actionDNSServerConfig),
)
}
if cfg.Features.QueryLogConfig {
actions = append(actions,
action("query log config", actionQueryLogConfig),
@@ -52,12 +57,6 @@ func setupActions(cfg *types.Config) (actions []syncAction) {
action("DNS access lists", actionDNSAccessLists),
)
}
if cfg.Features.DNS.ServerConfig {
actions = append(actions,
action("DNS server config", actionDNSServerConfig),
)
}
if cfg.Features.DHCP.ServerConfig {
actions = append(actions,
action("DHCP server config", actionDHCPServerConfig),
@@ -81,8 +80,8 @@ type actionContext struct {
origin *origin
client client.Client
replicaStatus *model.ServerStatus
continueOnError bool
replica types.AdGuardInstance
cfg *types.Config
}
type defaultAction struct {

View File

@@ -33,11 +33,38 @@ func (w *worker) handleSync(c *gin.Context) {
}
func (w *worker) handleRoot(c *gin.Context) {
total, dns, blocked, malware, adult := statsGraph()
c.HTML(http.StatusOK, "index.html", map[string]interface{}{
"DarkMode": w.cfg.API.DarkMode,
"Metrics": w.cfg.API.Metrics.Enabled,
"Version": version.Version,
"Build": version.Build,
"SyncStatus": w.status(),
"Stats": map[string]interface{}{
"Labels": getLast24Hours(),
"DNS": dns,
"Blocked": blocked,
"BlockedPercentage": fmt.Sprintf(
"%.2f",
(float64(*total.NumBlockedFiltering)*100.0)/float64(*total.NumDnsQueries),
),
"Malware": malware,
"MalwarePercentage": fmt.Sprintf(
"%.2f",
(float64(*total.NumReplacedSafebrowsing)*100.0)/float64(*total.NumDnsQueries),
),
"Adult": adult,
"AdultPercentage": fmt.Sprintf(
"%.2f",
(float64(*total.NumReplacedParental)*100.0)/float64(*total.NumDnsQueries),
),
"TotalDNS": total.NumDnsQueries,
"TotalBlocked": total.NumBlockedFiltering,
"TotalMalware": total.NumReplacedSafebrowsing,
"TotalAdult": total.NumReplacedParental,
},
},
)
}
@@ -52,7 +79,7 @@ func (w *worker) handleLogs(c *gin.Context) {
func (w *worker) handleClearLogs(c *gin.Context) {
log.Clear()
c.Data(http.StatusOK, "text/plain", []byte{})
c.Status(http.StatusOK)
}
func (w *worker) handleStatus(c *gin.Context) {
@@ -159,3 +186,26 @@ type replicaStatus struct {
Error string `json:"error,omitempty"`
ProtectionEnabled *bool `json:"protection_enabled"`
}
func getLast24Hours() []string {
var result []string
currentTime := time.Now()
// Loop to get the last 24 hours
for i := 0; i < 24; i++ {
// Calculate the time for the current hour in the loop
timeInstance := currentTime.Add(time.Duration(-i) * time.Hour)
timeInstance = timeInstance.Truncate(time.Hour)
// Format the time as "14 Dec 17:00"
formattedTime := timeInstance.Format("02 Jan 15:04")
result = append(result, formattedTime)
}
// Reverse the slice to get the correct order (from oldest to latest)
for i, j := 0, len(result)-1; i < j; i, j = i+1, j-1 {
result[i], result[j] = result[j], result[i]
}
return result
}

View File

@@ -3,19 +3,13 @@
<title>AdGuardHome sync</title>
<script type="text/javascript" src="https://code.jquery.com/jquery-3.7.1.min.js">
</script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.12.9/dist/umd/popper.min.js"
integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous">
</script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/js/bootstrap.min.js"
integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous">
</script>
{{- if .DarkMode }}
<link rel="stylesheet" href="https://bootswatch.com/5/darkly/bootstrap.min.css"
crossorigin="anonymous">
{{- else }}
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-KyZXEAg3QhqLMpG8r+8fhAXLRk2vvoC2f3B09zVXn8CA5QIVfZOJ3BCsw2P0p/We"
crossOrigin="anonymous">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
crossorigin="anonymous">
{{- end }}
<script type="text/javascript">
$(document).ready(function () {
@@ -51,6 +45,43 @@
});
</script>
<link rel="shortcut icon" href="favicon.ico">
<style>
.stat-card {
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
padding: 15px;
text-align: left;
display: flex;
flex-direction: column;
justify-content: space-between;
height: 100%;
}
{{- if .Metrics }}
.stat-card h3 {
margin: 0;
font-size: 2rem;
}
.stat-card p {
margin: 5px 0;
font-size: 0.9rem;
}
.percentage {
font-size: 0.9rem;
text-align: right;
height: 20px;
}
canvas {
flex-grow: 1;
height: 100px !important;
}
{{- end }}
.button-row {
margin-top: 20px;
}
.btn-group {
margin: 5px;
}
</style>
</head>
<body>
<div class="container-fluid px-4">
@@ -60,12 +91,51 @@
<p class="h6">{{ .Version }} ({{ .Build }})</p>
</p>
</div>
<div class="row">
{{- if .Metrics }}
<div class="row g-4 d-flex">
<div class="col-12 col-md-3 d-flex">
<div class="stat-card flex-fill">
<div class="percentage"></div>
<h3 style="color: rgb(78, 141, 245);">{{.Stats.TotalDNS}}</h3>
<p>DNS Queries</p>
<canvas id="dnsQueriesChart"></canvas>
</div>
</div>
<div class="col-12 col-md-3 d-flex">
<div class="stat-card flex-fill">
<div class="percentage" style="color: rgb(255, 94, 94);">{{.Stats.BlockedPercentage}}%</div>
<h3 style="color: rgb(255, 94, 94);">{{.Stats.TotalBlocked}}</h3>
<p>Blocked by Filters</p>
<canvas id="blockedFiltersChart"></canvas>
</div>
</div>
<div class="col-12 col-md-3 d-flex">
<div class="stat-card flex-fill">
<div class="percentage" style="color: rgb(110, 224, 122);">{{.Stats.MalwarePercentage}}%</div>
<h3 style="color: rgb(110, 224, 122);">{{.Stats.TotalMalware}}</h3>
<p>Blocked malware/phishing</p>
<canvas id="malwareChart"></canvas>
</div>
</div>
<div class="col-12 col-md-3 d-flex">
<div class="stat-card flex-fill">
<div class="percentage" style="color: rgb(232, 198, 78);">{{.Stats.AdultPercentage}}%</div>
<h3 style="color: rgb(232, 198, 78);">{{.Stats.TotalAdult}}</h3>
<p>Blocked adult websites</p>
<canvas id="adultWebsitesChart"></canvas>
</div>
</div>
</div>
{{- end }}
<div class="row button-row">
<div class="col">
<div class="btn-group" role="group">
<button type="button" class="btn btn-success" id="sync">Synchronize</button>
<button type="button" class="btn btn-secondary" id="showLogs">Update Logs</button>
<button type="button" class="btn btn-secondary dropdown-toggle dropdown-toggle-split" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
<button type="button" class="btn btn-secondary dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
</button>
<div class="dropdown-menu">
<a class="dropdown-item" href="#" id="clearLogs">Clear Logs</a>
@@ -87,10 +157,97 @@
</div>
</div>
<div class="row mt-3">
<div class="col-12">
<div class="col-12 col-md-12">
<div class="stat-card">
<pre class="p-3 border"><code id="logs"></code></pre>
</div>
</div>
</div>
</div>
<!-- openssl dgst -sha384 -binary popper.min.js | openssl base64 -A -->
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.2/dist/umd/popper.min.js"
integrity="sha384-IQsoLXl5PILFhosVNubq5LC7Qb9DXgDA9i+tQ8Zj3iwWAwPtgFTxbJ8NT4GN1R8p" crossorigin="anonymous">
</script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js"
integrity="sha384-0pUGZvbkm6XF6gxjEnlmuGrJXVbNuzT9qBBavbLwCsOGabYfZo0T0to5eqruptLy" crossorigin="anonymous">
</script>
{{- if .Metrics }}
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.7/dist/chart.umd.min.js"ŝ
integrity="sha384-vsrfeLOOY6KuIYKDlmVH5UiBmgIdB1oEf7p01YgWHuqmOHfZr374+odEv96n9tNC" crossorigin="anonymous">
</script>
<script>
// Function to create minimal line charts
function createChart(canvasId, data) {
const ctx = document.getElementById(canvasId).getContext('2d');
const datasets = Array(data.length);
for (let i = 0; i < data.length; i++) {
datasets[i] = {
data: data[i].data,
title: data[i].title,
backgroundColor: `rgb(${data[i].r}, ${data[i].g}, ${data[i].b}, 0.2)`,
borderColor: `rgb(${data[i].r}, ${data[i].g}, ${data[i].b}, 1)`,
borderWidth: 3,
fill: data[i].fill,
pointRadius: 0,
}
}
new Chart(ctx, {
type: 'line',
data: {
labels: {{.Stats.Labels}},
datasets: datasets
},
options: {
responsive: true,
maintainAspectRatio: false,
interaction: {
mode: 'index',
intersect: false,
},
plugins: {
legend: { display: false },
tooltip: {
enabled: true,
bodyFont: {
size: 20
},
titleFont: {
size: 20
},
displayColors: false,
callbacks: {
label: function(tooltipItem) {
if (tooltipItem.dataset.title) {
return tooltipItem.raw + " - " + tooltipItem.dataset.title;
}
return tooltipItem.raw;
}
}
}
},
scales: {
x: { display: false,
title: {
display: true
}
},
y: { display: false,
min: 0,
title: {
display: true
} }
}
}
});
}
createChart('dnsQueriesChart', {{.Stats.DNS}});
createChart('blockedFiltersChart', {{.Stats.Blocked}});
createChart('malwareChart', {{.Stats.Malware}});
createChart('adultWebsitesChart', {{.Stats.Adult}});
</script>
{{- end }}
</body>
</html>

129
pkg/sync/stats.go Normal file
View File

@@ -0,0 +1,129 @@
package sync
import (
"slices"
"strings"
"github.com/bakito/adguardhome-sync/pkg/client/model"
"github.com/bakito/adguardhome-sync/pkg/metrics"
)
var (
blue = []int{78, 141, 245}
blueAlternatives = [][]int{
{44, 95, 163},
{122, 166, 247},
{30, 61, 92},
{93, 158, 255},
{58, 123, 213},
}
red = []int{255, 94, 94}
redAlternatives = [][]int{
{204, 59, 59},
{255, 127, 127},
{140, 36, 36},
{255, 153, 153},
{255, 66, 66},
}
yellow = []int{232, 198, 78}
yellowAlternatives = [][]int{
{196, 163, 60},
{255, 220, 110},
{140, 114, 36},
{250, 233, 156},
{212, 180, 84},
}
green = []int{110, 224, 122}
greenAlternatives = [][]int{
{68, 160, 80},
{142, 255, 158},
{44, 140, 63},
{163, 255, 192},
{85, 198, 102},
}
)
func statsGraph() (*model.Stats, []line, []line, []line, []line) {
s := metrics.GetStats()
t := s.Total()
dns := graphLines(t, s, blue, blueAlternatives, func(s *model.Stats) []int {
return safeStats(s.DnsQueries)
})
blocked := graphLines(t, s, red, redAlternatives, func(s *model.Stats) []int {
return safeStats(s.BlockedFiltering)
})
malware := graphLines(t, s, green, greenAlternatives, func(s *model.Stats) []int {
return safeStats(s.ReplacedSafebrowsing)
})
adult := graphLines(t, s, yellow, yellowAlternatives, func(s *model.Stats) []int {
return safeStats(s.ReplacedParental)
})
return t, dns, blocked, malware, adult
}
func safeStats(stats *[]int) []int {
if stats == nil {
return make([]int, 0)
}
return *stats
}
func graphLines(
t *model.Stats,
s metrics.OverallStats,
baseColor []int,
altColors [][]int,
dataCB func(s *model.Stats) []int,
) []line {
g := &graph{
total: line{
Fill: true,
Title: "Total",
Data: dataCB(t),
R: baseColor[0],
G: baseColor[1],
B: baseColor[2],
},
}
var i int
for name, data := range s {
if name != metrics.StatsTotal {
g.replicas = append(g.replicas, line{
Fill: false,
Title: name,
Data: dataCB(data),
R: altColors[i%len(altColors)][0],
G: altColors[i%len(altColors)][1],
B: altColors[i%len(altColors)][2],
})
i++
}
}
lines := []line{g.total}
slices.SortFunc(g.replicas, func(a, b line) int {
return strings.Compare(a.Title, b.Title)
})
lines = append(lines, g.replicas...)
return lines
}
type graph struct {
total line
replicas []line
}
type line struct {
Data []int `json:"data"`
R int `json:"r"`
G int `json:"g"`
B int `json:"b"`
Title string `json:"title"`
Fill bool `json:"fill"`
}

View File

@@ -66,16 +66,12 @@ func Sync(cfg *types.Config) error {
if cfg.API.Port != 0 {
w.cron.Start()
} else {
runOnStartAsync(cfg, w)
w.cron.Run()
}
}
if cfg.API.Port != 0 {
if cfg.RunOnStart {
go func() {
l.Info("Running sync on startup")
w.sync()
}()
}
runOnStartAsync(cfg, w)
w.listenAndServe()
} else if cfg.RunOnStart {
l.Info("Running sync on startup")
@@ -85,6 +81,15 @@ func Sync(cfg *types.Config) error {
return nil
}
func runOnStartAsync(cfg *types.Config, w *worker) {
if cfg.RunOnStart {
go func() {
l.Info("Running sync on startup")
w.sync()
}()
}
}
type worker struct {
cfg *types.Config
running bool
@@ -167,7 +172,8 @@ func (w *worker) sync() {
}
if versions.IsNewerThan(versions.MinAgh, o.status.Version) {
sl.With("error", err, "version", o.status.Version).Errorf("Origin AdGuard Home version must be >= %s", versions.MinAgh)
sl.With("error", err, "version", o.status.Version).
Errorf("Origin AdGuard Home version must be >= %s", versions.MinAgh)
return
}
@@ -275,16 +281,18 @@ func (w *worker) syncTo(l *zap.SugaredLogger, o *origin, replica types.AdGuardIn
rl.With("version", replicaStatus.Version).Info("Connected to replica")
if versions.IsNewerThan(versions.MinAgh, replicaStatus.Version) {
rl.With("error", err, "version", replicaStatus.Version).Errorf("Replica AdGuard Home version must be >= %s", versions.MinAgh)
rl.With("error", err, "version", replicaStatus.Version).
Errorf("Replica AdGuard Home version must be >= %s", versions.MinAgh)
return
}
if o.status.Version != replicaStatus.Version {
rl.With("originVersion", o.status.Version, "replicaVersion", replicaStatus.Version).Warn("Versions do not match")
rl.With("originVersion", o.status.Version, "replicaVersion", replicaStatus.Version).
Warn("Versions do not match")
}
ac := &actionContext{
continueOnError: w.cfg.ContinueOnError,
cfg: w.cfg,
rl: rl,
origin: o,
replicaStatus: replicaStatus,
@@ -303,7 +311,11 @@ func (w *worker) syncTo(l *zap.SugaredLogger, o *origin, replica types.AdGuardIn
rl.Info("Sync done")
}
func (w *worker) statusWithSetup(rl *zap.SugaredLogger, replica types.AdGuardInstance, rc client.Client) (*model.ServerStatus, error) {
func (w *worker) statusWithSetup(
rl *zap.SugaredLogger,
replica types.AdGuardInstance,
rc client.Client,
) (*model.ServerStatus, error) {
rs, err := rc.Status()
if err != nil {
if replica.AutoSetup && errors.Is(err, client.ErrSetupNeeded) {

View File

@@ -48,6 +48,7 @@ var _ = Describe("Sync", func() {
GeneralSettings: true,
StatsConfig: true,
QueryLogConfig: true,
Theme: true,
},
Replicas: []types.AdGuardInstance{
{},
@@ -57,7 +58,7 @@ var _ = Describe("Sync", func() {
te = errors.New(uuid.NewString())
ac = &actionContext{
continueOnError: false,
cfg: w.cfg,
rl: l,
origin: &origin{
profileInfo: &model.ProfileInfo{
@@ -258,16 +259,32 @@ var _ = Describe("Sync", func() {
err := actionProfileInfo(ac)
Ω(err).ShouldNot(HaveOccurred())
})
It("should not change theme if feature is disabled", func() {
ac.origin.profileInfo.Language = "de"
ac.cfg.Features.Theme = false
cl.EXPECT().ProfileInfo().Return(&model.ProfileInfo{Name: "replica", Language: "en"}, nil)
cl.EXPECT().SetProfileInfo(&model.ProfileInfo{
Language: "de",
Name: "replica",
Theme: "",
})
err := actionProfileInfo(ac)
Ω(err).ShouldNot(HaveOccurred())
})
It("should not sync profileInfo if language is not set", func() {
ac.origin.profileInfo.Language = ""
cl.EXPECT().ProfileInfo().Return(&model.ProfileInfo{Name: "replica", Language: "en", Theme: "auto"}, nil)
cl.EXPECT().
ProfileInfo().
Return(&model.ProfileInfo{Name: "replica", Language: "en", Theme: "auto"}, nil)
cl.EXPECT().SetProfileInfo(ac.origin.profileInfo).Times(0)
err := actionProfileInfo(ac)
Ω(err).ShouldNot(HaveOccurred())
})
It("should not sync profileInfo if theme is not set", func() {
ac.origin.profileInfo.Theme = ""
cl.EXPECT().ProfileInfo().Return(&model.ProfileInfo{Name: "replica", Language: "en", Theme: "auto"}, nil)
cl.EXPECT().
ProfileInfo().
Return(&model.ProfileInfo{Name: "replica", Language: "en", Theme: "auto"}, nil)
cl.EXPECT().SetProfileInfo(ac.origin.profileInfo).Times(0)
err := actionProfileInfo(ac)
Ω(err).ShouldNot(HaveOccurred())
@@ -302,7 +319,8 @@ var _ = Describe("Sync", func() {
var interval model.QueryLogConfigInterval = 123
ac.origin.queryLogConfig.Interval = &interval
cl.EXPECT().QueryLogConfig().Return(qlc, nil)
cl.EXPECT().SetQueryLogConfig(&model.QueryLogConfigWithIgnored{QueryLogConfig: model.QueryLogConfig{AnonymizeClientIp: nil, Interval: &interval, Enabled: nil}})
cl.EXPECT().
SetQueryLogConfig(&model.QueryLogConfigWithIgnored{QueryLogConfig: model.QueryLogConfig{AnonymizeClientIp: nil, Interval: &interval, Enabled: nil}})
err := actionQueryLogConfig(ac)
Ω(err).ShouldNot(HaveOccurred())
})
@@ -421,7 +439,9 @@ var _ = Describe("Sync", func() {
Ω(err).ShouldNot(HaveOccurred())
})
It("should update a filter", func() {
ac.origin.filters.Filters = utils.Ptr([]model.Filter{{Name: "foo", Url: "https://foo.bar", Enabled: true}})
ac.origin.filters.Filters = utils.Ptr(
[]model.Filter{{Name: "foo", Url: "https://foo.bar", Enabled: true}},
)
rf.Filters = utils.Ptr([]model.Filter{{Name: "foo", Url: "https://foo.bar"}})
cl.EXPECT().Filtering().Return(rf, nil)
cl.EXPECT().UpdateFilter(false, model.Filter{Name: "foo", Url: "https://foo.bar", Enabled: true})
@@ -431,19 +451,25 @@ var _ = Describe("Sync", func() {
})
It("should abort after failed added filter", func() {
ac.continueOnError = false
ac.cfg.ContinueOnError = false
ac.origin.filters.Filters = utils.Ptr([]model.Filter{{Name: "foo", Url: "https://foo.bar"}})
cl.EXPECT().Filtering().Return(rf, nil)
cl.EXPECT().AddFilter(false, model.Filter{Name: "foo", Url: "https://foo.bar"}).Return(errors.New("test failure"))
cl.EXPECT().
AddFilter(false, model.Filter{Name: "foo", Url: "https://foo.bar"}).
Return(errors.New("test failure"))
err := actionFilters(ac)
Ω(err).Should(HaveOccurred())
})
It("should continue after failed added filter", func() {
ac.continueOnError = true
ac.origin.filters.Filters = utils.Ptr([]model.Filter{{Name: "foo", Url: "https://foo.bar"}, {Name: "bar", Url: "https://bar.foo"}})
ac.cfg.ContinueOnError = true
ac.origin.filters.Filters = utils.Ptr(
[]model.Filter{{Name: "foo", Url: "https://foo.bar"}, {Name: "bar", Url: "https://bar.foo"}},
)
cl.EXPECT().Filtering().Return(rf, nil)
cl.EXPECT().AddFilter(false, model.Filter{Name: "foo", Url: "https://foo.bar"}).Return(errors.New("test failure"))
cl.EXPECT().
AddFilter(false, model.Filter{Name: "foo", Url: "https://foo.bar"}).
Return(errors.New("test failure"))
cl.EXPECT().AddFilter(false, model.Filter{Name: "bar", Url: "https://bar.foo"})
cl.EXPECT().RefreshFilters(gm.Any())
err := actionFilters(ac)

View File

@@ -21,6 +21,7 @@ func NewFeatures(enabled bool) Features {
ClientSettings: enabled,
Services: enabled,
Filters: enabled,
Theme: enabled,
}
}
@@ -34,6 +35,7 @@ type Features struct {
ClientSettings bool `json:"clientSettings" yaml:"clientSettings" env:"FEATURES_CLIENT_SETTINGS"`
Services bool `json:"services" yaml:"services" env:"FEATURES_SERVICES"`
Filters bool `json:"filters" yaml:"filters" env:"FEATURES_FILTERS"`
Theme bool `json:"theme" yaml:"theme" env:"FEATURES_THEME"`
}
// DHCP features

View File

@@ -20,7 +20,7 @@ const (
type Config struct {
Origin AdGuardInstance `json:"origin" yaml:"origin" env:"ORIGIN"`
Replica *AdGuardInstance `json:"replica,omitempty" yaml:"replica,omitempty" env:"REPLICA"`
Replicas []AdGuardInstance `json:"replicas,omitempty" yaml:"replicas,omitempty"`
Replicas []AdGuardInstance `json:"replicas,omitempty" yaml:"replicas,omitempty" faker:"slice_len=2"`
Cron string `json:"cron,omitempty" yaml:"cron,omitempty" env:"CRON"`
RunOnStart bool `json:"runOnStart,omitempty" yaml:"runOnStart,omitempty" env:"RUN_ON_START"`
PrintConfigOnly bool `json:"printConfigOnly,omitempty" yaml:"printConfigOnly,omitempty" env:"PRINT_CONFIG_ONLY"`
@@ -140,8 +140,8 @@ func (cfg *Config) Init() error {
// AdGuardInstance AdguardHome config instance
// +k8s:deepcopy-gen=true
type AdGuardInstance struct {
URL string `json:"url" yaml:"url" env:"URL"`
WebURL string `json:"webURL" yaml:"webURL" env:"WEB_URL"`
URL string `json:"url" yaml:"url" env:"URL" faker:"url"`
WebURL string `json:"webURL" yaml:"webURL" env:"WEB_URL" faker:"url"`
APIPath string `json:"apiPath,omitempty" yaml:"apiPath,omitempty" env:"API_PATH"`
Username string `json:"username,omitempty" yaml:"username,omitempty" env:"USERNAME"`
Password string `json:"password,omitempty" yaml:"password,omitempty" env:"PASSWORD"`

View File

@@ -12,3 +12,13 @@ func PtrToString[I interface{}](i *I) string {
}
return fmt.Sprintf("%v", i)
}
func PtrEquals[I comparable](a *I, b *I) bool {
if a == nil && b == nil {
return true
}
if a == nil || b == nil {
return false
}
return *a == *b
}

28
renovate.json Normal file
View File

@@ -0,0 +1,28 @@
{
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
"customManagers": [
{
"customType": "regex",
"datasourceTemplate": "go",
"description": "Update toolbox tools in .toolbox.mk",
"fileMatch": [
"^\\.toolbox\\.mk$"
],
"matchStrings": [
"# renovate: packageName=(?<packageName>.+?)\\s+.+?_VERSION \\?= (?<currentValue>.+?)\\s"
]
},
{
"customType": "regex",
"datasourceTemplate": "github-releases",
"description": "Update github _VERSION Makefile",
"fileMatch": [
"^Makefile$"
],
"matchStrings": [
"# renovate: packageName=(?<packageName>.+?)\\s+.+?_VERSION \\?= (?<currentValue>.+?)\\s"
]
}
],
"dependencyDashboard": true
}

View File

@@ -35,3 +35,4 @@ features:
clientSettings: true
services: true
filters: true
theme: true

View File

@@ -35,3 +35,4 @@ features:
clientSettings: true
services: true
filters: true
theme: true

View File

@@ -45,3 +45,4 @@ features:
clientSettings: true
services: true
filters: true
theme: true

View File

@@ -7,3 +7,4 @@ if [[ $(helm list --no-headers -n agh-e2e | grep agh-e2e | wc -l) == "1" ]]; the
helm delete agh-e2e -n agh-e2e --wait
fi
helm install agh-e2e testdata/e2e -n agh-e2e --create-namespace --set mode=${1}

View File

@@ -1,7 +1,7 @@
#!/bin/bash
set -e
echo "## Pod adguardhome-origin logs" >> $GITHUB_STEP_SUMMARY
echo "## Pod adguardhome-origin ${1} logs" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
kubectl logs adguardhome-origin >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY

View File

@@ -4,15 +4,18 @@ set -e
for pod in $(kubectl get pods -l bakito.net/adguardhome-sync=replica -o name); do
echo "## Pod ${pod} logs" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
LOGS=$(kubectl logs ${pod})
K8S_LOGS=$(kubectl logs ${pod})
# ignore certain errors
LOGS=$(echo -e "${LOGS}" | grep -v -e "error.* deleting filter .* no such file or directory" )
# https://github.com/AdguardTeam/AdGuardHome/issues/4944
LOGS=$(echo -e "${LOGS}" | grep -v -e "error.* creating dhcpv4 srv")
echo -e "${LOGS}" >> $GITHUB_STEP_SUMMARY
ERRORS=$(echo -e "${LOGS}"} | grep '\[error\]' | wc -l)
echo '```' >> $GITHUB_STEP_SUMMARY
echo "Found ${ERRORS} error(s) in ${pod} log" >> $GITHUB_STEP_SUMMARY
echo "----------------------------------------------" >> $GITHUB_STEP_SUMMARY
LOGS=$(echo -e "${K8S_LOGS}" |
grep -v -e "error.* deleting filter .* no such file or directory" |
grep -v -e '\[error\] storage: recovered from panic: runtime' # https://github.com/AdguardTeam/AdGuardHome/issues/7315
)
echo -e "${K8S_LOGS}" >> $GITHUB_STEP_SUMMARY
ERRORS=$(echo -e "${LOGS}"} | grep '\[error\]' | wc -l)
TOTAL_ERRORS=$(echo -e "${K8S_LOGS}"} | grep '\[error\]' | wc -l)
IGNORED_ERRORS=$(echo "${TOTAL_ERRORS} - ${ERRORS}" | bc)
echo '```' >> $GITHUB_STEP_SUMMARY
echo "Found ${ERRORS} error(s) (${IGNORED_ERRORS} ignored) in ${pod} log" >> $GITHUB_STEP_SUMMARY
echo "----------------------------------------------" >> $GITHUB_STEP_SUMMARY
done

3
testdata/e2e/bin/wait-for-start.sh vendored Executable file
View File

@@ -0,0 +1,3 @@
#!/bin/bash
kubectl wait --for=jsonpath='{.status.phase}'=Running pod/adguardhome-sync --timeout=1m

View File

@@ -1,7 +1,5 @@
#!/bin/bash
kubectl wait --for=jsonpath='{.status.phase}'=Running pod/adguardhome-sync --timeout=1m
kubectl port-forward pod/adguardhome-sync 9090:9090 &
for i in {1..6}; do

View File

@@ -21,13 +21,12 @@ dns:
ratelimit_whitelist: []
refuse_any: true
upstream_dns:
- https://dns10.quad9.net/dns-query
- 8.8.8.8
upstream_dns_file: ""
bootstrap_dns:
- 1.1.1.1:53
fallback_dns: []
all_servers: false
fastest_addr: false
upstream_mode: load_balance
fastest_timeout: 1s
allowed_clients: []
disallowed_clients: []
@@ -62,6 +61,8 @@ dns:
dns64_prefixes: []
serve_http3: false
use_http3_upstreams: false
serve_plain_dns: true
hostsfile_enabled: true
tls:
enabled: false
server_name: ""
@@ -78,12 +79,14 @@ tls:
private_key_path: ""
strict_sni_check: false
querylog:
dir_path: ""
ignored: []
interval: 6h
size_memory: 1000
enabled: true
file_enabled: true
statistics:
dir_path: ""
ignored: []
interval: 24h
enabled: true
@@ -170,8 +173,6 @@ clients:
hosts: true
persistent:
- name: Device 1
tags:
- device_1
ids:
- 2.2.2.2
blocked_services:
@@ -192,6 +193,7 @@ clients:
ignore_querylog: false
ignore_statistics: false
log:
enabled: true
file: ""
max_backups: 0
max_size: 100
@@ -203,4 +205,4 @@ os:
group: ""
user: ""
rlimit_nofile: 0
schema_version: 27
schema_version: 28

View File

@@ -8,4 +8,4 @@ mode: env
kubectl:
repository: bitnami/kubectl
tag: 1.27
tag: "1.30"

8
tools.go Normal file
View File

@@ -0,0 +1,8 @@
//go:build tools
// +build tools
package tools
import (
_ "github.com/onsi/ginkgo/v2/ginkgo"
)