Compare commits
32 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
01dbf8e50a | ||
|
|
58d0302c74 | ||
|
|
90ea6a13de | ||
|
|
4f80a7979f | ||
|
|
3812101c25 | ||
|
|
8c79c8b32d | ||
|
|
0afc437252 | ||
|
|
6ae53fea6e | ||
|
|
d925ccf45a | ||
|
|
24243a4b4d | ||
|
|
ef9ebc29b7 | ||
|
|
bd4e0f2b28 | ||
|
|
e952c9f85a | ||
|
|
df67e9a0bd | ||
|
|
7e47ed0879 | ||
|
|
1952ec1527 | ||
|
|
9ca5205d6a | ||
|
|
8a8da9d162 | ||
|
|
6440c71492 | ||
|
|
0b66b2debb | ||
|
|
351c142b91 | ||
|
|
8ce6aed66f | ||
|
|
778d18d816 | ||
|
|
2ea436bbbc | ||
|
|
b5a820b6f4 | ||
|
|
37f5043493 | ||
|
|
7638fb75a3 | ||
|
|
fdad6d3b7b | ||
|
|
074e300974 | ||
|
|
523e068195 | ||
|
|
9a7c617311 | ||
|
|
c214899b75 |
4
.github/workflows/codeql-analysis.yml
vendored
4
.github/workflows/codeql-analysis.yml
vendored
@@ -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
|
||||
|
||||
@@ -4,10 +4,17 @@ 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,7 +51,7 @@ 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@v6
|
||||
if: ${{ github.event.release.tag_name != '' }}
|
||||
@@ -63,7 +70,7 @@ 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@v6
|
||||
if: ${{ github.event.release.tag_name == '' && env.NEW_COMMIT_COUNT > 0 }}
|
||||
4
.github/workflows/e2e.yaml
vendored
4
.github/workflows/e2e.yaml
vendored
@@ -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
|
||||
|
||||
4
.github/workflows/go.yml
vendored
4
.github/workflows/go.yml
vendored
@@ -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
|
||||
|
||||
@@ -42,5 +42,6 @@ changelog:
|
||||
exclude:
|
||||
- '^docs:'
|
||||
- '^test:'
|
||||
- '^chore'
|
||||
release:
|
||||
prerelease: auto
|
||||
|
||||
24
.toolbox.mk
24
.toolbox.mk
@@ -11,7 +11,9 @@ $(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
|
||||
@@ -19,11 +21,15 @@ TB_SEMVER ?= $(TB_LOCALBIN)/semver
|
||||
|
||||
## Tool Versions
|
||||
# renovate: packageName=k8s.io/code-generator/cmd/deepcopy-gen
|
||||
TB_DEEPCOPY_GEN_VERSION ?= v0.32.0
|
||||
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.62.2
|
||||
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.5.0
|
||||
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
|
||||
@@ -40,10 +46,18 @@ $(TB_DEEPCOPY_GEN): $(TB_LOCALBIN)
|
||||
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)
|
||||
@@ -67,7 +81,9 @@ 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 \
|
||||
@@ -78,7 +94,9 @@ tb.reset:
|
||||
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 \
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.23-alpine AS builder
|
||||
FROM golang:1.24-alpine AS builder
|
||||
|
||||
WORKDIR /go/src/app
|
||||
|
||||
|
||||
7
Makefile
7
Makefile
@@ -14,8 +14,11 @@ generate: tb.deepcopy-gen
|
||||
@touch ./tmp/deepcopy-gen-boilerplate.go.txt
|
||||
$(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 tb.ginkgo
|
||||
@@ -65,7 +68,7 @@ kind-test:
|
||||
@./testdata/e2e/bin/install-chart.sh
|
||||
|
||||
# renovate: packageName=AdguardTeam/AdGuardHome
|
||||
ADGUARD_HOME_VERSION ?= v0.107.55
|
||||
ADGUARD_HOME_VERSION ?= v0.107.57
|
||||
|
||||
model: tb.oapi-codegen
|
||||
@mkdir -p tmp
|
||||
|
||||
15
cmd/run.go
15
cmd/run.go
@@ -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")
|
||||
}
|
||||
|
||||
34
go.mod
34
go.mod
@@ -1,24 +1,26 @@
|
||||
module github.com/bakito/adguardhome-sync
|
||||
|
||||
go 1.23.1
|
||||
go 1.24.0
|
||||
|
||||
require (
|
||||
github.com/caarlos0/env/v11 v11.3.0
|
||||
github.com/caarlos0/env/v11 v11.3.1
|
||||
github.com/gin-gonic/gin v1.10.0
|
||||
github.com/go-resty/resty/v2 v2.16.2
|
||||
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.22.0
|
||||
github.com/onsi/gomega v1.36.1
|
||||
github.com/prometheus/client_golang v1.20.5
|
||||
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.1
|
||||
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/mod v0.22.0
|
||||
golang.org/x/mod v0.23.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
k8s.io/apimachinery v0.32.0
|
||||
k8s.io/apimachinery v0.32.2
|
||||
k8s.io/utils v0.0.0-20241210054802-24370beab758
|
||||
)
|
||||
|
||||
@@ -42,10 +44,10 @@ 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-20241029153458-d1b30febd7db // 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.9 // 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
|
||||
@@ -54,20 +56,20 @@ require (
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.55.0 // indirect
|
||||
github.com/prometheus/common v0.62.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // 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.31.0 // indirect
|
||||
golang.org/x/net v0.32.0 // indirect
|
||||
golang.org/x/net v0.33.0 // indirect
|
||||
golang.org/x/sys v0.28.0 // indirect
|
||||
golang.org/x/text v0.21.0 // indirect
|
||||
golang.org/x/text v0.22.0 // indirect
|
||||
golang.org/x/tools v0.28.0 // indirect
|
||||
google.golang.org/protobuf v1.35.1 // indirect
|
||||
google.golang.org/protobuf v1.36.1 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
|
||||
|
||||
71
go.sum
71
go.sum
@@ -8,19 +8,21 @@ 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/v11 v11.3.0 h1:CVTN6W6+twFC1jHKUwsw9eOTEiFpzyJOSA2AyHa8uvw=
|
||||
github.com/caarlos0/env/v11 v11.3.0/go.mod h1:Q5lYHeOsgY20CCV/R+b50Jwg2MnjySid7+3FUBz2BJw=
|
||||
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.4/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=
|
||||
@@ -29,6 +31,8 @@ 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-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=
|
||||
@@ -39,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.16.2 h1:CpRqTjIzq/rweXUt9+GxzzQdlkqMdt8Lm/fuK/CAbAg=
|
||||
github.com/go-resty/resty/v2 v2.16.2/go.mod h1:0fHAoK7JoBy/Ch36N8VFeMsK7xQOHhvWaC3iOktwmIU=
|
||||
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=
|
||||
@@ -53,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-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
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=
|
||||
@@ -66,8 +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.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA=
|
||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
||||
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=
|
||||
@@ -91,21 +95,21 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq
|
||||
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.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg=
|
||||
github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
|
||||
github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw=
|
||||
github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
|
||||
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.20.5 h1:cxppBPuYhUnsO6yo/aoRol4L7q7UFfdm+bR9r+8l63Y=
|
||||
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
||||
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.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc=
|
||||
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
|
||||
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=
|
||||
@@ -113,10 +117,12 @@ github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzG
|
||||
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.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM=
|
||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
||||
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=
|
||||
@@ -128,8 +134,9 @@ 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=
|
||||
@@ -156,14 +163,14 @@ 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.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
|
||||
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
||||
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.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
|
||||
golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
|
||||
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=
|
||||
@@ -176,8 +183,8 @@ 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.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
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=
|
||||
@@ -190,8 +197,8 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
|
||||
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.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA=
|
||||
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
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=
|
||||
@@ -200,8 +207,8 @@ gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
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.32.0 h1:cFSE7N3rmEEtv4ei5X6DaJPHHX0C+upp+v5lVPiEwpg=
|
||||
k8s.io/apimachinery v0.32.0/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
|
||||
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=
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
}
|
||||
|
||||
|
||||
@@ -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{
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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"`
|
||||
}
|
||||
|
||||
@@ -1205,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
|
||||
|
||||
@@ -1494,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)
|
||||
|
||||
@@ -1986,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 {
|
||||
@@ -3674,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
|
||||
@@ -5984,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)
|
||||
|
||||
@@ -6560,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
|
||||
@@ -8099,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...)
|
||||
@@ -9244,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)
|
||||
|
||||
@@ -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() {
|
||||
|
||||
175
pkg/config/config-schema.json
Normal file
175
pkg/config/config-schema.json
Normal 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"
|
||||
}
|
||||
@@ -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
|
||||
|
||||
52
pkg/config/validate.go
Normal file
52
pkg/config/validate.go
Normal 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)
|
||||
}
|
||||
39
pkg/config/validate_test.go
Normal file
39
pkg/config/validate_test.go
Normal 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())
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -105,7 +105,8 @@ var (
|
||||
return ac.client.SetCustomRules(ac.origin.filters.UserRules)
|
||||
}
|
||||
|
||||
if !utils.PtrEquals(ac.origin.filters.Enabled, rf.Enabled) || !utils.PtrEquals(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
|
||||
@@ -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 {
|
||||
|
||||
@@ -45,11 +45,20 @@ func (w *worker) handleRoot(c *gin.Context) {
|
||||
"Labels": getLast24Hours(),
|
||||
"DNS": dns,
|
||||
"Blocked": blocked,
|
||||
"BlockedPercentage": fmt.Sprintf("%.2f", (float64(*total.NumBlockedFiltering)*100.0)/float64(*total.NumDnsQueries)),
|
||||
"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)),
|
||||
"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)),
|
||||
"AdultPercentage": fmt.Sprintf(
|
||||
"%.2f",
|
||||
(float64(*total.NumReplacedParental)*100.0)/float64(*total.NumDnsQueries),
|
||||
),
|
||||
|
||||
"TotalDNS": total.NumDnsQueries,
|
||||
"TotalBlocked": total.NumBlockedFiltering,
|
||||
|
||||
@@ -72,7 +72,13 @@ func safeStats(stats *[]int) []int {
|
||||
return *stats
|
||||
}
|
||||
|
||||
func graphLines(t *model.Stats, s metrics.OverallStats, baseColor []int, altColors [][]int, dataCB func(s *model.Stats) []int) []line {
|
||||
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,
|
||||
|
||||
@@ -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,12 +281,14 @@ 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{
|
||||
@@ -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) {
|
||||
|
||||
@@ -273,14 +273,18 @@ var _ = Describe("Sync", func() {
|
||||
})
|
||||
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())
|
||||
@@ -315,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())
|
||||
})
|
||||
@@ -434,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})
|
||||
@@ -447,16 +454,22 @@ var _ = Describe("Sync", func() {
|
||||
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.cfg.ContinueOnError = true
|
||||
ac.origin.filters.Filters = utils.Ptr([]model.Filter{{Name: "foo", Url: "https://foo.bar"}, {Name: "bar", Url: "https://bar.foo"}})
|
||||
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)
|
||||
|
||||
@@ -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"`
|
||||
|
||||
Reference in New Issue
Block a user