Compare commits
56 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
32c728ccf8 | ||
|
|
327d67c9ef | ||
|
|
edd7f82351 | ||
|
|
012d43b950 | ||
|
|
e2298f6f1e | ||
|
|
18350f94a6 | ||
|
|
1a9d5df5cb | ||
|
|
8ef1eb8c2a | ||
|
|
7c2018acbc | ||
|
|
2079f6a3eb | ||
|
|
d9419446bf | ||
|
|
c0cbccb63c | ||
|
|
5444dda08a | ||
|
|
224617aae6 | ||
|
|
c941c8a100 | ||
|
|
07a25cd094 | ||
|
|
54d98c10fe | ||
|
|
4a897c40b5 | ||
|
|
9af45d3cab | ||
|
|
9c60b399a8 | ||
|
|
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 | ||
|
|
e31a8c8064 | ||
|
|
31cc27df1b | ||
|
|
d60051b5cb | ||
|
|
6770ae2a99 |
4
.github/workflows/codeql-analysis.yml
vendored
4
.github/workflows/codeql-analysis.yml
vendored
@@ -20,6 +20,10 @@ on:
|
|||||||
schedule:
|
schedule:
|
||||||
- cron: '32 19 * * 6'
|
- cron: '32 19 * * 6'
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
analyze:
|
analyze:
|
||||||
name: Analyze
|
name: Analyze
|
||||||
|
|||||||
@@ -4,10 +4,17 @@ on:
|
|||||||
workflow_dispatch: # allows manual triggering
|
workflow_dispatch: # allows manual triggering
|
||||||
schedule:
|
schedule:
|
||||||
- cron: '0 0 * * *'
|
- cron: '0 0 * * *'
|
||||||
|
#pull_request:
|
||||||
|
# branches:
|
||||||
|
# - main
|
||||||
release:
|
release:
|
||||||
types:
|
types:
|
||||||
- published
|
- published
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
images:
|
images:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
@@ -44,7 +51,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
sed -i -e "s|FROM scratch|FROM ${{ matrix.build.fromImage }}|g" Dockerfile
|
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
|
id: docker_build_release
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
if: ${{ github.event.release.tag_name != '' }}
|
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
|
run: echo "NEW_COMMIT_COUNT=$(git log --oneline --since '24 hours ago' | wc -l)" >> $GITHUB_ENV
|
||||||
if: ${{ github.event.release.tag_name == '' }}
|
if: ${{ github.event.release.tag_name == '' }}
|
||||||
|
|
||||||
- name: Build and push main
|
- name: Build images
|
||||||
id: docker_build_main
|
id: docker_build_main
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
if: ${{ github.event.release.tag_name == '' && env.NEW_COMMIT_COUNT > 0 }}
|
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:
|
branches:
|
||||||
- main
|
- main
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
e2e:
|
e2e:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|||||||
4
.github/workflows/go.yml
vendored
4
.github/workflows/go.yml
vendored
@@ -6,6 +6,10 @@ on:
|
|||||||
pull_request:
|
pull_request:
|
||||||
branches: [ main ]
|
branches: [ main ]
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
golangci:
|
golangci:
|
||||||
name: lint
|
name: lint
|
||||||
|
|||||||
16
.github/workflows/virustotal.yaml
vendored
Normal file
16
.github/workflows/virustotal.yaml
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
name: Scan GitHub Release with VirusTotal
|
||||||
|
|
||||||
|
on:
|
||||||
|
release:
|
||||||
|
types: [released]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
scan_release:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Analyze Build Assets
|
||||||
|
uses: bakito/virustotal-action@main
|
||||||
|
with:
|
||||||
|
release_name: ${{github.event.release.tag_name}}
|
||||||
|
vt_api_key: ${{secrets.VT_API_KEY}}
|
||||||
@@ -42,5 +42,6 @@ changelog:
|
|||||||
exclude:
|
exclude:
|
||||||
- '^docs:'
|
- '^docs:'
|
||||||
- '^test:'
|
- '^test:'
|
||||||
|
- '^chore'
|
||||||
release:
|
release:
|
||||||
prerelease: auto
|
prerelease: auto
|
||||||
|
|||||||
24
.toolbox.mk
24
.toolbox.mk
@@ -11,7 +11,9 @@ $(TB_LOCALBIN):
|
|||||||
## Tool Binaries
|
## Tool Binaries
|
||||||
TB_DEEPCOPY_GEN ?= $(TB_LOCALBIN)/deepcopy-gen
|
TB_DEEPCOPY_GEN ?= $(TB_LOCALBIN)/deepcopy-gen
|
||||||
TB_GINKGO ?= $(TB_LOCALBIN)/ginkgo
|
TB_GINKGO ?= $(TB_LOCALBIN)/ginkgo
|
||||||
|
TB_GOFUMPT ?= $(TB_LOCALBIN)/gofumpt
|
||||||
TB_GOLANGCI_LINT ?= $(TB_LOCALBIN)/golangci-lint
|
TB_GOLANGCI_LINT ?= $(TB_LOCALBIN)/golangci-lint
|
||||||
|
TB_GOLINES ?= $(TB_LOCALBIN)/golines
|
||||||
TB_GORELEASER ?= $(TB_LOCALBIN)/goreleaser
|
TB_GORELEASER ?= $(TB_LOCALBIN)/goreleaser
|
||||||
TB_MOCKGEN ?= $(TB_LOCALBIN)/mockgen
|
TB_MOCKGEN ?= $(TB_LOCALBIN)/mockgen
|
||||||
TB_OAPI_CODEGEN ?= $(TB_LOCALBIN)/oapi-codegen
|
TB_OAPI_CODEGEN ?= $(TB_LOCALBIN)/oapi-codegen
|
||||||
@@ -19,11 +21,15 @@ TB_SEMVER ?= $(TB_LOCALBIN)/semver
|
|||||||
|
|
||||||
## Tool Versions
|
## Tool Versions
|
||||||
# renovate: packageName=k8s.io/code-generator/cmd/deepcopy-gen
|
# renovate: packageName=k8s.io/code-generator/cmd/deepcopy-gen
|
||||||
TB_DEEPCOPY_GEN_VERSION ?= v0.32.0
|
TB_DEEPCOPY_GEN_VERSION ?= v0.32.3
|
||||||
|
# renovate: packageName=mvdan.cc/gofumpt
|
||||||
|
TB_GOFUMPT_VERSION ?= v0.7.0
|
||||||
# renovate: packageName=github.com/golangci/golangci-lint/cmd/golangci-lint
|
# renovate: packageName=github.com/golangci/golangci-lint/cmd/golangci-lint
|
||||||
TB_GOLANGCI_LINT_VERSION ?= v1.62.2
|
TB_GOLANGCI_LINT_VERSION ?= v1.64.7
|
||||||
|
# renovate: packageName=github.com/segmentio/golines
|
||||||
|
TB_GOLINES_VERSION ?= v0.12.2
|
||||||
# renovate: packageName=github.com/goreleaser/goreleaser/v2
|
# renovate: packageName=github.com/goreleaser/goreleaser/v2
|
||||||
TB_GORELEASER_VERSION ?= v2.5.0
|
TB_GORELEASER_VERSION ?= v2.8.0
|
||||||
# renovate: packageName=go.uber.org/mock/mockgen
|
# renovate: packageName=go.uber.org/mock/mockgen
|
||||||
TB_MOCKGEN_VERSION ?= v0.5.0
|
TB_MOCKGEN_VERSION ?= v0.5.0
|
||||||
# renovate: packageName=github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen
|
# 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_GINKGO) ## Download ginkgo locally if necessary.
|
||||||
$(TB_GINKGO): $(TB_LOCALBIN)
|
$(TB_GINKGO): $(TB_LOCALBIN)
|
||||||
test -s $(TB_LOCALBIN)/ginkgo || GOBIN=$(TB_LOCALBIN) go install github.com/onsi/ginkgo/v2/ginkgo
|
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
|
.PHONY: tb.golangci-lint
|
||||||
tb.golangci-lint: $(TB_GOLANGCI_LINT) ## Download golangci-lint locally if necessary.
|
tb.golangci-lint: $(TB_GOLANGCI_LINT) ## Download golangci-lint locally if necessary.
|
||||||
$(TB_GOLANGCI_LINT): $(TB_LOCALBIN)
|
$(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)
|
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
|
.PHONY: tb.goreleaser
|
||||||
tb.goreleaser: $(TB_GORELEASER) ## Download goreleaser locally if necessary.
|
tb.goreleaser: $(TB_GORELEASER) ## Download goreleaser locally if necessary.
|
||||||
$(TB_GORELEASER): $(TB_LOCALBIN)
|
$(TB_GORELEASER): $(TB_LOCALBIN)
|
||||||
@@ -67,7 +81,9 @@ tb.reset:
|
|||||||
@rm -f \
|
@rm -f \
|
||||||
$(TB_LOCALBIN)/deepcopy-gen \
|
$(TB_LOCALBIN)/deepcopy-gen \
|
||||||
$(TB_LOCALBIN)/ginkgo \
|
$(TB_LOCALBIN)/ginkgo \
|
||||||
|
$(TB_LOCALBIN)/gofumpt \
|
||||||
$(TB_LOCALBIN)/golangci-lint \
|
$(TB_LOCALBIN)/golangci-lint \
|
||||||
|
$(TB_LOCALBIN)/golines \
|
||||||
$(TB_LOCALBIN)/goreleaser \
|
$(TB_LOCALBIN)/goreleaser \
|
||||||
$(TB_LOCALBIN)/mockgen \
|
$(TB_LOCALBIN)/mockgen \
|
||||||
$(TB_LOCALBIN)/oapi-codegen \
|
$(TB_LOCALBIN)/oapi-codegen \
|
||||||
@@ -78,7 +94,9 @@ tb.reset:
|
|||||||
tb.update: tb.reset
|
tb.update: tb.reset
|
||||||
toolbox makefile --renovate -f $(TB_LOCALDIR)/Makefile \
|
toolbox makefile --renovate -f $(TB_LOCALDIR)/Makefile \
|
||||||
k8s.io/code-generator/cmd/deepcopy-gen@github.com/kubernetes/code-generator \
|
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/golangci/golangci-lint/cmd/golangci-lint \
|
||||||
|
github.com/segmentio/golines \
|
||||||
github.com/goreleaser/goreleaser/v2 \
|
github.com/goreleaser/goreleaser/v2 \
|
||||||
go.uber.org/mock/mockgen@github.com/uber-go/mock \
|
go.uber.org/mock/mockgen@github.com/uber-go/mock \
|
||||||
github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen \
|
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
|
WORKDIR /go/src/app
|
||||||
|
|
||||||
|
|||||||
10
Makefile
10
Makefile
@@ -14,8 +14,14 @@ generate: tb.deepcopy-gen
|
|||||||
@touch ./tmp/deepcopy-gen-boilerplate.go.txt
|
@touch ./tmp/deepcopy-gen-boilerplate.go.txt
|
||||||
$(TB_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
|
# Run tests
|
||||||
test: generate lint test-ci
|
test: generate fmt lint test-ci
|
||||||
|
|
||||||
|
fuzz:
|
||||||
|
go test -fuzz=FuzzMask -v ./pkg/types/ -fuzztime=60s
|
||||||
|
|
||||||
# Run ci tests
|
# Run ci tests
|
||||||
test-ci: mocks tidy tb.ginkgo
|
test-ci: mocks tidy tb.ginkgo
|
||||||
@@ -65,7 +71,7 @@ kind-test:
|
|||||||
@./testdata/e2e/bin/install-chart.sh
|
@./testdata/e2e/bin/install-chart.sh
|
||||||
|
|
||||||
# renovate: packageName=AdguardTeam/AdGuardHome
|
# renovate: packageName=AdguardTeam/AdGuardHome
|
||||||
ADGUARD_HOME_VERSION ?= v0.107.55
|
ADGUARD_HOME_VERSION ?= v0.107.57
|
||||||
|
|
||||||
model: tb.oapi-codegen
|
model: tb.oapi-codegen
|
||||||
@mkdir -p tmp
|
@mkdir -p tmp
|
||||||
|
|||||||
@@ -245,6 +245,11 @@ services:
|
|||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Unraid
|
||||||
|
|
||||||
|
Note when running the Docker container in Unraid please remove unneeded env variables if don't needed.
|
||||||
|
If replica2 isn't used this can cause sync errors.
|
||||||
|
|
||||||
### Config file
|
### Config file
|
||||||
|
|
||||||
location: $HOME/.adguardhome-sync.yaml
|
location: $HOME/.adguardhome-sync.yaml
|
||||||
|
|||||||
26
cmd/run.go
26
cmd/run.go
@@ -5,7 +5,6 @@ import (
|
|||||||
"github.com/bakito/adguardhome-sync/pkg/log"
|
"github.com/bakito/adguardhome-sync/pkg/log"
|
||||||
"github.com/bakito/adguardhome-sync/pkg/sync"
|
"github.com/bakito/adguardhome-sync/pkg/sync"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// runCmd represents the run command
|
// runCmd represents the run command
|
||||||
@@ -26,18 +25,16 @@ var doCmd = &cobra.Command{
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.PrintConfigOnly {
|
if cfg.PrintConfigOnly() {
|
||||||
config, err := yaml.Marshal(cfg)
|
if err := cfg.Print(); err != nil {
|
||||||
if err != nil {
|
|
||||||
logger.Error(err)
|
logger.Error(err)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
logger.Infof("Printing adguardhome-sync config (THE APPLICATION WILL NOT START IN THIS MODE): \n%s",
|
|
||||||
string(config))
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return sync.Sync(cfg)
|
return sync.Sync(cfg.Get())
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,7 +47,8 @@ func init() {
|
|||||||
doCmd.PersistentFlags().Bool(config.FlagContinueOnError, false, "If enabled, the synchronisation task "+
|
doCmd.PersistentFlags().Bool(config.FlagContinueOnError, false, "If enabled, the synchronisation task "+
|
||||||
"will not fail on single errors, but will log the errors and continue.")
|
"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.FlagApiUsername, "", "Sync API username")
|
||||||
doCmd.PersistentFlags().String(config.FlagApiPassword, "", "Sync API password")
|
doCmd.PersistentFlags().String(config.FlagApiPassword, "", "Sync API password")
|
||||||
doCmd.PersistentFlags().String(config.FlagApiDarkMode, "", "API UI in dark mode")
|
doCmd.PersistentFlags().String(config.FlagApiDarkMode, "", "API UI in dark mode")
|
||||||
@@ -70,7 +68,8 @@ func init() {
|
|||||||
doCmd.PersistentFlags().Bool(config.FlagFeatureFilters, true, "Enable filters sync feature")
|
doCmd.PersistentFlags().Bool(config.FlagFeatureFilters, true, "Enable filters sync feature")
|
||||||
|
|
||||||
doCmd.PersistentFlags().String(config.FlagOriginURL, "", "Origin instance url")
|
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.FlagOriginApiPath, "/control", "Origin instance API path")
|
||||||
doCmd.PersistentFlags().String(config.FlagOriginUsername, "", "Origin instance username")
|
doCmd.PersistentFlags().String(config.FlagOriginUsername, "", "Origin instance username")
|
||||||
doCmd.PersistentFlags().String(config.FlagOriginPassword, "", "Origin instance password")
|
doCmd.PersistentFlags().String(config.FlagOriginPassword, "", "Origin instance password")
|
||||||
@@ -78,12 +77,15 @@ func init() {
|
|||||||
doCmd.PersistentFlags().Bool(config.FlagOriginISV, false, "Enable Origin instance InsecureSkipVerify")
|
doCmd.PersistentFlags().Bool(config.FlagOriginISV, false, "Enable Origin instance InsecureSkipVerify")
|
||||||
|
|
||||||
doCmd.PersistentFlags().String(config.FlagReplicaURL, "", "Replica instance url")
|
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.FlagReplicaApiPath, "/control", "Replica instance API path")
|
||||||
doCmd.PersistentFlags().String(config.FlagReplicaUsername, "", "Replica instance username")
|
doCmd.PersistentFlags().String(config.FlagReplicaUsername, "", "Replica instance username")
|
||||||
doCmd.PersistentFlags().String(config.FlagReplicaPassword, "", "Replica instance password")
|
doCmd.PersistentFlags().String(config.FlagReplicaPassword, "", "Replica instance password")
|
||||||
doCmd.PersistentFlags().String(config.FlagReplicaCookie, "", "If Set, uses a cookie for authentication")
|
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.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().
|
||||||
doCmd.PersistentFlags().String(config.FlagReplicaInterfaceName, "", "Optional change the interface name of the replica if it differs from the master")
|
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")
|
||||||
}
|
}
|
||||||
|
|||||||
41
go.mod
41
go.mod
@@ -1,25 +1,26 @@
|
|||||||
module github.com/bakito/adguardhome-sync
|
module github.com/bakito/adguardhome-sync
|
||||||
|
|
||||||
go 1.23.1
|
go 1.24.0
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/caarlos0/env/v11 v11.2.2
|
github.com/caarlos0/env/v11 v11.3.1
|
||||||
github.com/gin-gonic/gin v1.10.0
|
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/google/uuid v1.6.0
|
||||||
github.com/jinzhu/copier v0.4.0
|
github.com/jinzhu/copier v0.4.0
|
||||||
github.com/oapi-codegen/runtime v1.1.1
|
github.com/oapi-codegen/runtime v1.1.1
|
||||||
github.com/onsi/ginkgo/v2 v2.22.0
|
github.com/onsi/ginkgo/v2 v2.23.0
|
||||||
github.com/onsi/gomega v1.36.1
|
github.com/onsi/gomega v1.36.2
|
||||||
github.com/prometheus/client_golang v1.20.5
|
github.com/prometheus/client_golang v1.21.1
|
||||||
github.com/robfig/cron/v3 v3.0.1
|
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/mock v0.5.0
|
||||||
go.uber.org/zap v1.27.0
|
go.uber.org/zap v1.27.0
|
||||||
golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e
|
golang.org/x/mod v0.24.0
|
||||||
golang.org/x/mod v0.22.0
|
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
k8s.io/apimachinery v0.32.0
|
k8s.io/apimachinery v0.32.3
|
||||||
k8s.io/utils v0.0.0-20241210054802-24370beab758
|
k8s.io/utils v0.0.0-20241210054802-24370beab758
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -43,10 +44,10 @@ require (
|
|||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/google/go-cmp v0.6.0 // indirect
|
github.com/google/go-cmp v0.6.0 // indirect
|
||||||
github.com/google/gofuzz v1.2.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/inconshreveable/mousetrap v1.1.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // 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/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||||
github.com/leodido/go-urn v1.4.0 // indirect
|
github.com/leodido/go-urn v1.4.0 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
@@ -55,20 +56,20 @@ require (
|
|||||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||||
github.com/prometheus/client_model v0.6.1 // 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/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/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||||
github.com/x448/float16 v0.8.4 // indirect
|
github.com/x448/float16 v0.8.4 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
golang.org/x/arch v0.8.0 // indirect
|
golang.org/x/arch v0.8.0 // indirect
|
||||||
golang.org/x/crypto v0.31.0 // indirect
|
golang.org/x/crypto v0.35.0 // indirect
|
||||||
golang.org/x/net v0.32.0 // indirect
|
golang.org/x/net v0.36.0 // indirect
|
||||||
golang.org/x/sys v0.28.0 // indirect
|
golang.org/x/sys v0.30.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
|
golang.org/x/tools v0.30.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
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
k8s.io/klog/v2 v2.130.1 // indirect
|
k8s.io/klog/v2 v2.130.1 // indirect
|
||||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
|
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
|
||||||
|
|||||||
89
go.sum
89
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 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 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
|
||||||
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||||
github.com/caarlos0/env/v11 v11.2.2 h1:95fApNrUyueipoZN/EhA8mMxiNxrBwDa+oAZrMWl3Kg=
|
github.com/caarlos0/env/v11 v11.3.1 h1:cArPWC15hWmEt+gWk7YBi7lEXTXCvpaSdCiZE2X5mCA=
|
||||||
github.com/caarlos0/env/v11 v11.2.2/go.mod h1:JBfcdeQiBoI3Zh1QRAWfe+tpiNTmDtcCj/hHHHMx0vc=
|
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 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
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 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
||||||
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
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 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
||||||
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
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.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.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 h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
|
||||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
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 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
|
||||||
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
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 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-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 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
||||||
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
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 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||||
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
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 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/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 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
|
||||||
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
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.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptdhTM=
|
||||||
github.com/go-resty/resty/v2 v2.16.2/go.mod h1:0fHAoK7JoBy/Ch36N8VFeMsK7xQOHhvWaC3iOktwmIU=
|
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 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
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.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 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
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-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg=
|
||||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
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 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
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=
|
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/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/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
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.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||||
github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw=
|
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.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 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||||
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
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/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 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro=
|
||||||
github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg=
|
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.23.0 h1:FA1xjp8ieYDzlgS5ABTpdUDB7wtngggONc8a7ku2NqQ=
|
||||||
github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
|
github.com/onsi/ginkgo/v2 v2.23.0/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM=
|
||||||
github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw=
|
github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
|
||||||
github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
|
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 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
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.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 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
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.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk=
|
||||||
github.com/prometheus/client_golang v1.20.5/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE=
|
github.com/prometheus/client_golang v1.21.1/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 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
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.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
|
||||||
github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8=
|
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 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
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 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 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
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/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/santhosh-tekuri/jsonschema/v6 v6.0.1 h1:PKK9DyHxif4LZo+uQSgXNqs0jj5+xZwwfKHgph2lxBw=
|
||||||
github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y=
|
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1/go.mod h1:JXeL+ps8p7/KNMjDQk3TCwPpBy0wYklyWTfbkIzdIFU=
|
||||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo=
|
||||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
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/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.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
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.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.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
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.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 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
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 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||||
@@ -152,22 +159,18 @@ 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-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-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-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
|
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
|
||||||
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
|
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
|
||||||
golang.org/x/exp v0.0.0-20241210194714-1829a127f884 h1:Y/Mj/94zIQQGHVSv1tTtQBDaQaJe62U9bkDZKKyhPCU=
|
|
||||||
golang.org/x/exp v0.0.0-20241210194714-1829a127f884/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
|
||||||
golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e h1:4qufH0hlUYs6AO6XmZC3GqfDPGSXHVXUFR6OND+iJX4=
|
|
||||||
golang.org/x/exp v0.0.0-20241215155358-4a5509556b9e/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c=
|
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
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.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||||
golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4=
|
golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||||
golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY=
|
golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
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-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-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-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI=
|
golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA=
|
||||||
golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs=
|
golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I=
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
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-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-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
@@ -176,26 +179,26 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.5.0/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.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
|
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||||
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.30.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.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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
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 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
||||||
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
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-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-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-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.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8=
|
golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
|
||||||
golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw=
|
golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
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-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-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/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.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
|
||||||
google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
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 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 h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||||
@@ -204,12 +207,10 @@ 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.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 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
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.3 h1:JmDuDarhDmA/Li7j3aPrwhpNBA94Nvk5zLeOge9HH1U=
|
||||||
k8s.io/apimachinery v0.32.0/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
|
k8s.io/apimachinery v0.32.3/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
|
||||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||||
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro=
|
|
||||||
k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
|
||||||
k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0=
|
k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0=
|
||||||
k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||||
|
|||||||
@@ -20,7 +20,9 @@ func main() {
|
|||||||
}
|
}
|
||||||
log.Printf("Patching schema version %s\n", version)
|
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 {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
@@ -51,6 +53,11 @@ func main() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
correctEntries(schema)
|
||||||
|
|
||||||
|
addFakeTags(schema)
|
||||||
|
|
||||||
b, err := yaml.Marshal(&schema)
|
b, err := yaml.Marshal(&schema)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
@@ -61,3 +68,26 @@ func main() {
|
|||||||
log.Fatalln(err)
|
log.Fatalln(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func correctEntries(schema map[string]interface{}) {
|
||||||
|
// https://github.com/AdguardTeam/AdGuardHome/pull/7678
|
||||||
|
if err := unstructured.SetNestedField(schema, "string", "components", "schemas", "QueryLogItem", "properties", "client_proto", "type"); err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func addFakeTags(schema map[string]interface{}) {
|
||||||
|
fake := map[string]interface{}{"faker": `slice_len=24`}
|
||||||
|
if err := unstructured.SetNestedMap(schema, fake, "components", "schemas", "Stats", "properties", "blocked_filtering", "x-oapi-codegen-extra-tags"); err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
if err := unstructured.SetNestedMap(schema, fake, "components", "schemas", "Stats", "properties", "dns_queries", "x-oapi-codegen-extra-tags"); err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
if err := unstructured.SetNestedMap(schema, fake, "components", "schemas", "Stats", "properties", "replaced_parental", "x-oapi-codegen-extra-tags"); err != nil {
|
||||||
|
log.Fatalln(err)
|
||||||
|
}
|
||||||
|
if err := unstructured.SetNestedMap(schema, fake, "components", "schemas", "Stats", "properties", "replaced_safebrowsing", "x-oapi-codegen-extra-tags"); 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) {
|
func (cl *client) QueryLog(limit int) (*model.QueryLog, error) {
|
||||||
ql := &model.QueryLog{}
|
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
|
return ql, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -260,7 +263,10 @@ func (cl *client) UpdateFilter(whitelist bool, f model.Filter) error {
|
|||||||
|
|
||||||
func (cl *client) RefreshFilters(whitelist bool) error {
|
func (cl *client) RefreshFilters(whitelist bool) error {
|
||||||
cl.log.With("whitelist", whitelist).Info("Refresh filter")
|
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 {
|
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 {
|
func (cl *client) UpdateClient(client *model.Client) error {
|
||||||
cl.log.With("name", *client.Name).Info("Update client settings")
|
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 {
|
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 {
|
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")
|
return cl.doPut(cl.client.R().EnableTrace().SetBody(qlc), "/querylog/config/update")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -137,7 +137,14 @@ var _ = Describe("Client", func() {
|
|||||||
|
|
||||||
Context("Setup", func() {
|
Context("Setup", func() {
|
||||||
It("should add setup the instance", 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 := cl.Setup()
|
||||||
Ω(err).ShouldNot(HaveOccurred())
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
})
|
})
|
||||||
@@ -303,7 +310,10 @@ var _ = Describe("Client", func() {
|
|||||||
Ω(*qlc.Interval).Should(Equal(model.QueryLogConfigInterval(90)))
|
Ω(*qlc.Interval).Should(Equal(model.QueryLogConfigInterval(90)))
|
||||||
})
|
})
|
||||||
It("should set QueryLogConfig", func() {
|
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
|
var interval model.QueryLogConfigInterval = 123
|
||||||
err := cl.SetQueryLogConfig(&model.QueryLogConfigWithIgnored{
|
err := cl.SetQueryLogConfig(&model.QueryLogConfigWithIgnored{
|
||||||
|
|||||||
@@ -442,7 +442,9 @@ func (c *DNSConfig) Sanitize(l *zap.SugaredLogger) {
|
|||||||
// https://github.com/AdguardTeam/AdGuardHome/issues/6820
|
// https://github.com/AdguardTeam/AdGuardHome/issues/6820
|
||||||
if c.UsePrivatePtrResolvers != nil && *c.UsePrivatePtrResolvers &&
|
if c.UsePrivatePtrResolvers != nil && *c.UsePrivatePtrResolvers &&
|
||||||
(c.LocalPtrUpstreams == nil || len(*c.LocalPtrUpstreams) == 0) {
|
(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)
|
c.UsePrivatePtrResolvers = utils.Ptr(false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -91,6 +91,15 @@ const (
|
|||||||
QueryLogConfigIntervalN90 QueryLogConfigInterval = 90
|
QueryLogConfigIntervalN90 QueryLogConfigInterval = 90
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Defines values for QueryLogItemClientProto.
|
||||||
|
const (
|
||||||
|
Dnscrypt QueryLogItemClientProto = "dnscrypt"
|
||||||
|
Doh QueryLogItemClientProto = "doh"
|
||||||
|
Doq QueryLogItemClientProto = "doq"
|
||||||
|
Dot QueryLogItemClientProto = "dot"
|
||||||
|
Empty QueryLogItemClientProto = ""
|
||||||
|
)
|
||||||
|
|
||||||
// Defines values for QueryLogItemReason.
|
// Defines values for QueryLogItemReason.
|
||||||
const (
|
const (
|
||||||
QueryLogItemReasonFilteredBlackList QueryLogItemReason = "FilteredBlackList"
|
QueryLogItemReasonFilteredBlackList QueryLogItemReason = "FilteredBlackList"
|
||||||
@@ -397,6 +406,17 @@ type ClientsFindEntry map[string]ClientFindSubEntry
|
|||||||
// ClientsFindResponse Client search results.
|
// ClientsFindResponse Client search results.
|
||||||
type ClientsFindResponse = []ClientsFindEntry
|
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
|
// DNSConfig DNS server configuration
|
||||||
type DNSConfig struct {
|
type DNSConfig struct {
|
||||||
// BlockedResponseTtl TTL for blocked responses.
|
// BlockedResponseTtl TTL for blocked responses.
|
||||||
@@ -443,8 +463,11 @@ type DNSConfig struct {
|
|||||||
UpstreamDnsFile *string `json:"upstream_dns_file,omitempty"`
|
UpstreamDnsFile *string `json:"upstream_dns_file,omitempty"`
|
||||||
|
|
||||||
// UpstreamMode Upstream modes enumeration.
|
// UpstreamMode Upstream modes enumeration.
|
||||||
UpstreamMode *DNSConfigUpstreamMode `json:"upstream_mode,omitempty"`
|
UpstreamMode *DNSConfigUpstreamMode `json:"upstream_mode,omitempty"`
|
||||||
UsePrivatePtrResolvers *bool `json:"use_private_ptr_resolvers,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"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DNSConfigBlockingMode defines model for DNSConfig.BlockingMode.
|
// DNSConfigBlockingMode defines model for DNSConfig.BlockingMode.
|
||||||
@@ -725,11 +748,18 @@ type Login struct {
|
|||||||
// NetInterface Network interface info
|
// NetInterface Network interface info
|
||||||
type NetInterface 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 Flags could be any combination of the following values, divided by the "|" character: "up", "broadcast", "loopback", "pointtopoint" and "multicast".
|
||||||
Flags string `json:"flags"`
|
Flags string `json:"flags"`
|
||||||
HardwareAddress string `json:"hardware_address"`
|
|
||||||
IpAddresses *[]string `json:"ip_addresses,omitempty"`
|
// GatewayIp The IP address of the gateway.
|
||||||
Mtu int `json:"mtu"`
|
GatewayIp string `json:"gateway_ip"`
|
||||||
Name string `json:"name"`
|
HardwareAddress string `json:"hardware_address"`
|
||||||
|
|
||||||
|
// 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"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NetInterfaces Network interfaces dictionary, keys are interface names.
|
// NetInterfaces Network interfaces dictionary, keys are interface names.
|
||||||
@@ -791,8 +821,8 @@ type QueryLogItem struct {
|
|||||||
ClientId *string `json:"client_id,omitempty"`
|
ClientId *string `json:"client_id,omitempty"`
|
||||||
|
|
||||||
// ClientInfo Client information for a query log item.
|
// ClientInfo Client information for a query log item.
|
||||||
ClientInfo *QueryLogItemClient `json:"client_info,omitempty"`
|
ClientInfo *QueryLogItemClient `json:"client_info,omitempty"`
|
||||||
ClientProto *interface{} `json:"client_proto,omitempty"`
|
ClientProto *QueryLogItemClientProto `json:"client_proto,omitempty"`
|
||||||
|
|
||||||
// Ecs The IP network defined by an EDNS Client-Subnet option in the request message if any.
|
// Ecs The IP network defined by an EDNS Client-Subnet option in the request message if any.
|
||||||
Ecs *string `json:"ecs,omitempty"`
|
Ecs *string `json:"ecs,omitempty"`
|
||||||
@@ -833,6 +863,9 @@ type QueryLogItem struct {
|
|||||||
Upstream *string `json:"upstream,omitempty"`
|
Upstream *string `json:"upstream,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QueryLogItemClientProto defines model for QueryLogItem.ClientProto.
|
||||||
|
type QueryLogItemClientProto string
|
||||||
|
|
||||||
// QueryLogItemReason Request filtering status.
|
// QueryLogItemReason Request filtering status.
|
||||||
type QueryLogItemReason string
|
type QueryLogItemReason string
|
||||||
|
|
||||||
@@ -968,8 +1001,8 @@ type SetRulesRequest struct {
|
|||||||
type Stats struct {
|
type Stats struct {
|
||||||
// AvgProcessingTime Average time in seconds on processing a DNS request
|
// AvgProcessingTime Average time in seconds on processing a DNS request
|
||||||
AvgProcessingTime *float32 `json:"avg_processing_time,omitempty"`
|
AvgProcessingTime *float32 `json:"avg_processing_time,omitempty"`
|
||||||
BlockedFiltering *[]int `json:"blocked_filtering,omitempty"`
|
BlockedFiltering *[]int `faker:"slice_len=24" json:"blocked_filtering,omitempty"`
|
||||||
DnsQueries *[]int `json:"dns_queries,omitempty"`
|
DnsQueries *[]int `faker:"slice_len=24" json:"dns_queries,omitempty"`
|
||||||
|
|
||||||
// NumBlockedFiltering Number of requests blocked by filtering rules
|
// NumBlockedFiltering Number of requests blocked by filtering rules
|
||||||
NumBlockedFiltering *int `json:"num_blocked_filtering,omitempty"`
|
NumBlockedFiltering *int `json:"num_blocked_filtering,omitempty"`
|
||||||
@@ -985,8 +1018,8 @@ type Stats struct {
|
|||||||
|
|
||||||
// NumReplacedSafesearch Number of requests blocked by safesearch module
|
// NumReplacedSafesearch Number of requests blocked by safesearch module
|
||||||
NumReplacedSafesearch *int `json:"num_replaced_safesearch,omitempty"`
|
NumReplacedSafesearch *int `json:"num_replaced_safesearch,omitempty"`
|
||||||
ReplacedParental *[]int `json:"replaced_parental,omitempty"`
|
ReplacedParental *[]int `faker:"slice_len=24" json:"replaced_parental,omitempty"`
|
||||||
ReplacedSafebrowsing *[]int `json:"replaced_safebrowsing,omitempty"`
|
ReplacedSafebrowsing *[]int `faker:"slice_len=24" json:"replaced_safebrowsing,omitempty"`
|
||||||
|
|
||||||
// TimeUnits Time units
|
// TimeUnits Time units
|
||||||
TimeUnits *StatsTimeUnits `json:"time_units,omitempty"`
|
TimeUnits *StatsTimeUnits `json:"time_units,omitempty"`
|
||||||
@@ -1205,6 +1238,9 @@ type ClientsAddJSONRequestBody = Client
|
|||||||
// ClientsDeleteJSONRequestBody defines body for ClientsDelete for application/json ContentType.
|
// ClientsDeleteJSONRequestBody defines body for ClientsDelete for application/json ContentType.
|
||||||
type ClientsDeleteJSONRequestBody = ClientDelete
|
type ClientsDeleteJSONRequestBody = ClientDelete
|
||||||
|
|
||||||
|
// ClientsSearchJSONRequestBody defines body for ClientsSearch for application/json ContentType.
|
||||||
|
type ClientsSearchJSONRequestBody = ClientsSearchRequest
|
||||||
|
|
||||||
// ClientsUpdateJSONRequestBody defines body for ClientsUpdate for application/json ContentType.
|
// ClientsUpdateJSONRequestBody defines body for ClientsUpdate for application/json ContentType.
|
||||||
type ClientsUpdateJSONRequestBody = ClientUpdate
|
type ClientsUpdateJSONRequestBody = ClientUpdate
|
||||||
|
|
||||||
@@ -1494,6 +1530,11 @@ type ClientInterface interface {
|
|||||||
// ClientsFind request
|
// ClientsFind request
|
||||||
ClientsFind(ctx context.Context, params *ClientsFindParams, reqEditors ...RequestEditorFn) (*http.Response, error)
|
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 request with any body
|
||||||
ClientsUpdateWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
|
ClientsUpdateWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error)
|
||||||
|
|
||||||
@@ -1986,6 +2027,30 @@ func (c *AdguardHomeClient) ClientsFind(ctx context.Context, params *ClientsFind
|
|||||||
return c.Client.Do(req)
|
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) {
|
func (c *AdguardHomeClient) ClientsUpdateWithBody(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*http.Response, error) {
|
||||||
req, err := NewClientsUpdateRequestWithBody(c.Server, contentType, body)
|
req, err := NewClientsUpdateRequestWithBody(c.Server, contentType, body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -3674,6 +3739,46 @@ func NewClientsFindRequest(server string, params *ClientsFindParams) (*http.Requ
|
|||||||
return req, nil
|
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
|
// NewClientsUpdateRequest calls the generic ClientsUpdate builder with application/json body
|
||||||
func NewClientsUpdateRequest(server string, body ClientsUpdateJSONRequestBody) (*http.Request, error) {
|
func NewClientsUpdateRequest(server string, body ClientsUpdateJSONRequestBody) (*http.Request, error) {
|
||||||
var bodyReader io.Reader
|
var bodyReader io.Reader
|
||||||
@@ -5984,6 +6089,11 @@ type ClientWithResponsesInterface interface {
|
|||||||
// ClientsFindWithResponse request
|
// ClientsFindWithResponse request
|
||||||
ClientsFindWithResponse(ctx context.Context, params *ClientsFindParams, reqEditors ...RequestEditorFn) (*ClientsFindResp, error)
|
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 request with any body
|
||||||
ClientsUpdateWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*ClientsUpdateResp, error)
|
ClientsUpdateWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*ClientsUpdateResp, error)
|
||||||
|
|
||||||
@@ -6560,6 +6670,28 @@ func (r ClientsFindResp) StatusCode() int {
|
|||||||
return 0
|
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 {
|
type ClientsUpdateResp struct {
|
||||||
Body []byte
|
Body []byte
|
||||||
HTTPResponse *http.Response
|
HTTPResponse *http.Response
|
||||||
@@ -8099,6 +8231,23 @@ func (c *ClientWithResponses) ClientsFindWithResponse(ctx context.Context, param
|
|||||||
return ParseClientsFindResp(rsp)
|
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
|
// ClientsUpdateWithBodyWithResponse request with arbitrary body returning *ClientsUpdateResp
|
||||||
func (c *ClientWithResponses) ClientsUpdateWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*ClientsUpdateResp, error) {
|
func (c *ClientWithResponses) ClientsUpdateWithBodyWithResponse(ctx context.Context, contentType string, body io.Reader, reqEditors ...RequestEditorFn) (*ClientsUpdateResp, error) {
|
||||||
rsp, err := c.ClientsUpdateWithBody(ctx, contentType, body, reqEditors...)
|
rsp, err := c.ClientsUpdateWithBody(ctx, contentType, body, reqEditors...)
|
||||||
@@ -9244,6 +9393,32 @@ func ParseClientsFindResp(rsp *http.Response) (*ClientsFindResp, error) {
|
|||||||
return response, nil
|
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
|
// ParseClientsUpdateResp parses an HTTP response from a ClientsUpdateWithResponse call
|
||||||
func ParseClientsUpdateResp(rsp *http.Response) (*ClientsUpdateResp, error) {
|
func ParseClientsUpdateResp(rsp *http.Response) (*ClientsUpdateResp, error) {
|
||||||
bodyBytes, err := io.ReadAll(rsp.Body)
|
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() {
|
It("should return 3 one replicas if urls are different", func() {
|
||||||
cfg.Replica = &types.AdGuardInstance{URL: url, APIPath: apiPath}
|
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 := cfg.UniqueReplicas()
|
||||||
Ω(r).Should(HaveLen(3))
|
Ω(r).Should(HaveLen(3))
|
||||||
})
|
})
|
||||||
@@ -311,8 +314,14 @@ var _ = Describe("Types", func() {
|
|||||||
cl2 *model.Client
|
cl2 *model.Client
|
||||||
)
|
)
|
||||||
BeforeEach(func() {
|
BeforeEach(func() {
|
||||||
cl1 = &model.Client{Name: utils.Ptr("foo"), BlockedServicesSchedule: &model.Schedule{TimeZone: utils.Ptr("UTC")}}
|
cl1 = &model.Client{
|
||||||
cl2 = &model.Client{Name: utils.Ptr("foo"), BlockedServicesSchedule: &model.Schedule{TimeZone: utils.Ptr("Local")}}
|
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() {
|
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"
|
||||||
|
}
|
||||||
@@ -14,16 +14,39 @@ var (
|
|||||||
logger = log.GetLogger("config")
|
logger = log.GetLogger("config")
|
||||||
)
|
)
|
||||||
|
|
||||||
func Get(configFile string, flags Flags) (*types.Config, error) {
|
type AppConfig struct {
|
||||||
|
cfg *types.Config
|
||||||
|
filePath string
|
||||||
|
content string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *AppConfig) PrintConfigOnly() bool {
|
||||||
|
return ac.cfg.PrintConfigOnly
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *AppConfig) Get() *types.Config {
|
||||||
|
return ac.cfg
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *AppConfig) Init() error {
|
||||||
|
return ac.cfg.Init()
|
||||||
|
}
|
||||||
|
|
||||||
|
func Get(configFile string, flags Flags) (*AppConfig, error) {
|
||||||
path, err := configFilePath(configFile)
|
path, err := configFilePath(configFile)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if err = validateSchema(path); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
cfg := initialConfig()
|
cfg := initialConfig()
|
||||||
|
|
||||||
// read yaml config
|
// read yaml config
|
||||||
if err := readFile(cfg, path); err != nil {
|
var content string
|
||||||
|
if content, err = readFile(cfg, path); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,7 +105,7 @@ func Get(configFile string, flags Flags) (*types.Config, error) {
|
|||||||
|
|
||||||
cfg.Replicas, err = enrichReplicasFromEnv(cfg.Replicas)
|
cfg.Replicas, err = enrichReplicasFromEnv(cfg.Replicas)
|
||||||
|
|
||||||
return cfg, err
|
return &AppConfig{cfg: cfg, filePath: path, content: content}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func initialConfig() *types.Config {
|
func initialConfig() *types.Config {
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ var _ = Describe("Config", func() {
|
|||||||
|
|
||||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||||
Ω(err).ShouldNot(HaveOccurred())
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
Ω(cfg.Origin.URL).Should(Equal("https://origin-file:443"))
|
Ω(cfg.Get().Origin.URL).Should(Equal("https://origin-file:443"))
|
||||||
})
|
})
|
||||||
It("should have the origin URL from the config flags", func() {
|
It("should have the origin URL from the config flags", func() {
|
||||||
flags.EXPECT().Changed(config.FlagOriginURL).Return(true).AnyTimes()
|
flags.EXPECT().Changed(config.FlagOriginURL).Return(true).AnyTimes()
|
||||||
@@ -58,7 +58,7 @@ var _ = Describe("Config", func() {
|
|||||||
|
|
||||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||||
Ω(err).ShouldNot(HaveOccurred())
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
Ω(cfg.Origin.URL).Should(Equal("https://origin-flag:443"))
|
Ω(cfg.Get().Origin.URL).Should(Equal("https://origin-flag:443"))
|
||||||
})
|
})
|
||||||
It("should have the origin URL from the config env var", func() {
|
It("should have the origin URL from the config env var", func() {
|
||||||
setEnv("ORIGIN_URL", "https://origin-env:443")
|
setEnv("ORIGIN_URL", "https://origin-env:443")
|
||||||
@@ -68,7 +68,7 @@ var _ = Describe("Config", func() {
|
|||||||
|
|
||||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||||
Ω(err).ShouldNot(HaveOccurred())
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
Ω(cfg.Origin.URL).Should(Equal("https://origin-env:443"))
|
Ω(cfg.Get().Origin.URL).Should(Equal("https://origin-env:443"))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
Context("Replica insecure skip verify", func() {
|
Context("Replica insecure skip verify", func() {
|
||||||
@@ -77,7 +77,7 @@ var _ = Describe("Config", func() {
|
|||||||
|
|
||||||
cfg, err := config.Get("../../testdata/config_test_replica.yaml", flags)
|
cfg, err := config.Get("../../testdata/config_test_replica.yaml", flags)
|
||||||
Ω(err).ShouldNot(HaveOccurred())
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
Ω(cfg.Replicas[0].InsecureSkipVerify).Should(BeFalse())
|
Ω(cfg.Get().Replicas[0].InsecureSkipVerify).Should(BeFalse())
|
||||||
})
|
})
|
||||||
It("should have the insecure skip verify from the config flags", func() {
|
It("should have the insecure skip verify from the config flags", func() {
|
||||||
flags.EXPECT().Changed(config.FlagReplicaISV).Return(true).AnyTimes()
|
flags.EXPECT().Changed(config.FlagReplicaISV).Return(true).AnyTimes()
|
||||||
@@ -86,7 +86,7 @@ var _ = Describe("Config", func() {
|
|||||||
|
|
||||||
cfg, err := config.Get("../../testdata/config_test_replica.yaml", flags)
|
cfg, err := config.Get("../../testdata/config_test_replica.yaml", flags)
|
||||||
Ω(err).ShouldNot(HaveOccurred())
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
Ω(cfg.Replicas[0].InsecureSkipVerify).Should(BeTrue())
|
Ω(cfg.Get().Replicas[0].InsecureSkipVerify).Should(BeTrue())
|
||||||
})
|
})
|
||||||
It("should have the insecure skip verify from the config env var", func() {
|
It("should have the insecure skip verify from the config env var", func() {
|
||||||
setEnv("REPLICA_INSECURE_SKIP_VERIFY", "false")
|
setEnv("REPLICA_INSECURE_SKIP_VERIFY", "false")
|
||||||
@@ -96,7 +96,7 @@ var _ = Describe("Config", func() {
|
|||||||
|
|
||||||
cfg, err := config.Get("../../testdata/config_test_replica.yaml", flags)
|
cfg, err := config.Get("../../testdata/config_test_replica.yaml", flags)
|
||||||
Ω(err).ShouldNot(HaveOccurred())
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
Ω(cfg.Replicas[0].InsecureSkipVerify).Should(BeFalse())
|
Ω(cfg.Get().Replicas[0].InsecureSkipVerify).Should(BeFalse())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -106,7 +106,7 @@ var _ = Describe("Config", func() {
|
|||||||
|
|
||||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||||
Ω(err).ShouldNot(HaveOccurred())
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
Ω(cfg.Replicas[0].InsecureSkipVerify).Should(BeFalse())
|
Ω(cfg.Get().Replicas[0].InsecureSkipVerify).Should(BeFalse())
|
||||||
})
|
})
|
||||||
It("should have the insecure skip verify from the config env var", func() {
|
It("should have the insecure skip verify from the config env var", func() {
|
||||||
setEnv("REPLICA1_INSECURE_SKIP_VERIFY", "true")
|
setEnv("REPLICA1_INSECURE_SKIP_VERIFY", "true")
|
||||||
@@ -114,7 +114,7 @@ var _ = Describe("Config", func() {
|
|||||||
|
|
||||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||||
Ω(err).ShouldNot(HaveOccurred())
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
Ω(cfg.Replicas[0].InsecureSkipVerify).Should(BeTrue())
|
Ω(cfg.Get().Replicas[0].InsecureSkipVerify).Should(BeTrue())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
Context("API Port", func() {
|
Context("API Port", func() {
|
||||||
@@ -122,7 +122,7 @@ var _ = Describe("Config", func() {
|
|||||||
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
||||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||||
Ω(err).ShouldNot(HaveOccurred())
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
Ω(cfg.API.Port).Should(Equal(9090))
|
Ω(cfg.Get().API.Port).Should(Equal(9090))
|
||||||
})
|
})
|
||||||
It("should have the api port from the config flags", func() {
|
It("should have the api port from the config flags", func() {
|
||||||
flags.EXPECT().Changed(config.FlagApiPort).Return(true).AnyTimes()
|
flags.EXPECT().Changed(config.FlagApiPort).Return(true).AnyTimes()
|
||||||
@@ -131,7 +131,7 @@ var _ = Describe("Config", func() {
|
|||||||
|
|
||||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||||
Ω(err).ShouldNot(HaveOccurred())
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
Ω(cfg.API.Port).Should(Equal(9990))
|
Ω(cfg.Get().API.Port).Should(Equal(9990))
|
||||||
})
|
})
|
||||||
It("should have the api port from the config env var", func() {
|
It("should have the api port from the config env var", func() {
|
||||||
setEnv("API_PORT", "9999")
|
setEnv("API_PORT", "9999")
|
||||||
@@ -141,7 +141,7 @@ var _ = Describe("Config", func() {
|
|||||||
|
|
||||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||||
Ω(err).ShouldNot(HaveOccurred())
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
Ω(cfg.API.Port).Should(Equal(9999))
|
Ω(cfg.Get().API.Port).Should(Equal(9999))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -151,8 +151,8 @@ var _ = Describe("Config", func() {
|
|||||||
|
|
||||||
cfg, err := config.Get("../../testdata/config_test_replica.yaml", flags)
|
cfg, err := config.Get("../../testdata/config_test_replica.yaml", flags)
|
||||||
Ω(err).ShouldNot(HaveOccurred())
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
Ω(cfg.Replicas[0].DHCPServerEnabled).ShouldNot(BeNil())
|
Ω(cfg.Get().Replicas[0].DHCPServerEnabled).ShouldNot(BeNil())
|
||||||
Ω(*cfg.Replicas[0].DHCPServerEnabled).Should(BeFalse())
|
Ω(*cfg.Get().Replicas[0].DHCPServerEnabled).Should(BeFalse())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -162,8 +162,8 @@ var _ = Describe("Config", func() {
|
|||||||
|
|
||||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||||
Ω(err).ShouldNot(HaveOccurred())
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
Ω(cfg.Replicas[0].DHCPServerEnabled).ShouldNot(BeNil())
|
Ω(cfg.Get().Replicas[0].DHCPServerEnabled).ShouldNot(BeNil())
|
||||||
Ω(*cfg.Replicas[0].DHCPServerEnabled).Should(BeFalse())
|
Ω(*cfg.Get().Replicas[0].DHCPServerEnabled).Should(BeFalse())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
Context("API Port", func() {
|
Context("API Port", func() {
|
||||||
@@ -171,7 +171,7 @@ var _ = Describe("Config", func() {
|
|||||||
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
||||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||||
Ω(err).ShouldNot(HaveOccurred())
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
Ω(cfg.API.Port).Should(Equal(9090))
|
Ω(cfg.Get().API.Port).Should(Equal(9090))
|
||||||
})
|
})
|
||||||
It("should have the api port from the config flags", func() {
|
It("should have the api port from the config flags", func() {
|
||||||
flags.EXPECT().Changed(config.FlagApiPort).Return(true).AnyTimes()
|
flags.EXPECT().Changed(config.FlagApiPort).Return(true).AnyTimes()
|
||||||
@@ -180,7 +180,7 @@ var _ = Describe("Config", func() {
|
|||||||
|
|
||||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||||
Ω(err).ShouldNot(HaveOccurred())
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
Ω(cfg.API.Port).Should(Equal(9990))
|
Ω(cfg.Get().API.Port).Should(Equal(9990))
|
||||||
})
|
})
|
||||||
It("should have the api port from the config env var", func() {
|
It("should have the api port from the config env var", func() {
|
||||||
setEnv("API_PORT", "9999")
|
setEnv("API_PORT", "9999")
|
||||||
@@ -190,18 +190,16 @@ var _ = Describe("Config", func() {
|
|||||||
|
|
||||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||||
Ω(err).ShouldNot(HaveOccurred())
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
Ω(cfg.API.Port).Should(Equal(9999))
|
Ω(cfg.Get().API.Port).Should(Equal(9999))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
//////
|
|
||||||
|
|
||||||
Context("Feature DNS Server Config", func() {
|
Context("Feature DNS Server Config", func() {
|
||||||
It("should have the feature dns server config from the config file", func() {
|
It("should have the feature dns server config from the config file", func() {
|
||||||
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
||||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||||
Ω(err).ShouldNot(HaveOccurred())
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
Ω(cfg.Features.DNS.ServerConfig).Should(BeFalse())
|
Ω(cfg.Get().Features.DNS.ServerConfig).Should(BeFalse())
|
||||||
})
|
})
|
||||||
It("should have the feature dns server config from the config flags", func() {
|
It("should have the feature dns server config from the config flags", func() {
|
||||||
flags.EXPECT().Changed(config.FlagFeatureDnsServerConfig).Return(true).AnyTimes()
|
flags.EXPECT().Changed(config.FlagFeatureDnsServerConfig).Return(true).AnyTimes()
|
||||||
@@ -210,7 +208,7 @@ var _ = Describe("Config", func() {
|
|||||||
|
|
||||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||||
Ω(err).ShouldNot(HaveOccurred())
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
Ω(cfg.Features.DNS.ServerConfig).Should(BeTrue())
|
Ω(cfg.Get().Features.DNS.ServerConfig).Should(BeTrue())
|
||||||
})
|
})
|
||||||
It("should have the feature dns server config from the config env var", func() {
|
It("should have the feature dns server config from the config env var", func() {
|
||||||
setEnv("FEATURES_DNS_SERVER_CONFIG", "false")
|
setEnv("FEATURES_DNS_SERVER_CONFIG", "false")
|
||||||
@@ -220,7 +218,7 @@ var _ = Describe("Config", func() {
|
|||||||
|
|
||||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||||
Ω(err).ShouldNot(HaveOccurred())
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
Ω(cfg.Features.DNS.ServerConfig).Should(BeFalse())
|
Ω(cfg.Get().Features.DNS.ServerConfig).Should(BeFalse())
|
||||||
})
|
})
|
||||||
It("should have the feature dns server config from the config DEPRECATED env var", func() {
|
It("should have the feature dns server config from the config DEPRECATED env var", func() {
|
||||||
setEnv("FEATURES_DNS_SERVERCONFIG", "false")
|
setEnv("FEATURES_DNS_SERVERCONFIG", "false")
|
||||||
@@ -230,7 +228,7 @@ var _ = Describe("Config", func() {
|
|||||||
|
|
||||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||||
Ω(err).ShouldNot(HaveOccurred())
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
Ω(cfg.Features.DNS.ServerConfig).Should(BeFalse())
|
Ω(cfg.Get().Features.DNS.ServerConfig).Should(BeFalse())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
|
|
||||||
"github.com/bakito/adguardhome-sync/pkg/config"
|
"github.com/bakito/adguardhome-sync/pkg/config"
|
||||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
|
||||||
. "github.com/onsi/ginkgo/v2"
|
. "github.com/onsi/ginkgo/v2"
|
||||||
. "github.com/onsi/gomega"
|
. "github.com/onsi/gomega"
|
||||||
)
|
)
|
||||||
@@ -99,7 +98,7 @@ var _ = Describe("Config", func() {
|
|||||||
Ω(os.Setenv(fmt.Sprintf("REPLICA%s_INTERFACE_NAME", "1"), "eth0")).ShouldNot(HaveOccurred())
|
Ω(os.Setenv(fmt.Sprintf("REPLICA%s_INTERFACE_NAME", "1"), "eth0")).ShouldNot(HaveOccurred())
|
||||||
cfg, err := config.Get("", nil)
|
cfg, err := config.Get("", nil)
|
||||||
Ω(err).ShouldNot(HaveOccurred())
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
Ω(cfg.Replicas[0].InterfaceName).Should(Equal("eth0"))
|
Ω(cfg.Get().Replicas[0].InterfaceName).Should(Equal("eth0"))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
Context("dhcp server", func() {
|
Context("dhcp server", func() {
|
||||||
@@ -108,32 +107,32 @@ var _ = Describe("Config", func() {
|
|||||||
Ω(os.Setenv(fmt.Sprintf("REPLICA%s_DHCPSERVERENABLED", "1"), "true")).ShouldNot(HaveOccurred())
|
Ω(os.Setenv(fmt.Sprintf("REPLICA%s_DHCPSERVERENABLED", "1"), "true")).ShouldNot(HaveOccurred())
|
||||||
cfg, err := config.Get("", nil)
|
cfg, err := config.Get("", nil)
|
||||||
Ω(err).ShouldNot(HaveOccurred())
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
Ω(cfg.Replicas[0].DHCPServerEnabled).ShouldNot(BeNil())
|
Ω(cfg.Get().Replicas[0].DHCPServerEnabled).ShouldNot(BeNil())
|
||||||
Ω(*cfg.Replicas[0].DHCPServerEnabled).Should(BeTrue())
|
Ω(*cfg.Get().Replicas[0].DHCPServerEnabled).Should(BeTrue())
|
||||||
})
|
})
|
||||||
It("should disable the dhcp server of replica 1", func() {
|
It("should disable the dhcp server of replica 1", func() {
|
||||||
Ω(os.Setenv("REPLICA1_URL", "https://foo.bar")).ShouldNot(HaveOccurred())
|
Ω(os.Setenv("REPLICA1_URL", "https://foo.bar")).ShouldNot(HaveOccurred())
|
||||||
Ω(os.Setenv(fmt.Sprintf("REPLICA%s_DHCPSERVERENABLED", "1"), "false")).ShouldNot(HaveOccurred())
|
Ω(os.Setenv(fmt.Sprintf("REPLICA%s_DHCPSERVERENABLED", "1"), "false")).ShouldNot(HaveOccurred())
|
||||||
cfg, err := config.Get("", nil)
|
cfg, err := config.Get("", nil)
|
||||||
Ω(err).ShouldNot(HaveOccurred())
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
Ω(cfg.Replicas[0].DHCPServerEnabled).ShouldNot(BeNil())
|
Ω(cfg.Get().Replicas[0].DHCPServerEnabled).ShouldNot(BeNil())
|
||||||
Ω(*cfg.Replicas[0].DHCPServerEnabled).Should(BeFalse())
|
Ω(*cfg.Get().Replicas[0].DHCPServerEnabled).Should(BeFalse())
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
func verifyFeatures(cfg *types.Config, value bool) {
|
func verifyFeatures(cfg *config.AppConfig, value bool) {
|
||||||
Ω(cfg.Features.GeneralSettings).Should(Equal(value))
|
Ω(cfg.Get().Features.GeneralSettings).Should(Equal(value))
|
||||||
Ω(cfg.Features.QueryLogConfig).Should(Equal(value))
|
Ω(cfg.Get().Features.QueryLogConfig).Should(Equal(value))
|
||||||
Ω(cfg.Features.StatsConfig).Should(Equal(value))
|
Ω(cfg.Get().Features.StatsConfig).Should(Equal(value))
|
||||||
Ω(cfg.Features.ClientSettings).Should(Equal(value))
|
Ω(cfg.Get().Features.ClientSettings).Should(Equal(value))
|
||||||
Ω(cfg.Features.Services).Should(Equal(value))
|
Ω(cfg.Get().Features.Services).Should(Equal(value))
|
||||||
Ω(cfg.Features.Filters).Should(Equal(value))
|
Ω(cfg.Get().Features.Filters).Should(Equal(value))
|
||||||
Ω(cfg.Features.DHCP.ServerConfig).Should(Equal(value))
|
Ω(cfg.Get().Features.DHCP.ServerConfig).Should(Equal(value))
|
||||||
Ω(cfg.Features.DHCP.StaticLeases).Should(Equal(value))
|
Ω(cfg.Get().Features.DHCP.StaticLeases).Should(Equal(value))
|
||||||
Ω(cfg.Features.DNS.ServerConfig).Should(Equal(value))
|
Ω(cfg.Get().Features.DNS.ServerConfig).Should(Equal(value))
|
||||||
Ω(cfg.Features.DNS.AccessLists).Should(Equal(value))
|
Ω(cfg.Get().Features.DNS.AccessLists).Should(Equal(value))
|
||||||
Ω(cfg.Features.DNS.Rewrites).Should(Equal(value))
|
Ω(cfg.Get().Features.DNS.Rewrites).Should(Equal(value))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,17 +8,19 @@ import (
|
|||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
)
|
)
|
||||||
|
|
||||||
func readFile(cfg *types.Config, path string) error {
|
func readFile(cfg *types.Config, path string) (string, error) {
|
||||||
|
var content string
|
||||||
if _, err := os.Stat(path); err == nil {
|
if _, err := os.Stat(path); err == nil {
|
||||||
b, err := os.ReadFile(path)
|
b, err := os.ReadFile(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
|
content = string(b)
|
||||||
if err := yaml.Unmarshal(b, cfg); err != nil {
|
if err := yaml.Unmarshal(b, cfg); err != nil {
|
||||||
return err
|
return "", err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return nil
|
return content, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func configFilePath(configFile string) (string, error) {
|
func configFilePath(configFile string) (string, error) {
|
||||||
|
|||||||
90
pkg/config/print-config.go
Normal file
90
pkg/config/print-config.go
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
_ "embed"
|
||||||
|
"os"
|
||||||
|
"runtime"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
|
||||||
|
"github.com/bakito/adguardhome-sync/pkg/client"
|
||||||
|
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||||
|
"github.com/bakito/adguardhome-sync/version"
|
||||||
|
"gopkg.in/yaml.v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
//go:embed print-config.md
|
||||||
|
var printConfigTemplate string
|
||||||
|
|
||||||
|
func (ac *AppConfig) Print() error {
|
||||||
|
originVersion := aghVersion(ac.cfg.Origin)
|
||||||
|
var replicaVersions []string
|
||||||
|
for _, replica := range ac.cfg.Replicas {
|
||||||
|
replicaVersions = append(replicaVersions, aghVersion(replica))
|
||||||
|
}
|
||||||
|
|
||||||
|
out, err := ac.print(os.Environ(), originVersion, replicaVersions)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Infof(
|
||||||
|
"Printing adguardhome-sync aggregated config (THE APPLICATION WILL NOT START IN THIS MODE):\n%s",
|
||||||
|
out,
|
||||||
|
)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func aghVersion(i types.AdGuardInstance) string {
|
||||||
|
cl, err := client.New(i)
|
||||||
|
if err != nil {
|
||||||
|
return "N/A"
|
||||||
|
}
|
||||||
|
stats, err := cl.Status()
|
||||||
|
if err != nil {
|
||||||
|
return "N/A"
|
||||||
|
}
|
||||||
|
return stats.Version
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ac *AppConfig) print(env []string, originVersion string, replicaVersions []string) (string, error) {
|
||||||
|
config, err := yaml.Marshal(ac.Get())
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
funcMap := template.FuncMap{
|
||||||
|
// The name "inc" is what the function will be called in the template text.
|
||||||
|
"inc": func(i int) int {
|
||||||
|
return i + 1
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
t, err := template.New("printConfigTemplate").Funcs(funcMap).Parse(printConfigTemplate)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
sort.Strings(env)
|
||||||
|
|
||||||
|
var buf bytes.Buffer
|
||||||
|
|
||||||
|
if err = t.Execute(&buf, map[string]interface{}{
|
||||||
|
"Version": version.Version,
|
||||||
|
"Build": version.Build,
|
||||||
|
"OperatingSystem": runtime.GOOS,
|
||||||
|
"Architecture": runtime.GOARCH,
|
||||||
|
"AggregatedConfig": string(config),
|
||||||
|
"ConfigFilePath": ac.filePath,
|
||||||
|
"ConfigFileContent": ac.content,
|
||||||
|
"EnvironmentVariables": strings.Join(env, "\n"),
|
||||||
|
"OriginVersion": originVersion,
|
||||||
|
"ReplicaVersions": replicaVersions,
|
||||||
|
}); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return buf.String(), nil
|
||||||
|
}
|
||||||
36
pkg/config/print-config.md
Normal file
36
pkg/config/print-config.md
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<!-- PLEASE COPY THE FOLLOWING OUTPUT AS IS INTO THE GITHUB ISSUE (Don't forget to mask your usernames, passwords, IPs and other sensitive information when using this in an issue ) -->
|
||||||
|
|
||||||
|
### Runtime
|
||||||
|
|
||||||
|
AdguardHome-Sync Version: {{ .Version }}
|
||||||
|
Build: {{ .Build }}
|
||||||
|
OperatingSystem: {{ .OperatingSystem }}
|
||||||
|
Architecture: {{ .Architecture }}
|
||||||
|
OriginVersion: {{ .OriginVersion }}
|
||||||
|
ReplicaVersions:
|
||||||
|
{{- range $i,$rep := .ReplicaVersions }}
|
||||||
|
- Replica {{ inc $i }}: {{ $rep }}
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
### AdGuardHome sync aggregated config
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
{{ .AggregatedConfig }}
|
||||||
|
```
|
||||||
|
{{- if .ConfigFilePath }}
|
||||||
|
### AdGuardHome sync unmodified config file
|
||||||
|
|
||||||
|
Config file path: {{ .ConfigFilePath }}
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
{{ .ConfigFileContent }}
|
||||||
|
```
|
||||||
|
{{- end }}
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
|
||||||
|
```ini
|
||||||
|
{{ .EnvironmentVariables }}
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- END OF GITHUB ISSUE CONTENT -->
|
||||||
58
pkg/config/print-config_test.go
Normal file
58
pkg/config/print-config_test.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
_ "embed"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"runtime"
|
||||||
|
|
||||||
|
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||||
|
"github.com/bakito/adguardhome-sync/version"
|
||||||
|
. "github.com/onsi/ginkgo/v2"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("AppConfig", func() {
|
||||||
|
var (
|
||||||
|
ac *AppConfig
|
||||||
|
env []string
|
||||||
|
)
|
||||||
|
BeforeEach(func() {
|
||||||
|
ac = &AppConfig{
|
||||||
|
cfg: &types.Config{
|
||||||
|
Origin: types.AdGuardInstance{
|
||||||
|
URL: "https://ha.xxxx.net:3000",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
content: `
|
||||||
|
origin:
|
||||||
|
url: https://ha.xxxx.net:3000
|
||||||
|
`,
|
||||||
|
}
|
||||||
|
env = []string{"FOO=foo", "BAR=bar"}
|
||||||
|
})
|
||||||
|
Context("print", func() {
|
||||||
|
It("should print config without file", func() {
|
||||||
|
out, err := ac.print(env, "v0.0.1", []string{"v0.0.2"})
|
||||||
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
|
Ω(
|
||||||
|
out,
|
||||||
|
).Should(Equal(fmt.Sprintf(expected(1), version.Version, version.Build, runtime.GOOS, runtime.GOARCH)))
|
||||||
|
})
|
||||||
|
It("should print config with file", func() {
|
||||||
|
ac.filePath = "config.yaml"
|
||||||
|
out, err := ac.print(env, "v0.0.1", []string{"v0.0.2"})
|
||||||
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
|
Ω(
|
||||||
|
out,
|
||||||
|
).Should(Equal(fmt.Sprintf(expected(2), version.Version, version.Build, runtime.GOOS, runtime.GOARCH)))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
func expected(id int) string {
|
||||||
|
b, err := os.ReadFile(filepath.Join("../../testdata/config", fmt.Sprintf("print-config_test_expected%d.md", id)))
|
||||||
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
|
return string(b)
|
||||||
|
}
|
||||||
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())
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"github.com/bakito/adguardhome-sync/pkg/client/model"
|
"github.com/bakito/adguardhome-sync/pkg/client/model"
|
||||||
"github.com/bakito/adguardhome-sync/pkg/log"
|
"github.com/bakito/adguardhome-sync/pkg/log"
|
||||||
"github.com/prometheus/client_golang/prometheus"
|
"github.com/prometheus/client_golang/prometheus"
|
||||||
"golang.org/x/exp/constraints"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const StatsTotal = "total"
|
const StatsTotal = "total"
|
||||||
@@ -156,8 +155,8 @@ func initMetric(name string, metric *prometheus.GaugeVec) {
|
|||||||
l.With("name", name).Info("New Prometheus metric registered")
|
l.With("name", name).Info("New Prometheus metric registered")
|
||||||
}
|
}
|
||||||
|
|
||||||
func Update(ims ...InstanceMetrics) {
|
func Update(iml InstanceMetricsList) {
|
||||||
for _, im := range ims {
|
for _, im := range iml.Metrics {
|
||||||
update(im)
|
update(im)
|
||||||
stats[im.HostName] = im.Stats
|
stats[im.HostName] = im.Stats
|
||||||
}
|
}
|
||||||
@@ -231,6 +230,10 @@ func update(im InstanceMetrics) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type InstanceMetricsList struct {
|
||||||
|
Metrics []InstanceMetrics `faker:"slice_len=5"`
|
||||||
|
}
|
||||||
|
|
||||||
type InstanceMetrics struct {
|
type InstanceMetrics struct {
|
||||||
HostName string
|
HostName string
|
||||||
Status *model.ServerStatus
|
Status *model.ServerStatus
|
||||||
@@ -249,18 +252,14 @@ func (os OverallStats) consolidate() OverallStats {
|
|||||||
return consolidated
|
return consolidated
|
||||||
}
|
}
|
||||||
|
|
||||||
func safeMetric[T Number](v *T) float64 {
|
func safeMetric[T int | float64 | float32](v *T) float64 {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
return float64(*v)
|
return float64(*v)
|
||||||
}
|
}
|
||||||
|
|
||||||
type Number interface {
|
func getStats() OverallStats {
|
||||||
constraints.Float | constraints.Integer
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetStats() OverallStats {
|
|
||||||
return stats.consolidate()
|
return stats.consolidate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
13
pkg/metrics/metrics_suite_test.go
Normal file
13
pkg/metrics/metrics_suite_test.go
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package metrics_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
. "github.com/onsi/ginkgo/v2"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestSync(t *testing.T) {
|
||||||
|
RegisterFailHandler(Fail)
|
||||||
|
RunSpecs(t, "Metrics Suite")
|
||||||
|
}
|
||||||
101
pkg/metrics/metrics_test.go
Normal file
101
pkg/metrics/metrics_test.go
Normal file
@@ -0,0 +1,101 @@
|
|||||||
|
package metrics
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/bakito/adguardhome-sync/pkg/client/model"
|
||||||
|
"github.com/go-faker/faker/v4"
|
||||||
|
. "github.com/onsi/ginkgo/v2"
|
||||||
|
. "github.com/onsi/gomega"
|
||||||
|
"k8s.io/utils/ptr"
|
||||||
|
)
|
||||||
|
|
||||||
|
var _ = Describe("Metrics", func() {
|
||||||
|
BeforeEach(func() {
|
||||||
|
stats = make(OverallStats)
|
||||||
|
})
|
||||||
|
Context("Update / getStats", func() {
|
||||||
|
It("generate correct stats", func() {
|
||||||
|
Update(InstanceMetricsList{[]InstanceMetrics{
|
||||||
|
{HostName: "foo", Status: &model.ServerStatus{}, Stats: &model.Stats{
|
||||||
|
NumDnsQueries: ptr.To(100),
|
||||||
|
DnsQueries: ptr.To(
|
||||||
|
[]int{10, 20, 30, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||||
|
),
|
||||||
|
}},
|
||||||
|
{HostName: "bar", Status: &model.ServerStatus{}, Stats: &model.Stats{
|
||||||
|
NumDnsQueries: ptr.To(200),
|
||||||
|
DnsQueries: ptr.To(
|
||||||
|
[]int{20, 40, 60, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||||
|
),
|
||||||
|
}},
|
||||||
|
{HostName: "aaa", Status: &model.ServerStatus{}, Stats: &model.Stats{
|
||||||
|
NumDnsQueries: ptr.To(300),
|
||||||
|
DnsQueries: ptr.To(
|
||||||
|
[]int{30, 60, 90, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
|
||||||
|
),
|
||||||
|
}},
|
||||||
|
}})
|
||||||
|
Ω(stats).Should(HaveKey("foo"))
|
||||||
|
Ω(stats["foo"].NumDnsQueries).Should(Equal(ptr.To(100)))
|
||||||
|
Ω(stats).Should(HaveKey("bar"))
|
||||||
|
Ω(stats["bar"].NumDnsQueries).Should(Equal(ptr.To(200)))
|
||||||
|
Ω(stats).Should(HaveKey("aaa"))
|
||||||
|
Ω(stats["aaa"].NumDnsQueries).Should(Equal(ptr.To(300)))
|
||||||
|
|
||||||
|
os := getStats()
|
||||||
|
tot := os.Total()
|
||||||
|
Ω(*tot.NumDnsQueries).Should(Equal(600))
|
||||||
|
Ω(
|
||||||
|
*tot.DnsQueries,
|
||||||
|
).Should(Equal([]int{60, 120, 180, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}))
|
||||||
|
|
||||||
|
foo := os["foo"]
|
||||||
|
bar := os["bar"]
|
||||||
|
aaa := os["aaa"]
|
||||||
|
|
||||||
|
Ω(*foo.NumDnsQueries).Should(Equal(100))
|
||||||
|
Ω(*bar.NumDnsQueries).Should(Equal(200))
|
||||||
|
Ω(*aaa.NumDnsQueries).Should(Equal(300))
|
||||||
|
Ω(
|
||||||
|
*foo.DnsQueries,
|
||||||
|
).Should(Equal([]int{10, 20, 30, 40, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}))
|
||||||
|
Ω(
|
||||||
|
*bar.DnsQueries,
|
||||||
|
).Should(Equal([]int{20, 40, 60, 80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}))
|
||||||
|
Ω(
|
||||||
|
*aaa.DnsQueries,
|
||||||
|
).Should(Equal([]int{30, 60, 90, 120, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
Context("StatsGraph", func() {
|
||||||
|
var metrics InstanceMetricsList
|
||||||
|
BeforeEach(func() {
|
||||||
|
err := faker.FakeData(&metrics)
|
||||||
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
|
})
|
||||||
|
It("should provide correct results with faked values", func() {
|
||||||
|
Update(metrics)
|
||||||
|
|
||||||
|
_, dns, blocked, malware, adult := StatsGraph()
|
||||||
|
|
||||||
|
verifyStats(dns)
|
||||||
|
verifyStats(blocked)
|
||||||
|
verifyStats(malware)
|
||||||
|
verifyStats(adult)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
func verifyStats(lines []line) {
|
||||||
|
var total line
|
||||||
|
sum := make([]int, len(lines[0].Data))
|
||||||
|
for _, l := range lines {
|
||||||
|
if l.Title == labelTotal {
|
||||||
|
total = l
|
||||||
|
} else {
|
||||||
|
for i, d := range l.Data {
|
||||||
|
sum[i] = sum[i] + d
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ω(sum).Should(Equal(total.Data))
|
||||||
|
}
|
||||||
@@ -1,13 +1,14 @@
|
|||||||
package sync
|
package metrics
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"slices"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/bakito/adguardhome-sync/pkg/client/model"
|
"github.com/bakito/adguardhome-sync/pkg/client/model"
|
||||||
"github.com/bakito/adguardhome-sync/pkg/metrics"
|
|
||||||
"golang.org/x/exp/slices"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const labelTotal = "Total"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
blue = []int{78, 141, 245}
|
blue = []int{78, 141, 245}
|
||||||
blueAlternatives = [][]int{
|
blueAlternatives = [][]int{
|
||||||
@@ -46,30 +47,43 @@ var (
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
func statsGraph() (*model.Stats, []line, []line, []line, []line) {
|
func StatsGraph() (*model.Stats, []line, []line, []line, []line) {
|
||||||
s := metrics.GetStats()
|
s := getStats()
|
||||||
t := s.Total()
|
t := s.Total()
|
||||||
dns := graphLines(t, s, blue, blueAlternatives, func(s *model.Stats) []int {
|
dns := graphLines(t, s, blue, blueAlternatives, func(s *model.Stats) []int {
|
||||||
return *s.DnsQueries
|
return safeStats(s.DnsQueries)
|
||||||
})
|
})
|
||||||
blocked := graphLines(t, s, red, redAlternatives, func(s *model.Stats) []int {
|
blocked := graphLines(t, s, red, redAlternatives, func(s *model.Stats) []int {
|
||||||
return *s.BlockedFiltering
|
return safeStats(s.BlockedFiltering)
|
||||||
})
|
})
|
||||||
malware := graphLines(t, s, green, greenAlternatives, func(s *model.Stats) []int {
|
malware := graphLines(t, s, green, greenAlternatives, func(s *model.Stats) []int {
|
||||||
return *s.ReplacedSafebrowsing
|
return safeStats(s.ReplacedSafebrowsing)
|
||||||
})
|
})
|
||||||
adult := graphLines(t, s, yellow, yellowAlternatives, func(s *model.Stats) []int {
|
adult := graphLines(t, s, yellow, yellowAlternatives, func(s *model.Stats) []int {
|
||||||
return *s.ReplacedParental
|
return safeStats(s.ReplacedParental)
|
||||||
})
|
})
|
||||||
|
|
||||||
return t, dns, blocked, malware, adult
|
return t, dns, blocked, malware, adult
|
||||||
}
|
}
|
||||||
|
|
||||||
func graphLines(t *model.Stats, s metrics.OverallStats, baseColor []int, altColors [][]int, dataCB func(s *model.Stats) []int) []line {
|
func safeStats(stats *[]int) []int {
|
||||||
|
if stats == nil {
|
||||||
|
return make([]int, 0)
|
||||||
|
}
|
||||||
|
return *stats
|
||||||
|
}
|
||||||
|
|
||||||
|
func graphLines(
|
||||||
|
t *model.Stats,
|
||||||
|
s OverallStats,
|
||||||
|
baseColor []int,
|
||||||
|
altColors [][]int,
|
||||||
|
dataCB func(s *model.Stats) []int,
|
||||||
|
) []line {
|
||||||
g := &graph{
|
g := &graph{
|
||||||
total: line{
|
total: line{
|
||||||
Fill: true,
|
Fill: true,
|
||||||
Title: "Total",
|
Title: labelTotal,
|
||||||
Data: dataCB(t),
|
Data: dataCB(t),
|
||||||
R: baseColor[0],
|
R: baseColor[0],
|
||||||
G: baseColor[1],
|
G: baseColor[1],
|
||||||
@@ -79,7 +93,7 @@ func graphLines(t *model.Stats, s metrics.OverallStats, baseColor []int, altColo
|
|||||||
|
|
||||||
var i int
|
var i int
|
||||||
for name, data := range s {
|
for name, data := range s {
|
||||||
if name != metrics.StatsTotal {
|
if name != StatsTotal {
|
||||||
g.replicas = append(g.replicas, line{
|
g.replicas = append(g.replicas, line{
|
||||||
Fill: false,
|
Fill: false,
|
||||||
Title: name,
|
Title: name,
|
||||||
@@ -105,7 +105,8 @@ var (
|
|||||||
return ac.client.SetCustomRules(ac.origin.filters.UserRules)
|
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 ac.client.ToggleFiltering(*ac.origin.filters.Enabled, *ac.origin.filters.Interval)
|
||||||
}
|
}
|
||||||
return nil
|
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)
|
fa, fu, fd := model.MergeFilters(rFilters, of)
|
||||||
|
|
||||||
for _, f := range fd {
|
for _, f := range fd {
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ func (w *worker) handleSync(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *worker) handleRoot(c *gin.Context) {
|
func (w *worker) handleRoot(c *gin.Context) {
|
||||||
total, dns, blocked, malware, adult := statsGraph()
|
total, dns, blocked, malware, adult := metrics.StatsGraph()
|
||||||
|
|
||||||
c.HTML(http.StatusOK, "index.html", map[string]interface{}{
|
c.HTML(http.StatusOK, "index.html", map[string]interface{}{
|
||||||
"DarkMode": w.cfg.API.DarkMode,
|
"DarkMode": w.cfg.API.DarkMode,
|
||||||
@@ -42,14 +42,23 @@ func (w *worker) handleRoot(c *gin.Context) {
|
|||||||
"Build": version.Build,
|
"Build": version.Build,
|
||||||
"SyncStatus": w.status(),
|
"SyncStatus": w.status(),
|
||||||
"Stats": map[string]interface{}{
|
"Stats": map[string]interface{}{
|
||||||
"Labels": getLast24Hours(),
|
"Labels": getLast24Hours(),
|
||||||
"DNS": dns,
|
"DNS": dns,
|
||||||
"Blocked": blocked,
|
"Blocked": blocked,
|
||||||
"BlockedPercentage": fmt.Sprintf("%.2f", (float64(*total.NumBlockedFiltering)*100.0)/float64(*total.NumDnsQueries)),
|
"BlockedPercentage": fmt.Sprintf(
|
||||||
"Malware": malware,
|
"%.2f",
|
||||||
"MalwarePercentage": fmt.Sprintf("%.2f", (float64(*total.NumReplacedSafebrowsing)*100.0)/float64(*total.NumDnsQueries)),
|
(float64(*total.NumBlockedFiltering)*100.0)/float64(*total.NumDnsQueries),
|
||||||
"Adult": adult,
|
),
|
||||||
"AdultPercentage": fmt.Sprintf("%.2f", (float64(*total.NumReplacedParental)*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,
|
"TotalDNS": total.NumDnsQueries,
|
||||||
"TotalBlocked": total.NumBlockedFiltering,
|
"TotalBlocked": total.NumBlockedFiltering,
|
||||||
|
|||||||
@@ -7,9 +7,9 @@
|
|||||||
<link rel="stylesheet" href="https://bootswatch.com/5/darkly/bootstrap.min.css"
|
<link rel="stylesheet" href="https://bootswatch.com/5/darkly/bootstrap.min.css"
|
||||||
crossorigin="anonymous">
|
crossorigin="anonymous">
|
||||||
{{- else }}
|
{{- else }}
|
||||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.0/dist/css/bootstrap.min.css" rel="stylesheet"
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"
|
||||||
integrity="sha384-KyZXEAg3QhqLMpG8r+8fhAXLRk2vvoC2f3B09zVXn8CA5QIVfZOJ3BCsw2P0p/We"
|
integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH"
|
||||||
crossOrigin="anonymous">
|
crossorigin="anonymous">
|
||||||
{{- end }}
|
{{- end }}
|
||||||
<script type="text/javascript">
|
<script type="text/javascript">
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
@@ -47,7 +47,6 @@
|
|||||||
<link rel="shortcut icon" href="favicon.ico">
|
<link rel="shortcut icon" href="favicon.ico">
|
||||||
<style>
|
<style>
|
||||||
.stat-card {
|
.stat-card {
|
||||||
background-color: rgb(43, 43, 43);
|
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
@@ -58,11 +57,6 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
}
|
}
|
||||||
{{- if .Metrics }}
|
{{- if .Metrics }}
|
||||||
body {
|
|
||||||
background-color: rgb(30, 30, 30);
|
|
||||||
color: rgb(255, 255, 255);
|
|
||||||
font-family: Arial, sans-serif;
|
|
||||||
}
|
|
||||||
.stat-card h3 {
|
.stat-card h3 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
font-size: 2rem;
|
font-size: 2rem;
|
||||||
@@ -70,7 +64,6 @@
|
|||||||
.stat-card p {
|
.stat-card p {
|
||||||
margin: 5px 0;
|
margin: 5px 0;
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
color: rgb(78, 141, 245);
|
|
||||||
}
|
}
|
||||||
.percentage {
|
.percentage {
|
||||||
font-size: 0.9rem;
|
font-size: 0.9rem;
|
||||||
@@ -142,7 +135,7 @@
|
|||||||
<div class="btn-group" role="group">
|
<div class="btn-group" role="group">
|
||||||
<button type="button" class="btn btn-success" id="sync">Synchronize</button>
|
<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" 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>
|
</button>
|
||||||
<div class="dropdown-menu">
|
<div class="dropdown-menu">
|
||||||
<a class="dropdown-item" href="#" id="clearLogs">Clear Logs</a>
|
<a class="dropdown-item" href="#" id="clearLogs">Clear Logs</a>
|
||||||
@@ -171,14 +164,17 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.12.9/dist/umd/popper.min.js"
|
<!-- openssl dgst -sha384 -binary popper.min.js | openssl base64 -A -->
|
||||||
integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous">
|
<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>
|
||||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.0.0/dist/js/bootstrap.min.js"
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js"
|
||||||
integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous">
|
integrity="sha384-0pUGZvbkm6XF6gxjEnlmuGrJXVbNuzT9qBBavbLwCsOGabYfZo0T0to5eqruptLy" crossorigin="anonymous">
|
||||||
</script>
|
</script>
|
||||||
{{- if .Metrics }}
|
{{- if .Metrics }}
|
||||||
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
|
<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>
|
<script>
|
||||||
// Function to create minimal line charts
|
// Function to create minimal line charts
|
||||||
function createChart(canvasId, data) {
|
function createChart(canvasId, data) {
|
||||||
|
|||||||
@@ -26,13 +26,13 @@ func (w *worker) startScraping() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (w *worker) scrape() {
|
func (w *worker) scrape() {
|
||||||
var ims []metrics.InstanceMetrics
|
var iml metrics.InstanceMetricsList
|
||||||
|
|
||||||
ims = append(ims, w.getMetrics(w.cfg.Origin))
|
iml.Metrics = append(iml.Metrics, w.getMetrics(w.cfg.Origin))
|
||||||
for _, replica := range w.cfg.Replicas {
|
for _, replica := range w.cfg.Replicas {
|
||||||
ims = append(ims, w.getMetrics(replica))
|
iml.Metrics = append(iml.Metrics, w.getMetrics(replica))
|
||||||
}
|
}
|
||||||
metrics.Update(ims...)
|
metrics.Update(iml)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (w *worker) getMetrics(inst types.AdGuardInstance) (im metrics.InstanceMetrics) {
|
func (w *worker) getMetrics(inst types.AdGuardInstance) (im metrics.InstanceMetrics) {
|
||||||
|
|||||||
@@ -66,16 +66,12 @@ func Sync(cfg *types.Config) error {
|
|||||||
if cfg.API.Port != 0 {
|
if cfg.API.Port != 0 {
|
||||||
w.cron.Start()
|
w.cron.Start()
|
||||||
} else {
|
} else {
|
||||||
|
runOnStartAsync(cfg, w)
|
||||||
w.cron.Run()
|
w.cron.Run()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if cfg.API.Port != 0 {
|
if cfg.API.Port != 0 {
|
||||||
if cfg.RunOnStart {
|
runOnStartAsync(cfg, w)
|
||||||
go func() {
|
|
||||||
l.Info("Running sync on startup")
|
|
||||||
w.sync()
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
w.listenAndServe()
|
w.listenAndServe()
|
||||||
} else if cfg.RunOnStart {
|
} else if cfg.RunOnStart {
|
||||||
l.Info("Running sync on startup")
|
l.Info("Running sync on startup")
|
||||||
@@ -85,6 +81,15 @@ func Sync(cfg *types.Config) error {
|
|||||||
return nil
|
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 {
|
type worker struct {
|
||||||
cfg *types.Config
|
cfg *types.Config
|
||||||
running bool
|
running bool
|
||||||
@@ -167,7 +172,8 @@ func (w *worker) sync() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if versions.IsNewerThan(versions.MinAgh, o.status.Version) {
|
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
|
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")
|
rl.With("version", replicaStatus.Version).Info("Connected to replica")
|
||||||
|
|
||||||
if versions.IsNewerThan(versions.MinAgh, replicaStatus.Version) {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.status.Version != replicaStatus.Version {
|
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{
|
ac := &actionContext{
|
||||||
@@ -303,7 +311,11 @@ func (w *worker) syncTo(l *zap.SugaredLogger, o *origin, replica types.AdGuardIn
|
|||||||
rl.Info("Sync done")
|
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()
|
rs, err := rc.Status()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if replica.AutoSetup && errors.Is(err, client.ErrSetupNeeded) {
|
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() {
|
It("should not sync profileInfo if language is not set", func() {
|
||||||
ac.origin.profileInfo.Language = ""
|
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)
|
cl.EXPECT().SetProfileInfo(ac.origin.profileInfo).Times(0)
|
||||||
err := actionProfileInfo(ac)
|
err := actionProfileInfo(ac)
|
||||||
Ω(err).ShouldNot(HaveOccurred())
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
})
|
})
|
||||||
It("should not sync profileInfo if theme is not set", func() {
|
It("should not sync profileInfo if theme is not set", func() {
|
||||||
ac.origin.profileInfo.Theme = ""
|
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)
|
cl.EXPECT().SetProfileInfo(ac.origin.profileInfo).Times(0)
|
||||||
err := actionProfileInfo(ac)
|
err := actionProfileInfo(ac)
|
||||||
Ω(err).ShouldNot(HaveOccurred())
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
@@ -315,7 +319,8 @@ var _ = Describe("Sync", func() {
|
|||||||
var interval model.QueryLogConfigInterval = 123
|
var interval model.QueryLogConfigInterval = 123
|
||||||
ac.origin.queryLogConfig.Interval = &interval
|
ac.origin.queryLogConfig.Interval = &interval
|
||||||
cl.EXPECT().QueryLogConfig().Return(qlc, nil)
|
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 := actionQueryLogConfig(ac)
|
||||||
Ω(err).ShouldNot(HaveOccurred())
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
})
|
})
|
||||||
@@ -434,7 +439,9 @@ var _ = Describe("Sync", func() {
|
|||||||
Ω(err).ShouldNot(HaveOccurred())
|
Ω(err).ShouldNot(HaveOccurred())
|
||||||
})
|
})
|
||||||
It("should update a filter", func() {
|
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"}})
|
rf.Filters = utils.Ptr([]model.Filter{{Name: "foo", Url: "https://foo.bar"}})
|
||||||
cl.EXPECT().Filtering().Return(rf, nil)
|
cl.EXPECT().Filtering().Return(rf, nil)
|
||||||
cl.EXPECT().UpdateFilter(false, model.Filter{Name: "foo", Url: "https://foo.bar", Enabled: true})
|
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.cfg.ContinueOnError = false
|
||||||
ac.origin.filters.Filters = utils.Ptr([]model.Filter{{Name: "foo", Url: "https://foo.bar"}})
|
ac.origin.filters.Filters = utils.Ptr([]model.Filter{{Name: "foo", Url: "https://foo.bar"}})
|
||||||
cl.EXPECT().Filtering().Return(rf, nil)
|
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 := actionFilters(ac)
|
||||||
Ω(err).Should(HaveOccurred())
|
Ω(err).Should(HaveOccurred())
|
||||||
})
|
})
|
||||||
|
|
||||||
It("should continue after failed added filter", func() {
|
It("should continue after failed added filter", func() {
|
||||||
ac.cfg.ContinueOnError = true
|
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().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().AddFilter(false, model.Filter{Name: "bar", Url: "https://bar.foo"})
|
||||||
cl.EXPECT().RefreshFilters(gm.Any())
|
cl.EXPECT().RefreshFilters(gm.Any())
|
||||||
err := actionFilters(ac)
|
err := actionFilters(ac)
|
||||||
|
|||||||
@@ -27,15 +27,15 @@ func NewFeatures(enabled bool) Features {
|
|||||||
|
|
||||||
// Features feature flags
|
// Features feature flags
|
||||||
type Features struct {
|
type Features struct {
|
||||||
DNS DNS `json:"dns" yaml:"dns"`
|
DNS DNS `json:"dns" yaml:"dns"`
|
||||||
DHCP DHCP `json:"dhcp" yaml:"dhcp"`
|
DHCP DHCP `json:"dhcp" yaml:"dhcp"`
|
||||||
GeneralSettings bool `json:"generalSettings" yaml:"generalSettings" env:"FEATURES_GENERAL_SETTINGS"`
|
GeneralSettings bool `json:"generalSettings" yaml:"generalSettings" env:"FEATURES_GENERAL_SETTINGS"`
|
||||||
QueryLogConfig bool `json:"queryLogConfig" yaml:"queryLogConfig" env:"FEATURES_QUERY_LOG_CONFIG"`
|
QueryLogConfig bool `json:"queryLogConfig" yaml:"queryLogConfig" env:"FEATURES_QUERY_LOG_CONFIG"`
|
||||||
StatsConfig bool `json:"statsConfig" yaml:"statsConfig" env:"FEATURES_STATS_CONFIG"`
|
StatsConfig bool `json:"statsConfig" yaml:"statsConfig" env:"FEATURES_STATS_CONFIG"`
|
||||||
ClientSettings bool `json:"clientSettings" yaml:"clientSettings" env:"FEATURES_CLIENT_SETTINGS"`
|
ClientSettings bool `json:"clientSettings" yaml:"clientSettings" env:"FEATURES_CLIENT_SETTINGS"`
|
||||||
Services bool `json:"services" yaml:"services" env:"FEATURES_SERVICES"`
|
Services bool `json:"services" yaml:"services" env:"FEATURES_SERVICES"`
|
||||||
Filters bool `json:"filters" yaml:"filters" env:"FEATURES_FILTERS"`
|
Filters bool `json:"filters" yaml:"filters" env:"FEATURES_FILTERS"`
|
||||||
Theme bool `json:"theme" yaml:"theme" env:"FEATURES_THEME"`
|
Theme bool `json:"theme" yaml:"theme" env:"FEATURES_THEME"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// DHCP features
|
// DHCP features
|
||||||
@@ -46,9 +46,9 @@ type DHCP struct {
|
|||||||
|
|
||||||
// DNS features
|
// DNS features
|
||||||
type DNS struct {
|
type DNS struct {
|
||||||
AccessLists bool `json:"accessLists" yaml:"accessLists" env:"FEATURES_DNS_ACCESS_LISTS"`
|
AccessLists bool `json:"accessLists" yaml:"accessLists" env:"FEATURES_DNS_ACCESS_LISTS"`
|
||||||
ServerConfig bool `json:"serverConfig" yaml:"serverConfig" env:"FEATURES_DNS_SERVER_CONFIG"`
|
ServerConfig bool `json:"serverConfig" yaml:"serverConfig" env:"FEATURES_DNS_SERVER_CONFIG"`
|
||||||
Rewrites bool `json:"rewrites" yaml:"rewrites" env:"FEATURES_DNS_REWRITES"`
|
Rewrites bool `json:"rewrites" yaml:"rewrites" env:"FEATURES_DNS_REWRITES"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// LogDisabled log all disabled features
|
// LogDisabled log all disabled features
|
||||||
|
|||||||
@@ -18,39 +18,39 @@ const (
|
|||||||
// Config application configuration struct
|
// Config application configuration struct
|
||||||
// +k8s:deepcopy-gen=true
|
// +k8s:deepcopy-gen=true
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Origin AdGuardInstance `json:"origin" yaml:"origin" env:"ORIGIN"`
|
Origin AdGuardInstance `json:"origin" yaml:"origin" env:"ORIGIN"`
|
||||||
Replica *AdGuardInstance `json:"replica,omitempty" yaml:"replica,omitempty" env:"REPLICA"`
|
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"`
|
Cron string `json:"cron,omitempty" yaml:"cron,omitempty" env:"CRON"`
|
||||||
RunOnStart bool `json:"runOnStart,omitempty" yaml:"runOnStart,omitempty" env:"RUN_ON_START"`
|
RunOnStart bool `json:"runOnStart,omitempty" yaml:"runOnStart,omitempty" env:"RUN_ON_START"`
|
||||||
PrintConfigOnly bool `json:"printConfigOnly,omitempty" yaml:"printConfigOnly,omitempty" env:"PRINT_CONFIG_ONLY"`
|
PrintConfigOnly bool `json:"printConfigOnly,omitempty" yaml:"printConfigOnly,omitempty" env:"PRINT_CONFIG_ONLY"`
|
||||||
ContinueOnError bool `json:"continueOnError,omitempty" yaml:"continueOnError,omitempty" env:"CONTINUE_ON_ERROR"`
|
ContinueOnError bool `json:"continueOnError,omitempty" yaml:"continueOnError,omitempty" env:"CONTINUE_ON_ERROR"`
|
||||||
API API `json:"api,omitempty" yaml:"api,omitempty" env:"API"`
|
API API `json:"api,omitempty" yaml:"api,omitempty" env:"API"`
|
||||||
Features Features `json:"features,omitempty" yaml:"features,omitempty" env:"FEATURES_"`
|
Features Features `json:"features,omitempty" yaml:"features,omitempty" env:"FEATURES_"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// API configuration
|
// API configuration
|
||||||
type API struct {
|
type API struct {
|
||||||
Port int `json:"port,omitempty" yaml:"port,omitempty" env:"API_PORT"`
|
Port int `json:"port,omitempty" yaml:"port,omitempty" env:"API_PORT"`
|
||||||
Username string `json:"username,omitempty" yaml:"username,omitempty" env:"API_USERNAME"`
|
Username string `json:"username,omitempty" yaml:"username,omitempty" env:"API_USERNAME"`
|
||||||
Password string `json:"password,omitempty" yaml:"password,omitempty" env:"API_PASSWORD"`
|
Password string `json:"password,omitempty" yaml:"password,omitempty" env:"API_PASSWORD"`
|
||||||
DarkMode bool `json:"darkMode,omitempty" yaml:"darkMode,omitempty" env:"API_DARK_MODE"`
|
DarkMode bool `json:"darkMode,omitempty" yaml:"darkMode,omitempty" env:"API_DARK_MODE"`
|
||||||
Metrics Metrics `json:"metrics,omitempty" yaml:"metrics,omitempty" env:"API_METRICS"`
|
Metrics Metrics `json:"metrics,omitempty" yaml:"metrics,omitempty" env:"API_METRICS"`
|
||||||
TLS TLS `json:"tls,omitempty" yaml:"tls,omitempty" env:"API_TLS"`
|
TLS TLS `json:"tls,omitempty" yaml:"tls,omitempty" env:"API_TLS"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Metrics configuration
|
// Metrics configuration
|
||||||
type Metrics struct {
|
type Metrics struct {
|
||||||
Enabled bool `json:"enabled,omitempty" yaml:"enabled,omitempty" env:"API_METRICS_ENABLED"`
|
Enabled bool `json:"enabled,omitempty" yaml:"enabled,omitempty" env:"API_METRICS_ENABLED"`
|
||||||
ScrapeInterval time.Duration `json:"scrapeInterval,omitempty" yaml:"scrapeInterval,omitempty" env:"API_METRICS_SCRAPE_INTERVAL"`
|
ScrapeInterval time.Duration `json:"scrapeInterval,omitempty" yaml:"scrapeInterval,omitempty" env:"API_METRICS_SCRAPE_INTERVAL"`
|
||||||
QueryLogLimit int `json:"queryLogLimit,omitempty" yaml:"queryLogLimit,omitempty" env:"API_METRICS_QUERY_LOG_LIMIT"`
|
QueryLogLimit int `json:"queryLogLimit,omitempty" yaml:"queryLogLimit,omitempty" env:"API_METRICS_QUERY_LOG_LIMIT"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// TLS configuration
|
// TLS configuration
|
||||||
type TLS struct {
|
type TLS struct {
|
||||||
CertDir string `json:"certDir,omitempty" yaml:"certDir,omitempty" env:"API_TLS_CERT_DIR"`
|
CertDir string `json:"certDir,omitempty" yaml:"certDir,omitempty" env:"API_TLS_CERT_DIR"`
|
||||||
CertName string `json:"certName,omitempty" yaml:"certName,omitempty" env:"API_TLS_CERT_NAME"`
|
CertName string `json:"certName,omitempty" yaml:"certName,omitempty" env:"API_TLS_CERT_NAME"`
|
||||||
KeyName string `json:"keyName,omitempty" yaml:"keyName,omitempty" env:"API_TLS_KEY_NAME"`
|
KeyName string `json:"keyName,omitempty" yaml:"keyName,omitempty" env:"API_TLS_KEY_NAME"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t TLS) Enabled() bool {
|
func (t TLS) Enabled() bool {
|
||||||
@@ -140,15 +140,15 @@ func (cfg *Config) Init() error {
|
|||||||
// AdGuardInstance AdguardHome config instance
|
// AdGuardInstance AdguardHome config instance
|
||||||
// +k8s:deepcopy-gen=true
|
// +k8s:deepcopy-gen=true
|
||||||
type AdGuardInstance struct {
|
type AdGuardInstance struct {
|
||||||
URL string `json:"url" yaml:"url" env:"URL"`
|
URL string `json:"url" yaml:"url" env:"URL" faker:"url"`
|
||||||
WebURL string `json:"webURL" yaml:"webURL" env:"WEB_URL"`
|
WebURL string `json:"webURL" yaml:"webURL" env:"WEB_URL" faker:"url"`
|
||||||
APIPath string `json:"apiPath,omitempty" yaml:"apiPath,omitempty" env:"API_PATH"`
|
APIPath string `json:"apiPath,omitempty" yaml:"apiPath,omitempty" env:"API_PATH"`
|
||||||
Username string `json:"username,omitempty" yaml:"username,omitempty" env:"USERNAME"`
|
Username string `json:"username,omitempty" yaml:"username,omitempty" env:"USERNAME"`
|
||||||
Password string `json:"password,omitempty" yaml:"password,omitempty" env:"PASSWORD"`
|
Password string `json:"password,omitempty" yaml:"password,omitempty" env:"PASSWORD"`
|
||||||
Cookie string `json:"cookie,omitempty" yaml:"cookie,omitempty" env:"COOKIE"`
|
Cookie string `json:"cookie,omitempty" yaml:"cookie,omitempty" env:"COOKIE"`
|
||||||
InsecureSkipVerify bool `json:"insecureSkipVerify" yaml:"insecureSkipVerify" env:"INSECURE_SKIP_VERIFY"`
|
InsecureSkipVerify bool `json:"insecureSkipVerify" yaml:"insecureSkipVerify" env:"INSECURE_SKIP_VERIFY"`
|
||||||
AutoSetup bool `json:"autoSetup" yaml:"autoSetup" env:"AUTO_SETUP"`
|
AutoSetup bool `json:"autoSetup" yaml:"autoSetup" env:"AUTO_SETUP"`
|
||||||
InterfaceName string `json:"interfaceName,omitempty" yaml:"interfaceName,omitempty" env:"INTERFACE_NAME"`
|
InterfaceName string `json:"interfaceName,omitempty" yaml:"interfaceName,omitempty" env:"INTERFACE_NAME"`
|
||||||
DHCPServerEnabled *bool `json:"dhcpServerEnabled,omitempty" yaml:"dhcpServerEnabled,omitempty" env:"DHCP_SERVER_ENABLED"`
|
DHCPServerEnabled *bool `json:"dhcpServerEnabled,omitempty" yaml:"dhcpServerEnabled,omitempty" env:"DHCP_SERVER_ENABLED"`
|
||||||
|
|
||||||
Host string `json:"-" yaml:"-"`
|
Host string `json:"-" yaml:"-"`
|
||||||
@@ -187,8 +187,8 @@ func (i *AdGuardInstance) Init() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func mask(s string) string {
|
func mask(s string) string {
|
||||||
if s == "" {
|
if len(s) < 3 {
|
||||||
return "***"
|
return strings.Repeat("*", len(s))
|
||||||
}
|
}
|
||||||
mask := strings.Repeat("*", len(s)-2)
|
mask := strings.Repeat("*", len(s)-2)
|
||||||
return fmt.Sprintf("%v%s%v", string(s[0]), mask, string(s[len(s)-1]))
|
return fmt.Sprintf("%v%s%v", string(s[0]), mask, string(s[len(s)-1]))
|
||||||
|
|||||||
15
pkg/types/types_fuzz_test.go
Normal file
15
pkg/types/types_fuzz_test.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package types
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func FuzzMask(f *testing.F) {
|
||||||
|
testcases := []string{"", "a", "ab", "abc", "abcd"}
|
||||||
|
for _, tc := range testcases {
|
||||||
|
f.Add(tc)
|
||||||
|
}
|
||||||
|
f.Fuzz(func(t *testing.T, value string) {
|
||||||
|
_ = mask(value)
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -83,6 +83,15 @@ var _ = Describe("Types", func() {
|
|||||||
Ω(masked.API.Password).Should(Equal("p**s"))
|
Ω(masked.API.Password).Should(Equal("p**s"))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
DescribeTable("mask should work correctly",
|
||||||
|
func(value, expected string) {
|
||||||
|
Ω(mask(value)).Should(Equal(expected))
|
||||||
|
},
|
||||||
|
Entry(`Empty password`, "", ""),
|
||||||
|
Entry(`1 char password`, "a", "*"),
|
||||||
|
Entry(`2 char password`, "ab", "**"),
|
||||||
|
Entry(`3 char password`, "abc", "a*c"),
|
||||||
|
)
|
||||||
})
|
})
|
||||||
Context("Feature", func() {
|
Context("Feature", func() {
|
||||||
Context("LogDisabled", func() {
|
Context("LogDisabled", func() {
|
||||||
|
|||||||
31
testdata/config/print-config_test_expected1.md
vendored
Normal file
31
testdata/config/print-config_test_expected1.md
vendored
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
<!-- PLEASE COPY THE FOLLOWING OUTPUT AS IS INTO THE GITHUB ISSUE (Don't forget to mask your usernames, passwords, IPs and other sensitive information when using this in an issue ) -->
|
||||||
|
|
||||||
|
### Runtime
|
||||||
|
|
||||||
|
AdguardHome-Sync Version: %s
|
||||||
|
Build: %s
|
||||||
|
OperatingSystem: %s
|
||||||
|
Architecture: %s
|
||||||
|
OriginVersion: v0.0.1
|
||||||
|
ReplicaVersions:
|
||||||
|
- Replica 1: v0.0.2
|
||||||
|
|
||||||
|
### AdGuardHome sync aggregated config
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
origin:
|
||||||
|
url: https://ha.xxxx.net:3000
|
||||||
|
webURL: ""
|
||||||
|
insecureSkipVerify: false
|
||||||
|
autoSetup: false
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
|
||||||
|
```ini
|
||||||
|
BAR=bar
|
||||||
|
FOO=foo
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- END OF GITHUB ISSUE CONTENT -->
|
||||||
41
testdata/config/print-config_test_expected2.md
vendored
Normal file
41
testdata/config/print-config_test_expected2.md
vendored
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
<!-- PLEASE COPY THE FOLLOWING OUTPUT AS IS INTO THE GITHUB ISSUE (Don't forget to mask your usernames, passwords, IPs and other sensitive information when using this in an issue ) -->
|
||||||
|
|
||||||
|
### Runtime
|
||||||
|
|
||||||
|
AdguardHome-Sync Version: %s
|
||||||
|
Build: %s
|
||||||
|
OperatingSystem: %s
|
||||||
|
Architecture: %s
|
||||||
|
OriginVersion: v0.0.1
|
||||||
|
ReplicaVersions:
|
||||||
|
- Replica 1: v0.0.2
|
||||||
|
|
||||||
|
### AdGuardHome sync aggregated config
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
origin:
|
||||||
|
url: https://ha.xxxx.net:3000
|
||||||
|
webURL: ""
|
||||||
|
insecureSkipVerify: false
|
||||||
|
autoSetup: false
|
||||||
|
|
||||||
|
```
|
||||||
|
### AdGuardHome sync unmodified config file
|
||||||
|
|
||||||
|
Config file path: config.yaml
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
|
||||||
|
origin:
|
||||||
|
url: https://ha.xxxx.net:3000
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### Environment Variables
|
||||||
|
|
||||||
|
```ini
|
||||||
|
BAR=bar
|
||||||
|
FOO=foo
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- END OF GITHUB ISSUE CONTENT -->
|
||||||
Reference in New Issue
Block a user