Compare commits
74 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3139ad605f | ||
|
|
a9de069f6b | ||
|
|
4a8e2aab51 | ||
|
|
749c5f178c | ||
|
|
680989bc2e | ||
|
|
418989989b | ||
|
|
9a06a6ac10 | ||
|
|
ff7bae0bba | ||
|
|
215ee946dd | ||
|
|
cc13b9318d | ||
|
|
9d26eec6b0 | ||
|
|
bb969a0005 | ||
|
|
37b8fda889 | ||
|
|
0c9487a53d | ||
|
|
a039704f1b | ||
|
|
ec9be5aed6 | ||
|
|
542aacb002 | ||
|
|
e7e391f85c | ||
|
|
8ccd773b4b | ||
|
|
cb52a43940 | ||
|
|
2463809356 | ||
|
|
b71df4d8ed | ||
|
|
4cd60e818a | ||
|
|
31aad9471b | ||
|
|
34dac9e091 | ||
|
|
c1c81bb8f6 | ||
|
|
012350a8fd | ||
|
|
fefdda0015 | ||
|
|
55d63df17b | ||
|
|
37ee52aa8f | ||
|
|
da289017a5 | ||
|
|
0fb6f38bab | ||
|
|
014e9c8a26 | ||
|
|
d07c005191 | ||
|
|
a2b9930f92 | ||
|
|
8ac7b9addd | ||
|
|
8115f52d8a | ||
|
|
1581b82ae5 | ||
|
|
9a466cb86b | ||
|
|
fda2ac0a5a | ||
|
|
c1975eebdb | ||
|
|
ab891449cf | ||
|
|
e4f235586e | ||
|
|
49e79274bb | ||
|
|
4d077eba3c | ||
|
|
ad24071c9c | ||
|
|
d99af0c43d | ||
|
|
0f86e61cdd | ||
|
|
dea2d04a63 | ||
|
|
a34eb1ae57 | ||
|
|
6f426a870f | ||
|
|
0e129d4b10 | ||
|
|
2d65e7dc9e | ||
|
|
6e47c07aa3 | ||
|
|
dea159d766 | ||
|
|
e4221a9ca7 | ||
|
|
240a0285c2 | ||
|
|
bc69d0388c | ||
|
|
5043f157fa | ||
|
|
2b4877f122 | ||
|
|
53b9cf704c | ||
|
|
69dd7650e1 | ||
|
|
06b93cbdac | ||
|
|
dd21859cd1 | ||
|
|
9a19b33116 | ||
|
|
5385d0aaed | ||
|
|
02547975e9 | ||
|
|
598324b7aa | ||
|
|
49cd71daf7 | ||
|
|
2f2cd0af58 | ||
|
|
607238230d | ||
|
|
ed952dd891 | ||
|
|
50de6b1d71 | ||
|
|
4db293ccf2 |
28
.github/ISSUE_TEMPLATE/bug_report.md
vendored
28
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,28 +0,0 @@
|
||||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. What version of AdGuardHome sync used?
|
||||
2. What version of AdGuardHome us used?
|
||||
3. How does the configuration look?
|
||||
4. What is the error message?
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Log Files**
|
||||
If applicable, add log files or json responses from AdGuardHome to help explain your problem.
|
||||
Please set the environment variable `LOG_LEVEL=debug` to generate debug logs.
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
60
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
Normal file
60
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
name: Bug report
|
||||
description: Create a report to help us improve
|
||||
labels: ['bug']
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this issue report! If you have usage questions, please try the [FAQ](https://github.com/bakito/adguardhome-sync/wiki/FAQ) first.
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: What happened?
|
||||
description: Also tell us, what did you expect to happen?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: adguardhome-sync-version
|
||||
attributes:
|
||||
label: AdguardHome-Sync Version
|
||||
description: What version of adguardhome-sync was running when you discovered this issue?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: adguardhome-version
|
||||
attributes:
|
||||
label: AdguardHome Version
|
||||
description: What version of adguardhome was running when you discovered this issue?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: config
|
||||
attributes:
|
||||
label: Configuration
|
||||
description: |
|
||||
- How did you configure adguardhome-sync?
|
||||
- Please provide your configuration
|
||||
render: shell
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant log output
|
||||
description: |
|
||||
Please copy and paste any relevant **debug** log output. This will be automatically formatted into code, so no need for backticks.
|
||||
Enable debug logs by defining the following environment variable `LOG_LEVEL=debug`.
|
||||
|
||||
Please also check adguardhome logs and paste any relevant logs/errors to this issue.
|
||||
render: shell
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Anything else?
|
||||
description: |
|
||||
Links? References? Anything that will provide more context about the issue you are encountering!
|
||||
|
||||
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
|
||||
validations:
|
||||
required: false
|
||||
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
1
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
blank_issues_enabled: false
|
||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -1,20 +0,0 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: enhancement
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
36
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
Normal file
36
.github/ISSUE_TEMPLATE/feature_request.yaml
vendored
Normal file
@@ -0,0 +1,36 @@
|
||||
name: Feature request
|
||||
description: Suggest an idea for this project
|
||||
labels: ['enhancement']
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this issue report!
|
||||
- type: textarea
|
||||
id: relation
|
||||
attributes:
|
||||
label: Is your feature request related to a problem? Please describe.
|
||||
description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: solution
|
||||
attributes:
|
||||
label: Describe the solution you'd like*
|
||||
description: |
|
||||
A clear and concise description of what you want to happen.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: alternatives
|
||||
attributes:
|
||||
label: Describe alternatives you've considered
|
||||
description: |
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Anything else?
|
||||
description: |
|
||||
Add any other context or screenshots about the feature request here.
|
||||
validations:
|
||||
required: false
|
||||
60
.github/ISSUE_TEMPLATE/general_issue.yaml
vendored
Normal file
60
.github/ISSUE_TEMPLATE/general_issue.yaml
vendored
Normal file
@@ -0,0 +1,60 @@
|
||||
name: General Issue
|
||||
description: Report an issue with your setup
|
||||
labels: []
|
||||
body:
|
||||
- type: markdown
|
||||
attributes:
|
||||
value: |
|
||||
Thanks for taking the time to fill out this issue report! If you have usage questions, please try the [FAQ](https://github.com/bakito/adguardhome-sync/wiki/FAQ) first.
|
||||
- type: textarea
|
||||
id: what-happened
|
||||
attributes:
|
||||
label: What happened?
|
||||
description: Also tell us, what did you expect to happen?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: adguardhome-sync-version
|
||||
attributes:
|
||||
label: AdguardHome-Sync Version
|
||||
description: What version of adguardhome-sync was running when you discovered this issue?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: adguardhome-version
|
||||
attributes:
|
||||
label: AdguardHome Version
|
||||
description: What version of adguardhome was running when you discovered this issue?
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: config
|
||||
attributes:
|
||||
label: Configuration
|
||||
description: |
|
||||
- How did you configure adguardhome-sync?
|
||||
- Please provide your configuration
|
||||
render: shell
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant log output
|
||||
description: |
|
||||
Please copy and paste any relevant **debug** log output. This will be automatically formatted into code, so no need for backticks.
|
||||
Enable debug logs by defining the following environment variable `LOG_LEVEL=debug`.
|
||||
|
||||
Please also check adguardhome logs and paste any relevant logs/errors to this issue.
|
||||
render: shell
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Anything else?
|
||||
description: |
|
||||
Links? References? Anything that will provide more context about the issue you are encountering!
|
||||
|
||||
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
|
||||
validations:
|
||||
required: false
|
||||
8
.github/workflows/codeql-analysis.yml
vendored
8
.github/workflows/codeql-analysis.yml
vendored
@@ -38,11 +38,11 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v2
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
@@ -53,7 +53,7 @@ jobs:
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v2
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
@@ -67,4 +67,4 @@ jobs:
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v2
|
||||
uses: github/codeql-action/analyze@v3
|
||||
|
||||
4
.github/workflows/e2e.yaml
vendored
4
.github/workflows/e2e.yaml
vendored
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Install kind with registry
|
||||
uses: bakito/kind-with-registry-action@main
|
||||
@@ -31,3 +31,5 @@ jobs:
|
||||
run: ./testdata/e2e/bin/show-replica-logs.sh
|
||||
- name: Show Sync Logs
|
||||
run: ./testdata/e2e/bin/show-sync-logs.sh
|
||||
- name: Read latest replica config
|
||||
run: ./testdata/e2e/bin/read-latest-replica-config.sh
|
||||
|
||||
16
.github/workflows/go.yml
vendored
16
.github/workflows/go.yml
vendored
@@ -11,15 +11,17 @@ jobs:
|
||||
name: lint
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: "go.mod"
|
||||
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v3
|
||||
with:
|
||||
skip-pkg-cache: true
|
||||
|
||||
test:
|
||||
name: test
|
||||
@@ -27,10 +29,10 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: "go.mod"
|
||||
|
||||
@@ -48,15 +50,15 @@ jobs:
|
||||
steps:
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v4
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version-file: "go.mod"
|
||||
|
||||
- name: Run GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v4
|
||||
uses: goreleaser/goreleaser-action@v5
|
||||
with:
|
||||
version: latest
|
||||
args: --skip-publish --snapshot --rm-dist
|
||||
|
||||
29
.github/workflows/publish.yml
vendored
29
.github/workflows/publish.yml
vendored
@@ -1,9 +1,9 @@
|
||||
name: docker-image
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
workflow_dispatch: # allows manual triggering
|
||||
schedule:
|
||||
- cron: '0 0 * * *'
|
||||
release:
|
||||
types:
|
||||
- published
|
||||
@@ -22,30 +22,31 @@ jobs:
|
||||
- name: Get current date
|
||||
run: echo "curr_date=$(date --utc +%Y-%m-%dT%H:%M:%SZ)" >> $GITHUB_ENV
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v2
|
||||
uses: docker/setup-qemu-action@v3
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
- name: Login to Quay
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: quay.io
|
||||
username: ${{ secrets.REGISTRY_USERNAME }}
|
||||
password: ${{ secrets.REGISTRY_PASSWORD }}
|
||||
- name: Login to ghcr.io
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Modify Dockerfile
|
||||
run: |
|
||||
sed -i -e "s|FROM scratch|FROM ${{ matrix.build.fromImage }}|g" Dockerfile
|
||||
|
||||
- name: Build and push ${{github.event.release.tag_name }}
|
||||
id: docker_build_release
|
||||
uses: docker/build-push-action@v4
|
||||
uses: docker/build-push-action@v5
|
||||
if: ${{ github.event.release.tag_name != '' }}
|
||||
with:
|
||||
context: .
|
||||
@@ -53,20 +54,26 @@ jobs:
|
||||
push: true
|
||||
tags: quay.io/bakito/adguardhome-sync:${{ matrix.build.tagPrefix }}latest,quay.io/bakito/adguardhome-sync:${{ matrix.build.tagPrefix }}${{ github.event.release.tag_name }},ghcr.io/bakito/adguardhome-sync:${{ matrix.build.tagPrefix }}latest,ghcr.io/bakito/adguardhome-sync:${{ matrix.build.tagPrefix }}${{ github.event.release.tag_name }}
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
||||
provenance: false
|
||||
build-args: |
|
||||
VERSION=${{ github.event.release.tag_name }}
|
||||
BUILD=${{ env.curr_date }}
|
||||
|
||||
- name: Check for commits in the last 24 hours
|
||||
run: echo "NEW_COMMIT_COUNT=$(git log --oneline --since '24 hours ago' | wc -l)" >> $GITHUB_ENV
|
||||
if: ${{ github.event.release.tag_name == '' }}
|
||||
|
||||
- name: Build and push main
|
||||
id: docker_build_main
|
||||
uses: docker/build-push-action@v4
|
||||
if: ${{ github.event.release.tag_name == '' }}
|
||||
uses: docker/build-push-action@v5
|
||||
if: ${{ github.event.release.tag_name == '' && env.NEW_COMMIT_COUNT > 0 }}
|
||||
with:
|
||||
context: .
|
||||
pull: true
|
||||
push: true
|
||||
tags: quay.io/bakito/adguardhome-sync:${{ matrix.build.tagPrefix }}main,ghcr.io/bakito/adguardhome-sync:${{ matrix.build.tagPrefix }}main
|
||||
platforms: linux/amd64,linux/arm64,linux/arm/v7
|
||||
provenance: false
|
||||
build-args: |
|
||||
VERSION=main
|
||||
BUILD=${{ env.curr_date }}
|
||||
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@@ -1,5 +1,7 @@
|
||||
.vscode
|
||||
.idea
|
||||
coverage.out
|
||||
.run
|
||||
coverage.out*
|
||||
dist
|
||||
adguardhome-sync
|
||||
main
|
||||
|
||||
@@ -5,7 +5,6 @@ linters:
|
||||
enable:
|
||||
- asciicheck
|
||||
- bodyclose
|
||||
- depguard
|
||||
- dogsled
|
||||
- durationcheck
|
||||
- errcheck
|
||||
@@ -24,7 +23,6 @@ linters:
|
||||
- misspell
|
||||
- nakedret
|
||||
- nolintlint
|
||||
- revive
|
||||
- staticcheck
|
||||
- unconvert
|
||||
- unparam
|
||||
|
||||
3
.oapi-codegen.yaml
Normal file
3
.oapi-codegen.yaml
Normal file
@@ -0,0 +1,3 @@
|
||||
output-options:
|
||||
client-type-name: AdguardHomeClient
|
||||
response-type-suffix: Resp
|
||||
@@ -1,8 +1,10 @@
|
||||
FROM golang:1.20 as builder
|
||||
FROM golang:1.21-bullseye as builder
|
||||
|
||||
WORKDIR /go/src/app
|
||||
|
||||
RUN apt-get update && apt-get install -y upx
|
||||
RUN apt-get update && \
|
||||
apt-get install -y upx ca-certificates tzdata && \
|
||||
apt-get upgrade -y # upgrade to get latest ca-certs
|
||||
|
||||
ARG VERSION=main
|
||||
ARG BUILD="N/A"
|
||||
@@ -24,6 +26,7 @@ LABEL maintainer="bakito <github@bakito.ch>"
|
||||
EXPOSE 8080
|
||||
ENTRYPOINT ["/opt/go/adguardhome-sync"]
|
||||
CMD ["run", "--config", "/config/adguardhome-sync.yaml"]
|
||||
COPY --from=builder /go/src/app/adguardhome-sync /opt/go/adguardhome-sync
|
||||
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
|
||||
COPY --from=builder /usr/share/zoneinfo/ /usr/share/zoneinfo/
|
||||
COPY --from=builder /go/src/app/adguardhome-sync /opt/go/adguardhome-sync
|
||||
USER 1001
|
||||
|
||||
32
Makefile
32
Makefile
@@ -16,7 +16,8 @@ test: generate lint test-ci
|
||||
|
||||
# Run ci tests
|
||||
test-ci: mocks tidy
|
||||
go test ./... -coverprofile=coverage.out
|
||||
go test ./... -coverprofile=coverage.out.tmp
|
||||
cat coverage.out.tmp | grep -v "_generated.go" > coverage.out
|
||||
go tool cover -func=coverage.out
|
||||
|
||||
mocks: mockgen
|
||||
@@ -28,7 +29,7 @@ release: semver goreleaser
|
||||
$(GORELEASER) --clean
|
||||
|
||||
test-release: goreleaser
|
||||
$(GORELEASER) --skip-publish --snapshot --rm-dist
|
||||
$(GORELEASER) --skip-publish --snapshot --clean
|
||||
|
||||
## toolbox - start
|
||||
## Current working directory
|
||||
@@ -40,6 +41,7 @@ $(LOCALBIN):
|
||||
|
||||
## Tool Binaries
|
||||
SEMVER ?= $(LOCALBIN)/semver
|
||||
OAPI_CODEGEN ?= $(LOCALBIN)/oapi-codegen
|
||||
MOCKGEN ?= $(LOCALBIN)/mockgen
|
||||
GOLANGCI_LINT ?= $(LOCALBIN)/golangci-lint
|
||||
GORELEASER ?= $(LOCALBIN)/goreleaser
|
||||
@@ -47,16 +49,21 @@ DEEPCOPY_GEN ?= $(LOCALBIN)/deepcopy-gen
|
||||
|
||||
## Tool Versions
|
||||
SEMVER_VERSION ?= v1.1.3
|
||||
OAPI_CODEGEN_VERSION ?= v2.0.0
|
||||
MOCKGEN_VERSION ?= v1.6.0
|
||||
GOLANGCI_LINT_VERSION ?= v1.52.2
|
||||
GORELEASER_VERSION ?= v1.17.0
|
||||
DEEPCOPY_GEN_VERSION ?= v0.27.0
|
||||
GOLANGCI_LINT_VERSION ?= v1.55.2
|
||||
GORELEASER_VERSION ?= v1.23.0
|
||||
DEEPCOPY_GEN_VERSION ?= v0.29.0
|
||||
|
||||
## Tool Installer
|
||||
.PHONY: semver
|
||||
semver: $(SEMVER) ## Download semver locally if necessary.
|
||||
$(SEMVER): $(LOCALBIN)
|
||||
test -s $(LOCALBIN)/semver || GOBIN=$(LOCALBIN) go install github.com/bakito/semver@$(SEMVER_VERSION)
|
||||
.PHONY: oapi-codegen
|
||||
oapi-codegen: $(OAPI_CODEGEN) ## Download oapi-codegen locally if necessary.
|
||||
$(OAPI_CODEGEN): $(LOCALBIN)
|
||||
test -s $(LOCALBIN)/oapi-codegen || GOBIN=$(LOCALBIN) go install github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen@$(OAPI_CODEGEN_VERSION)
|
||||
.PHONY: mockgen
|
||||
mockgen: $(MOCKGEN) ## Download mockgen locally if necessary.
|
||||
$(MOCKGEN): $(LOCALBIN)
|
||||
@@ -79,12 +86,14 @@ $(DEEPCOPY_GEN): $(LOCALBIN)
|
||||
update-toolbox-tools:
|
||||
@rm -f \
|
||||
$(LOCALBIN)/semver \
|
||||
$(LOCALBIN)/oapi-codegen \
|
||||
$(LOCALBIN)/mockgen \
|
||||
$(LOCALBIN)/golangci-lint \
|
||||
$(LOCALBIN)/goreleaser \
|
||||
$(LOCALBIN)/deepcopy-gen
|
||||
toolbox makefile -f $(LOCALDIR)/Makefile \
|
||||
github.com/bakito/semver \
|
||||
github.com/deepmap/oapi-codegen/v2/cmd/oapi-codegen \
|
||||
github.com/golang/mock/mockgen \
|
||||
github.com/golangci/golangci-lint/cmd/golangci-lint \
|
||||
github.com/goreleaser/goreleaser \
|
||||
@@ -95,6 +104,9 @@ start-replica:
|
||||
docker run --pull always --name adguardhome-replica -p 9091:3000 --rm adguard/adguardhome:latest
|
||||
# docker run --pull always --name adguardhome-replica -p 9090:80 -p 9091:3000 --rm adguard/adguardhome:v0.107.13
|
||||
|
||||
copy-replica-config:
|
||||
docker cp adguardhome-replica:/opt/adguardhome/conf/AdGuardHome.yaml tmp/AdGuardHome.yaml
|
||||
|
||||
start-replica2:
|
||||
docker run --pull always --name adguardhome-replica2 -p 9093:3000 --rm adguard/adguardhome:latest
|
||||
# docker run --pull always --name adguardhome-replica -p 9090:80 -p 9091:3000 --rm adguard/adguardhome:v0.107.13
|
||||
@@ -116,3 +128,13 @@ kind-create:
|
||||
|
||||
kind-test:
|
||||
@./testdata/e2e/bin/install-chart.sh
|
||||
|
||||
model: oapi-codegen
|
||||
@mkdir -p tmp
|
||||
go run openapi/main.go v0.107.43
|
||||
$(OAPI_CODEGEN) -package model -generate types,client -config .oapi-codegen.yaml tmp/schema.yaml > pkg/client/model/model_generated.go
|
||||
|
||||
model-diff:
|
||||
go run openapi/main.go v0.107.43
|
||||
go run openapi/main.go
|
||||
diff tmp/schema.yaml tmp/schema-master.yaml
|
||||
|
||||
60
README.md
60
README.md
@@ -6,6 +6,10 @@
|
||||
|
||||
Synchronize [AdGuardHome](https://github.com/AdguardTeam/AdGuardHome) config to replica instances.
|
||||
|
||||
## FAQ
|
||||
|
||||
Please check the wiki for [FAQ](https://github.com/bakito/adguardhome-sync/wiki/FAQ).
|
||||
|
||||
## Current sync features
|
||||
|
||||
- General Settings
|
||||
@@ -37,6 +41,15 @@ go install github.com/bakito/adguardhome-sync@latest
|
||||
|
||||
Both the origin instance must be initially setup via the AdguardHome installation wizard.
|
||||
|
||||
## Username / Password vs. Cookie
|
||||
|
||||
Some instances of AdGuard Home do not support basic authentication. For instance, many routers with built-in Adguard
|
||||
Home support do not. If this is the case, a valid cookie may be provided instead. If the router protects the AdGuard
|
||||
instance behind its own authentication, the cookie from an authenticated request may allow the sync to succeed.
|
||||
|
||||
- This has been tested successfully against GL.Inet routers with AdGuard Home.
|
||||
- Note: due to the short validity of cookies, this approach is likely only suitable for one-time syncs
|
||||
|
||||
## Run Linux/Mac
|
||||
|
||||
```bash
|
||||
@@ -45,9 +58,11 @@ export LOG_LEVEL=info
|
||||
export ORIGIN_URL=https://192.168.1.2:3000
|
||||
export ORIGIN_USERNAME=username
|
||||
export ORIGIN_PASSWORD=password
|
||||
# export ORIGIN_COOKIE=Origin-Cookie-Name=CCCOOOKKKIIIEEE
|
||||
export REPLICA_URL=http://192.168.1.3
|
||||
export REPLICA_USERNAME=username
|
||||
export REPLICA_PASSWORD=password
|
||||
# export REPLICA_COOKIE=Replica-Cookie-Name=CCCOOOKKKIIIEEE
|
||||
|
||||
# run once
|
||||
adguardhome-sync run
|
||||
@@ -70,10 +85,12 @@ REM set LOG_LEVEL=error
|
||||
set ORIGIN_URL=http://192.168.1.2:3000
|
||||
set ORIGIN_USERNAME=username
|
||||
set ORIGIN_PASSWORD=password
|
||||
# set ORIGIN_COOKIE=Origin-Cookie-Name=CCCOOOKKKIIIEEE
|
||||
|
||||
set REPLICA_URL=http://192.168.2.2:3000
|
||||
set REPLICA_USERNAME=username
|
||||
set REPLICA_PASSWORD=password
|
||||
# set REPLICA_COOKIE=Replica-Cookie-Name=CCCOOOKKKIIIEEE
|
||||
|
||||
set FEATURES_DHCP=false
|
||||
set FEATURES_DHCP_SERVERCONFIG=false
|
||||
@@ -127,22 +144,26 @@ services:
|
||||
container_name: adguardhome-sync
|
||||
command: run
|
||||
environment:
|
||||
LOG_LEVEL: 'info'
|
||||
ORIGIN_URL: 'https://192.168.1.2:3000'
|
||||
ORIGIN_USERNAME: 'username'
|
||||
ORIGIN_PASSWORD: 'password'
|
||||
REPLICA_URL: 'http://192.168.1.3'
|
||||
REPLICA_USERNAME: 'username'
|
||||
REPLICA_PASSWORD: 'password'
|
||||
REPLICA1_URL: 'http://192.168.1.4'
|
||||
REPLICA1_USERNAME: 'username'
|
||||
REPLICA1_PASSWORD: 'password'
|
||||
REPLICA1_APIPATH: '/some/path/control'
|
||||
LOG_LEVEL: "info"
|
||||
ORIGIN_URL: "https://192.168.1.2:3000"
|
||||
# ORIGIN_WEBURL: "https://some-other.url" # used in the web interface (default: <origin-url>
|
||||
|
||||
ORIGIN_USERNAME: "username"
|
||||
ORIGIN_PASSWORD: "password"
|
||||
REPLICA_URL: "http://192.168.1.3"
|
||||
REPLICA_USERNAME: "username"
|
||||
REPLICA_PASSWORD: "password"
|
||||
REPLICA1_URL: "http://192.168.1.4"
|
||||
REPLICA1_USERNAME: "username"
|
||||
REPLICA1_PASSWORD: "password"
|
||||
REPLICA1_APIPATH: "/some/path/control"
|
||||
# REPLICA1_WEBURL: "https://some-other.url" # used in the web interface (default: <replica-url>
|
||||
# REPLICA1_AUTOSETUP: true # if true, AdGuardHome is automatically initialized.
|
||||
# REPLICA1_INTERFACENAME: 'ens18' # use custom dhcp interface name
|
||||
# REPLICA1_DHCPSERVERENABLED: true/false (optional) enables/disables the dhcp server on the replica
|
||||
CRON: '*/10 * * * *' # run every 10 minutes
|
||||
CRON: "*/10 * * * *" # run every 10 minutes
|
||||
RUNONSTART: true
|
||||
# CONTINUEONERROR: false # If enabled, the synchronisation task will not fail on single errors, but will log the errors and continue
|
||||
|
||||
# Configure the sync API server, disabled if api port is 0
|
||||
API_PORT: 8080
|
||||
@@ -175,6 +196,9 @@ cron: "*/10 * * * *"
|
||||
# runs the synchronisation on startup
|
||||
runOnStart: true
|
||||
|
||||
# If enabled, the synchronisation task will not fail on single errors, but will log the errors and continue
|
||||
continueOnError: false
|
||||
|
||||
origin:
|
||||
# url of the origin instance
|
||||
url: https://192.168.1.2:3000
|
||||
@@ -182,6 +206,7 @@ origin:
|
||||
# insecureSkipVerify: true # disable tls check
|
||||
username: username
|
||||
password: password
|
||||
# cookie: Origin-Cookie-Name=CCCOOOKKKIIIEEE
|
||||
|
||||
# replica instance (optional, if only one)
|
||||
replica:
|
||||
@@ -189,6 +214,8 @@ replica:
|
||||
url: http://192.168.1.3
|
||||
username: username
|
||||
password: password
|
||||
# cookie: Replica-Cookie-Name=CCCOOOKKKIIIEEE
|
||||
# webURL: "https://some-other.url" # used in the web interface (default: <origin-url>
|
||||
|
||||
# replicas instances (optional, if more than one)
|
||||
replicas:
|
||||
@@ -196,18 +223,23 @@ replicas:
|
||||
- url: http://192.168.1.3
|
||||
username: username
|
||||
password: password
|
||||
# cookie: Replica1-Cookie-Name=CCCOOOKKKIIIEEE
|
||||
- url: http://192.168.1.4
|
||||
username: username
|
||||
password: password
|
||||
# autoSetup: true # if true, AdGuardHome is automatically initialized.
|
||||
# cookie: Replica2-Cookie-Name=CCCOOOKKKIIIEEE
|
||||
# autoSetup: true # if true, AdGuardHome is automatically initialized.
|
||||
# webURL: "https://some-other.url" # used in the web interface (default: <replica-url>
|
||||
|
||||
# Configure the sync API server, disabled if api port is 0
|
||||
api:
|
||||
# Port, default 8080
|
||||
port: 8080
|
||||
# if username and password are defined, basic auth is applied to the sync API
|
||||
# if username and password are defined, basic auth is applied to the sync API
|
||||
username: username
|
||||
password: password
|
||||
# enable api dark mode
|
||||
darkMode: true
|
||||
|
||||
# Configure sync features; by default all features are enabled.
|
||||
features:
|
||||
|
||||
44
cmd/root.go
44
cmd/root.go
@@ -12,12 +12,14 @@ import (
|
||||
"github.com/mitchellh/go-homedir"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
const (
|
||||
configCron = "cron"
|
||||
configRunOnStart = "runOnStart"
|
||||
configCron = "cron"
|
||||
configRunOnStart = "runOnStart"
|
||||
configPrintConfigOnly = "PRINT_CONFIG_ONLY"
|
||||
configContinueOnError = "CONTINUE_ON_ERROR"
|
||||
configLogLevel = "LOG_LEVEL"
|
||||
|
||||
configAPIPort = "api.port"
|
||||
configAPIUsername = "api.username"
|
||||
@@ -37,28 +39,32 @@ const (
|
||||
configFeatureFilters = "features.filters"
|
||||
|
||||
configOriginURL = "origin.url"
|
||||
configOriginWebURL = "origin.webURL"
|
||||
configOriginAPIPath = "origin.apiPath"
|
||||
configOriginUsername = "origin.username"
|
||||
configOriginPassword = "origin.password"
|
||||
configOriginCookie = "origin.cookie"
|
||||
configOriginInsecureSkipVerify = "origin.insecureSkipVerify"
|
||||
|
||||
configReplicaURL = "replica.url"
|
||||
configReplicaWebURL = "replica.webURL"
|
||||
configReplicaAPIPath = "replica.apiPath"
|
||||
configReplicaUsername = "replica.username"
|
||||
configReplicaPassword = "replica.password"
|
||||
configReplicaCookie = "replica.cookie"
|
||||
configReplicaInsecureSkipVerify = "replica.insecureSkipVerify"
|
||||
configReplicaAutoSetup = "replica.autoSetup"
|
||||
configReplicaInterfaceName = "replica.interfaceName"
|
||||
|
||||
envReplicasUsernameFormat = "REPLICA%s_USERNAME" // #nosec G101
|
||||
envReplicasPasswordFormat = "REPLICA%s_PASSWORD" // #nosec G101
|
||||
envReplicasCookieFormat = "REPLICA%s_COOKIE" // #nosec G101
|
||||
envReplicasAPIPathFormat = "REPLICA%s_APIPATH"
|
||||
envReplicasInsecureSkipVerifyFormat = "REPLICA%s_INSECURESKIPVERIFY"
|
||||
envReplicasAutoSetup = "REPLICA%s_AUTOSETUP"
|
||||
envReplicasInterfaceName = "REPLICA%s_INTERFACENAME"
|
||||
// Deprecated: use envReplicasInterfaceName instead
|
||||
envReplicasInterfaceNameDeprecated = "REPLICA%s_INTERFACWENAME"
|
||||
envDHCPServerEnabled = "REPLICA%s_DHCPSERVERENABLED"
|
||||
envDHCPServerEnabled = "REPLICA%s_DHCPSERVERENABLED"
|
||||
envWebURL = "REPLICA%s_WEBURL"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -126,41 +132,42 @@ func initConfig() {
|
||||
}
|
||||
}
|
||||
|
||||
func getConfig(logger *zap.SugaredLogger) (*types.Config, error) {
|
||||
func getConfig() (*types.Config, error) {
|
||||
cfg := &types.Config{}
|
||||
if err := viper.Unmarshal(cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if cfg.Replica != nil &&
|
||||
cfg.Replica.URL == "" &&
|
||||
cfg.Replica.Username == "" {
|
||||
cfg.Replica = nil
|
||||
}
|
||||
|
||||
if len(cfg.Replicas) == 0 {
|
||||
cfg.Replicas = append(cfg.Replicas, collectEnvReplicas(logger)...)
|
||||
cfg.Replicas = append(cfg.Replicas, collectEnvReplicas()...)
|
||||
}
|
||||
|
||||
return cfg, nil
|
||||
}
|
||||
|
||||
// Manually collect replicas from env.
|
||||
func collectEnvReplicas(logger *zap.SugaredLogger) []types.AdGuardInstance {
|
||||
func collectEnvReplicas() []types.AdGuardInstance {
|
||||
var replicas []types.AdGuardInstance
|
||||
for _, v := range os.Environ() {
|
||||
if envReplicasURLPattern.MatchString(v) {
|
||||
sm := envReplicasURLPattern.FindStringSubmatch(v)
|
||||
re := types.AdGuardInstance{
|
||||
URL: sm[2],
|
||||
WebURL: os.Getenv(fmt.Sprintf(envWebURL, sm[1])),
|
||||
Username: os.Getenv(fmt.Sprintf(envReplicasUsernameFormat, sm[1])),
|
||||
Password: os.Getenv(fmt.Sprintf(envReplicasPasswordFormat, sm[1])),
|
||||
Cookie: os.Getenv(fmt.Sprintf(envReplicasCookieFormat, sm[1])),
|
||||
APIPath: os.Getenv(fmt.Sprintf(envReplicasAPIPathFormat, sm[1])),
|
||||
InsecureSkipVerify: strings.EqualFold(os.Getenv(fmt.Sprintf(envReplicasInsecureSkipVerifyFormat, sm[1])), "true"),
|
||||
AutoSetup: strings.EqualFold(os.Getenv(fmt.Sprintf(envReplicasAutoSetup, sm[1])), "true"),
|
||||
InterfaceName: os.Getenv(fmt.Sprintf(envReplicasInterfaceName, sm[1])),
|
||||
}
|
||||
if re.InterfaceName == "" {
|
||||
if in, ok := os.LookupEnv(fmt.Sprintf(envReplicasInterfaceNameDeprecated, sm[1])); ok {
|
||||
logger.
|
||||
With("correct", envReplicasInterfaceName, "deprecated", envReplicasInterfaceNameDeprecated).
|
||||
Warn("Deprecated env variable is used, please use the correct one")
|
||||
re.InterfaceName = in
|
||||
}
|
||||
}
|
||||
|
||||
if dhcpEnabled, ok := os.LookupEnv(fmt.Sprintf(envDHCPServerEnabled, sm[1])); ok {
|
||||
if strings.EqualFold(dhcpEnabled, "true") {
|
||||
re.DHCPServerEnabled = boolPtr(true)
|
||||
@@ -168,6 +175,9 @@ func collectEnvReplicas(logger *zap.SugaredLogger) []types.AdGuardInstance {
|
||||
re.DHCPServerEnabled = boolPtr(false)
|
||||
}
|
||||
}
|
||||
if re.APIPath == "" {
|
||||
re.APIPath = "/control"
|
||||
}
|
||||
replicas = append(replicas, re)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,11 +4,9 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/log"
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var envVars = []string{
|
||||
@@ -24,14 +22,11 @@ var envVars = []string{
|
||||
"FEATURES_DNS_ACCESSLISTS",
|
||||
"FEATURES_DNS_REWRITES",
|
||||
"REPLICA1_INTERFACENAME",
|
||||
"REPLICA1_INTERFACWENAME",
|
||||
"REPLICA1_DHCPSERVERENABLED",
|
||||
}
|
||||
|
||||
var _ = Describe("Run", func() {
|
||||
var logger *zap.SugaredLogger
|
||||
BeforeEach(func() {
|
||||
logger = log.GetLogger("root")
|
||||
for _, envVar := range envVars {
|
||||
Ω(os.Unsetenv(envVar)).ShouldNot(HaveOccurred())
|
||||
}
|
||||
@@ -44,7 +39,7 @@ var _ = Describe("Run", func() {
|
||||
})
|
||||
Context("getConfig", func() {
|
||||
It("features should be true by default", func() {
|
||||
cfg, err := getConfig(logger)
|
||||
cfg, err := getConfig()
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
verifyFeatures(cfg, true)
|
||||
})
|
||||
@@ -52,7 +47,7 @@ var _ = Describe("Run", func() {
|
||||
for _, envVar := range envVars {
|
||||
Ω(os.Setenv(envVar, "false")).ShouldNot(HaveOccurred())
|
||||
}
|
||||
cfg, err := getConfig(logger)
|
||||
cfg, err := getConfig()
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
verifyFeatures(cfg, false)
|
||||
})
|
||||
@@ -60,22 +55,7 @@ var _ = Describe("Run", func() {
|
||||
It("should set interface name of replica 1", func() {
|
||||
Ω(os.Setenv("REPLICA1_URL", "https://foo.bar")).ShouldNot(HaveOccurred())
|
||||
Ω(os.Setenv(fmt.Sprintf(envReplicasInterfaceName, "1"), "eth0")).ShouldNot(HaveOccurred())
|
||||
cfg, err := getConfig(logger)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(cfg.Replicas[0].InterfaceName).Should(Equal("eth0"))
|
||||
})
|
||||
It("should set interface name of replica 1 from deprecated env", func() {
|
||||
Ω(os.Setenv("REPLICA1_URL", "https://foo.bar")).ShouldNot(HaveOccurred())
|
||||
Ω(os.Setenv(fmt.Sprintf(envReplicasInterfaceNameDeprecated, "1"), "eth0")).ShouldNot(HaveOccurred())
|
||||
cfg, err := getConfig(logger)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(cfg.Replicas[0].InterfaceName).Should(Equal("eth0"))
|
||||
})
|
||||
It("deprecated should not overwrite the correct", func() {
|
||||
Ω(os.Setenv("REPLICA1_URL", "https://foo.bar")).ShouldNot(HaveOccurred())
|
||||
Ω(os.Setenv(fmt.Sprintf(envReplicasInterfaceNameDeprecated, "1"), "eth1")).ShouldNot(HaveOccurred())
|
||||
Ω(os.Setenv(fmt.Sprintf(envReplicasInterfaceName, "1"), "eth0")).ShouldNot(HaveOccurred())
|
||||
cfg, err := getConfig(logger)
|
||||
cfg, err := getConfig()
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(cfg.Replicas[0].InterfaceName).Should(Equal("eth0"))
|
||||
})
|
||||
@@ -84,7 +64,7 @@ var _ = Describe("Run", func() {
|
||||
It("should enable the dhcp server of replica 1", func() {
|
||||
Ω(os.Setenv("REPLICA1_URL", "https://foo.bar")).ShouldNot(HaveOccurred())
|
||||
Ω(os.Setenv(fmt.Sprintf(envDHCPServerEnabled, "1"), "true")).ShouldNot(HaveOccurred())
|
||||
cfg, err := getConfig(logger)
|
||||
cfg, err := getConfig()
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(cfg.Replicas[0].DHCPServerEnabled).ShouldNot(BeNil())
|
||||
Ω(*cfg.Replicas[0].DHCPServerEnabled).Should(BeTrue())
|
||||
@@ -92,7 +72,7 @@ var _ = Describe("Run", func() {
|
||||
It("should disable the dhcp server of replica 1", func() {
|
||||
Ω(os.Setenv("REPLICA1_URL", "https://foo.bar")).ShouldNot(HaveOccurred())
|
||||
Ω(os.Setenv(fmt.Sprintf(envDHCPServerEnabled, "1"), "false")).ShouldNot(HaveOccurred())
|
||||
cfg, err := getConfig(logger)
|
||||
cfg, err := getConfig()
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(cfg.Replicas[0].DHCPServerEnabled).ShouldNot(BeNil())
|
||||
Ω(*cfg.Replicas[0].DHCPServerEnabled).Should(BeFalse())
|
||||
|
||||
37
cmd/run.go
37
cmd/run.go
@@ -5,6 +5,7 @@ import (
|
||||
"github.com/bakito/adguardhome-sync/pkg/sync"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/viper"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
// runCmd represents the run command
|
||||
@@ -14,12 +15,28 @@ var doCmd = &cobra.Command{
|
||||
Long: `Synchronizes the configuration form an origin instance to a replica`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
logger = log.GetLogger("run")
|
||||
cfg, err := getConfig(logger)
|
||||
cfg, err := getConfig()
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
if err := cfg.Init(); err != nil {
|
||||
logger.Error(err)
|
||||
return err
|
||||
}
|
||||
|
||||
if cfg.PrintConfigOnly {
|
||||
config, err := yaml.Marshal(cfg)
|
||||
if err != nil {
|
||||
logger.Error(err)
|
||||
return err
|
||||
}
|
||||
logger.Infof("Printing adguardhome-sync config (THE APPLICATION WILL NOT START IN THIS MODE): \n%s",
|
||||
string(config))
|
||||
return nil
|
||||
}
|
||||
|
||||
return sync.Sync(cfg)
|
||||
},
|
||||
}
|
||||
@@ -30,6 +47,16 @@ func init() {
|
||||
_ = viper.BindPFlag(configCron, doCmd.PersistentFlags().Lookup("cron"))
|
||||
doCmd.PersistentFlags().Bool("runOnStart", true, "Run the sync job on start.")
|
||||
_ = viper.BindPFlag(configRunOnStart, doCmd.PersistentFlags().Lookup("runOnStart"))
|
||||
doCmd.PersistentFlags().Bool("printConfigOnly", false, "Prints the configuration only and exists. "+
|
||||
"Can be used to debug the config E.g: when having authentication issues.")
|
||||
_ = viper.BindPFlag(configPrintConfigOnly, doCmd.PersistentFlags().Lookup("printConfigOnly"))
|
||||
doCmd.PersistentFlags().Bool("continueOnError", false, "If enabled, the synchronisation task "+
|
||||
"will not fail on single errors, but will log the errors and continue.")
|
||||
_ = viper.BindPFlag(configContinueOnError, doCmd.PersistentFlags().Lookup("continueOnError"))
|
||||
|
||||
doCmd.PersistentFlags().String("logLevel", "info", "The log level to set. One of (debug, info, warn and error)")
|
||||
_ = viper.BindPFlag(configLogLevel, doCmd.PersistentFlags().Lookup("logLevel"))
|
||||
|
||||
doCmd.PersistentFlags().Int("api-port", 8080, "Sync API Port, the API endpoint will be started to enable remote triggering; if 0 port API is disabled.")
|
||||
_ = viper.BindPFlag(configAPIPort, doCmd.PersistentFlags().Lookup("api-port"))
|
||||
doCmd.PersistentFlags().String("api-username", "", "Sync API username")
|
||||
@@ -66,23 +93,31 @@ func init() {
|
||||
|
||||
doCmd.PersistentFlags().String("origin-url", "", "Origin instance url")
|
||||
_ = viper.BindPFlag(configOriginURL, doCmd.PersistentFlags().Lookup("origin-url"))
|
||||
doCmd.PersistentFlags().String("origin-weburl", "", "Origin instance web url used in the web interface (default: <origin-url>)")
|
||||
_ = viper.BindPFlag(configOriginWebURL, doCmd.PersistentFlags().Lookup("origin-weburl"))
|
||||
doCmd.PersistentFlags().String("origin-api-path", "/control", "Origin instance API path")
|
||||
_ = viper.BindPFlag(configOriginAPIPath, doCmd.PersistentFlags().Lookup("origin-api-path"))
|
||||
doCmd.PersistentFlags().String("origin-username", "", "Origin instance username")
|
||||
_ = viper.BindPFlag(configOriginUsername, doCmd.PersistentFlags().Lookup("origin-username"))
|
||||
doCmd.PersistentFlags().String("origin-password", "", "Origin instance password")
|
||||
_ = viper.BindPFlag(configOriginPassword, doCmd.PersistentFlags().Lookup("origin-password"))
|
||||
doCmd.PersistentFlags().String("origin-cookie", "", "If Set, uses a cookie for authentication")
|
||||
_ = viper.BindPFlag(configOriginCookie, doCmd.PersistentFlags().Lookup("origin-cookie"))
|
||||
doCmd.PersistentFlags().Bool("origin-insecure-skip-verify", false, "Enable Origin instance InsecureSkipVerify")
|
||||
_ = viper.BindPFlag(configOriginInsecureSkipVerify, doCmd.PersistentFlags().Lookup("origin-insecure-skip-verify"))
|
||||
|
||||
doCmd.PersistentFlags().String("replica-url", "", "Replica instance url")
|
||||
_ = viper.BindPFlag(configReplicaURL, doCmd.PersistentFlags().Lookup("replica-url"))
|
||||
doCmd.PersistentFlags().String("replica-weburl", "", "Replica instance web url used in the web interface (default: <replica-url>)")
|
||||
_ = viper.BindPFlag(configOriginWebURL, doCmd.PersistentFlags().Lookup("replica-weburl"))
|
||||
doCmd.PersistentFlags().String("replica-api-path", "/control", "Replica instance API path")
|
||||
_ = viper.BindPFlag(configReplicaAPIPath, doCmd.PersistentFlags().Lookup("replica-api-path"))
|
||||
doCmd.PersistentFlags().String("replica-username", "", "Replica instance username")
|
||||
_ = viper.BindPFlag(configReplicaUsername, doCmd.PersistentFlags().Lookup("replica-username"))
|
||||
doCmd.PersistentFlags().String("replica-password", "", "Replica instance password")
|
||||
_ = viper.BindPFlag(configReplicaPassword, doCmd.PersistentFlags().Lookup("replica-password"))
|
||||
doCmd.PersistentFlags().String("replica-cookie", "", "If Set, uses a cookie for authentication")
|
||||
_ = viper.BindPFlag(configReplicaCookie, doCmd.PersistentFlags().Lookup("replica-cookie"))
|
||||
doCmd.PersistentFlags().Bool("replica-insecure-skip-verify", false, "Enable Replica instance InsecureSkipVerify")
|
||||
_ = viper.BindPFlag(configReplicaInsecureSkipVerify, doCmd.PersistentFlags().Lookup("replica-insecure-skip-verify"))
|
||||
doCmd.PersistentFlags().Bool("replica-auto-setup", false, "Enable automatic setup of new AdguardHome instances. This replaces the setup wizard.")
|
||||
|
||||
93
go.mod
93
go.mod
@@ -1,63 +1,80 @@
|
||||
module github.com/bakito/adguardhome-sync
|
||||
|
||||
go 1.20
|
||||
go 1.21
|
||||
|
||||
require (
|
||||
github.com/gin-gonic/gin v1.9.0
|
||||
github.com/go-resty/resty/v2 v2.7.0
|
||||
github.com/gin-gonic/gin v1.9.1
|
||||
github.com/go-resty/resty/v2 v2.9.1
|
||||
github.com/golang/mock v1.6.0
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/jinzhu/copier v0.3.5
|
||||
github.com/google/uuid v1.5.0
|
||||
github.com/jinzhu/copier v0.4.0
|
||||
github.com/mitchellh/go-homedir v1.1.0
|
||||
github.com/onsi/ginkgo/v2 v2.9.2
|
||||
github.com/onsi/gomega v1.27.6
|
||||
github.com/oapi-codegen/runtime v1.1.1
|
||||
github.com/onsi/ginkgo/v2 v2.13.2
|
||||
github.com/onsi/gomega v1.30.0
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/spf13/cobra v1.7.0
|
||||
github.com/spf13/viper v1.15.0
|
||||
go.uber.org/zap v1.24.0
|
||||
golang.org/x/mod v0.10.0
|
||||
github.com/spf13/cobra v1.8.0
|
||||
github.com/spf13/viper v1.18.2
|
||||
go.uber.org/zap v1.26.0
|
||||
golang.org/x/mod v0.14.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
k8s.io/apimachinery v0.29.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/bytedance/sonic v1.8.0 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
|
||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
|
||||
github.com/bytedance/sonic v1.10.2 // indirect
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect
|
||||
github.com/chenzhuoyu/iasm v0.9.1 // indirect
|
||||
github.com/fsnotify/fsnotify v1.7.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/go-logr/logr v1.2.3 // indirect
|
||||
github.com/go-logr/logr v1.3.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.11.2 // indirect
|
||||
github.com/go-playground/validator/v10 v10.16.0 // indirect
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 // indirect
|
||||
github.com/goccy/go-json v0.10.0 // indirect
|
||||
github.com/google/go-cmp v0.5.9 // indirect
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.0.9 // indirect
|
||||
github.com/leodido/go-urn v1.2.1 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.6 // indirect
|
||||
github.com/leodido/go-urn v1.2.4 // indirect
|
||||
github.com/magiconair/properties v1.8.7 // indirect
|
||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mitchellh/mapstructure v1.5.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.0.6 // indirect
|
||||
github.com/spf13/afero v1.9.3 // indirect
|
||||
github.com/spf13/cast v1.5.0 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.1.1 // indirect
|
||||
github.com/sagikazarmark/locafero v0.4.0 // indirect
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 // indirect
|
||||
github.com/sourcegraph/conc v0.3.0 // indirect
|
||||
github.com/spf13/afero v1.11.0 // indirect
|
||||
github.com/spf13/cast v1.6.0 // indirect
|
||||
github.com/spf13/pflag v1.0.5 // indirect
|
||||
github.com/subosito/gotenv v1.4.2 // indirect
|
||||
github.com/subosito/gotenv v1.6.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.9 // indirect
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.8.0 // indirect
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
|
||||
golang.org/x/crypto v0.5.0 // indirect
|
||||
golang.org/x/net v0.8.0 // indirect
|
||||
golang.org/x/sys v0.6.0 // indirect
|
||||
golang.org/x/text v0.8.0 // indirect
|
||||
golang.org/x/tools v0.7.0 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/arch v0.7.0 // indirect
|
||||
golang.org/x/crypto v0.17.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc // indirect
|
||||
golang.org/x/net v0.19.0 // indirect
|
||||
golang.org/x/sys v0.16.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/tools v0.16.0 // indirect
|
||||
google.golang.org/protobuf v1.32.0 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
gopkg.in/ini.v1 v1.67.0 // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
k8s.io/klog/v2 v2.110.1 // indirect
|
||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b // indirect
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect
|
||||
)
|
||||
|
||||
644
go.sum
644
go.sum
@@ -1,188 +1,96 @@
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.44.3/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
||||
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
|
||||
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
|
||||
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
|
||||
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
|
||||
cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI=
|
||||
cloud.google.com/go v0.74.0/go.mod h1:VV1xSbzvo+9QJOxLDaJfTjx5e+MePCpCWwvftOeQmWk=
|
||||
cloud.google.com/go v0.75.0/go.mod h1:VGuuCn7PG0dwsd5XPVm2Mm3wlh3EL55/79EKB6hlPTY=
|
||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
||||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
|
||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
||||
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
|
||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||
cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||
github.com/RaveNoX/go-jsoncommentstrip v1.0.0/go.mod h1:78ihd09MekBnJnxpICcwzCMzGrKSKYe4AqU6PDYYpjk=
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0 h1:axGnT1gRIfimI7gJifB699GoE/oq+F2MU7Dml6nw9rQ=
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP2+08jFMw88y4klk=
|
||||
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
|
||||
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
|
||||
github.com/bytedance/sonic v1.8.0 h1:ea0Xadu+sHlu7x5O3gKhRpQ1IKiMrSiHttPF0ybECuA=
|
||||
github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM=
|
||||
github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE=
|
||||
github.com/bytedance/sonic v1.10.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0=
|
||||
github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA=
|
||||
github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
|
||||
github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0=
|
||||
github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE=
|
||||
github.com/fsnotify/fsnotify v1.6.0 h1:n+5WquG0fcWoWp6xPWfHdbskMCQaFnG6PfBrh1Ky4HY=
|
||||
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
|
||||
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/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
|
||||
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8=
|
||||
github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k=
|
||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
||||
github.com/go-logr/logr v1.2.3 h1:2DntVwHkVopvECVRSlL5PSo9eG+cAkDCuckLubN+rq0=
|
||||
github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
|
||||
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
|
||||
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
|
||||
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU=
|
||||
github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s=
|
||||
github.com/go-resty/resty/v2 v2.7.0 h1:me+K9p3uhSmXtrBZ4k9jcEAfJmuC8IivWHwaLZwPrFY=
|
||||
github.com/go-resty/resty/v2 v2.7.0/go.mod h1:9PWDzw47qPphMRFfhsyk0NnSgvluHcljSMVIq3w7q0I=
|
||||
github.com/go-playground/validator/v10 v10.16.0 h1:x+plE831WK4vaKHO/jpgUGsvLKIqRRkz6M78GuJAfGE=
|
||||
github.com/go-playground/validator/v10 v10.16.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU=
|
||||
github.com/go-resty/resty/v2 v2.9.1 h1:PIgGx4VrHvag0juCJ4dDv3MiFRlDmP0vicBucwf+gLM=
|
||||
github.com/go-resty/resty/v2 v2.9.1/go.mod h1:4/GYJVjh9nhkhGR6AUNW3XhpDYNUr+Uvy9gV/VGZIy4=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI=
|
||||
github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls=
|
||||
github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA=
|
||||
github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
||||
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
|
||||
github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
||||
github.com/google/pprof v0.0.0-20201023163331-3e6fc7fc9c4c/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201203190320-1bf35d6f28c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20201218002935-b9804c9f04c2/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38 h1:yAJXTCF9TqKcTiHJAE8dj7HMvPfh66eeA2JYW7eFpSE=
|
||||
github.com/google/pprof v0.0.0-20210407192527-94a9f03dee38/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/google-cloud-go-testing v0.0.0-20200911160855-bcd43fbb19e8/go.mod h1:dvDLG8qkwmyD9a/MJJN3XJcT3xFxOKAvTZGvuZmac9g=
|
||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 h1:K6RDEckDVWvDI9JAJYCmNdQXq6neHJOYx3V6jnqNEec=
|
||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
|
||||
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
|
||||
github.com/jinzhu/copier v0.3.5 h1:GlvfUwHk62RokgqVNvYsku0TATCF7bAHVwEXoBh3iJg=
|
||||
github.com/jinzhu/copier v0.3.5/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
|
||||
github.com/jinzhu/copier v0.4.0 h1:w3ciUoD19shMCRargcpm0cm91ytaBhDvuRpz1ODO/U8=
|
||||
github.com/jinzhu/copier v0.4.0/go.mod h1:DfbEm0FYsaqBcKcFuvmOZb218JkPGtvSHsKg8S8hyyg=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
||||
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc=
|
||||
github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
|
||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
|
||||
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
|
||||
github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY=
|
||||
github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0=
|
||||
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
|
||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
|
||||
@@ -192,393 +100,177 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/onsi/ginkgo/v2 v2.9.2 h1:BA2GMJOtfGAfagzYtrAlufIP0lq6QERkFmHLMLPwFSU=
|
||||
github.com/onsi/ginkgo/v2 v2.9.2/go.mod h1:WHcJJG2dIlcCqVfBAwUCrJxSPFb6v4azBwgxeMeDuts=
|
||||
github.com/onsi/gomega v1.27.6 h1:ENqfyGeS5AX/rlXDd/ETokDz93u0YufY1Pgxuy/PvWE=
|
||||
github.com/onsi/gomega v1.27.6/go.mod h1:PIQNjfQwkP3aQAH7lf7j87O/5FiNr+ZR8+ipb+qQlhg=
|
||||
github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
|
||||
github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro=
|
||||
github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg=
|
||||
github.com/onsi/ginkgo/v2 v2.13.2 h1:Bi2gGVkfn6gQcjNjZJVO8Gf0FHzMPf2phUei9tejVMs=
|
||||
github.com/onsi/ginkgo/v2 v2.13.2/go.mod h1:XStQ8QcGwLyF4HdfcZB8SFOS/MWCgDuXMSBe6zrvLgM=
|
||||
github.com/onsi/gomega v1.30.0 h1:hvMK7xYz4D3HapigLTeGdId/NcfQx1VHMJc60ew99+8=
|
||||
github.com/onsi/gomega v1.30.0/go.mod h1:9sxs+SwGrKI0+PWe4Fxa9tFQQBG5xSsSbMXOI8PPpoQ=
|
||||
github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI=
|
||||
github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
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/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
|
||||
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
||||
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/spf13/afero v1.9.3 h1:41FoI0fD7OR7mGcKE/aOiLkGreyf8ifIOQmJANWogMk=
|
||||
github.com/spf13/afero v1.9.3/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y=
|
||||
github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w=
|
||||
github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU=
|
||||
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
|
||||
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
|
||||
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
github.com/sagikazarmark/locafero v0.4.0 h1:HApY1R9zGo4DBgr7dqsTH/JJxLTTsOt7u6keLGt6kNQ=
|
||||
github.com/sagikazarmark/locafero v0.4.0/go.mod h1:Pe1W6UlPYUk/+wc/6KFhbORCfqzgYEpgQ3O5fPuL3H4=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0 h1:diDBnUNK9N/354PgrxMywXnAwEr1QZcOr6gto+ugjYE=
|
||||
github.com/sagikazarmark/slog-shim v0.1.0/go.mod h1:SrcSrq8aKtyuqEI1uvTDTK1arOWRIczQRv+GVI1AkeQ=
|
||||
github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo=
|
||||
github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0=
|
||||
github.com/spf13/afero v1.11.0 h1:WJQKhtpdm3v2IzqG8VMqrr6Rf3UYpEF239Jy9wNepM8=
|
||||
github.com/spf13/afero v1.11.0/go.mod h1:GH9Y3pIexgf1MTIWtNGyogA5MwRIDXGUr+hbWNoBjkY=
|
||||
github.com/spf13/cast v1.6.0 h1:GEiTHELF+vaR5dhz3VqZfFSzZjYbgeKDpBxQVS4GYJ0=
|
||||
github.com/spf13/cast v1.6.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
||||
github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0=
|
||||
github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.15.0 h1:js3yy885G8xwJa6iOISGFwd+qlUo5AvyXb7CiihdtiU=
|
||||
github.com/spf13/viper v1.15.0/go.mod h1:fFcTBJxvhhzSJiZy8n+PeW6t8l+KeT/uTARa0jHOQLA=
|
||||
github.com/spf13/viper v1.18.2 h1:LUXCnvUvSM6FXAsj6nnfc8Q2tp1dIgUfY9Kc8GsSOiQ=
|
||||
github.com/spf13/viper v1.18.2/go.mod h1:EKmWIqdnk5lOcmR72yw6hS+8OPYcwD0jteitLMVB+yk=
|
||||
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8=
|
||||
github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU=
|
||||
github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/atomic v1.9.0 h1:ECmE8Bn/WFTYwEW/bpKD3M8VtR/zQVbavAoalC1PYyE=
|
||||
go.uber.org/atomic v1.9.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/goleak v1.1.11 h1:wy28qYRKZgnJTxGxvye5/wgWr1EKjmUDGYox5mGlRlI=
|
||||
go.uber.org/multierr v1.8.0 h1:dg6GjLku4EH+249NNmoIciG9N/jURbDG+pFlTkhzIC8=
|
||||
go.uber.org/multierr v1.8.0/go.mod h1:7EAYxJLBy9rStEaz58O2t4Uvip6FSURkq8/ppBp95ak=
|
||||
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
|
||||
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU=
|
||||
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
|
||||
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
|
||||
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
|
||||
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc=
|
||||
golang.org/x/arch v0.7.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-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/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-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
|
||||
golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
|
||||
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
|
||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/lint v0.0.0-20201208152925-83fdc39ff7b5/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
||||
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
|
||||
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
|
||||
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
|
||||
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc h1:ao2WRsKSzW6KuUY9IWPwWahcHCgR0s52IfwutMfEbdM=
|
||||
golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI=
|
||||
golang.org/x/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.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
|
||||
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
|
||||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/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-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20211029224645-99673261e6eb/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
|
||||
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201109201403-9fd604954f58/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20201208152858-08078c50e5b5/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/oauth2 v0.0.0-20210218202405-ba52d332ba99/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
|
||||
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
|
||||
golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||
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-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/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-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200331124033-c3d80250170d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0 h1:MVltZSvRTcU2ljQOhs94SXPftV6DCNnZViHeQps87pQ=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
|
||||
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
|
||||
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
|
||||
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
|
||||
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
|
||||
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.0.0-20211116232009-f0f3c7e86c11/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
|
||||
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/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-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
||||
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
|
||||
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
|
||||
golang.org/x/tools v0.0.0-20200904185747-39188db58858/go.mod h1:Cj7w3i3Rnn0Xh82ur9kSqwfTHTeVxaDqrfMjpcNT6bE=
|
||||
golang.org/x/tools v0.0.0-20201110124207-079ba7bd75cd/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201201161351-ac6f37ff4c2a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4=
|
||||
golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.16.0 h1:GO788SKMRunPIBCXiQyo2AaexLstOrVhuAL5YwsckQM=
|
||||
golang.org/x/tools v0.16.0/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
||||
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
|
||||
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
|
||||
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
|
||||
google.golang.org/api v0.35.0/go.mod h1:/XrVsuzM0rZmrsbjJutiuftIzeuTQcEeaYcSk/mQ1dg=
|
||||
google.golang.org/api v0.36.0/go.mod h1:+z5ficQTmoYpPn8LCUNVpK5I7hwkpjbcgqA7I34qYtE=
|
||||
google.golang.org/api v0.40.0/go.mod h1:fYKFpnQN0DsDSKRVRcQSDQNtqWPfM9i+zNPxepjRCQ8=
|
||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
|
||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
|
||||
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20200904004341-0bd0a958aa1d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201109203340-2640f1f9cdfb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201201144952-b05cb90ed32e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201210142538-e3217bee35cc/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20201214200347-8c77b98c765d/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210108203827-ffc7fda8c3d7/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/genproto v0.0.0-20210226172003-ab064af71705/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
|
||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
||||
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
|
||||
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
|
||||
google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8=
|
||||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
|
||||
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
|
||||
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
|
||||
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U=
|
||||
gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
||||
gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA=
|
||||
gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
k8s.io/apimachinery v0.29.0 h1:+ACVktwyicPz0oc6MTMLwa2Pw3ouLAfAon1wPLtG48o=
|
||||
k8s.io/apimachinery v0.29.0/go.mod h1:eVBxQ/cwiJxH58eK/jd/vAk4mrxmVlnpBH5J2GbMeis=
|
||||
k8s.io/klog/v2 v2.110.1 h1:U/Af64HJf7FcwMcXyKm2RPM22WZzyR7OSpYj5tg3cL0=
|
||||
k8s.io/klog/v2 v2.110.1/go.mod h1:YGtd1984u+GgbuZ7e08/yBuAfKLSO0+uR1Fhi6ExXjo=
|
||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b h1:sgn3ZU783SCgtaSJjpcVVlRqd6GSnlTLKgpAAttJvpI=
|
||||
k8s.io/utils v0.0.0-20230726121419-3b25d923346b/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo=
|
||||
sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08=
|
||||
sigs.k8s.io/yaml v1.3.0 h1:a2VclLzOGrwOHDiV8EfBGhvjHvP46CtW5j6POvhYGGo=
|
||||
sigs.k8s.io/yaml v1.3.0/go.mod h1:GeOyir5tyXNByN85N/dRIT9es5UQNerPYEKK56eTBm8=
|
||||
|
||||
63
openapi/main.go
Normal file
63
openapi/main.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
"os"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
||||
)
|
||||
|
||||
func main() {
|
||||
version := "master"
|
||||
fileName := "schema-master.yaml"
|
||||
if len(os.Args) > 1 {
|
||||
version = os.Args[1]
|
||||
fileName = "schema.yaml"
|
||||
}
|
||||
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))
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
defer func() { _ = resp.Body.Close() }()
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
schema := make(map[string]interface{})
|
||||
err = yaml.Unmarshal(data, &schema)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
if requestBodies, ok, _ := unstructured.NestedMap(schema, "components", "requestBodies"); ok {
|
||||
for k := range requestBodies {
|
||||
_ = unstructured.SetNestedField(schema, k+"Body", "components", "requestBodies", k, "x-go-name")
|
||||
}
|
||||
}
|
||||
|
||||
if dnsInfo, ok, _ := unstructured.NestedMap(schema,
|
||||
"paths", "/dns_info", "get", "responses", "200", "content", "application/json", "schema"); ok {
|
||||
if allOf, ok, _ := unstructured.NestedSlice(dnsInfo, "allOf"); ok && len(allOf) == 2 {
|
||||
delete(dnsInfo, "allOf")
|
||||
if err := unstructured.SetNestedMap(schema, allOf[0].(map[string]interface{}),
|
||||
"paths", "/dns_info", "get", "responses", "200", "content", "application/json", "schema"); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
b, err := yaml.Marshal(&schema)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
log.Printf("Writing schema file tmp/%s", fileName)
|
||||
err = os.WriteFile("tmp/"+fileName, b, 0o600)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
101
pkg/client/client-methods.go
Normal file
101
pkg/client/client-methods.go
Normal file
@@ -0,0 +1,101 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-resty/resty/v2"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func (cl *client) doGet(req *resty.Request, url string) error {
|
||||
rl := cl.log.With("method", "GET", "path", url)
|
||||
if cl.client.UserInfo != nil {
|
||||
rl = rl.With("username", cl.client.UserInfo.Username)
|
||||
}
|
||||
req.ForceContentType("application/json")
|
||||
rl.Debug("do get")
|
||||
resp, err := req.Get(url)
|
||||
if err != nil {
|
||||
if resp != nil && resp.StatusCode() == http.StatusFound {
|
||||
loc := resp.Header().Get("Location")
|
||||
if loc == "/install.html" || loc == "/control/install.html" {
|
||||
return ErrSetupNeeded
|
||||
}
|
||||
}
|
||||
|
||||
rl.With("status", resp.StatusCode(), "body", string(resp.Body()), "error", err).Debug("error in do get")
|
||||
return detailedError(resp, err)
|
||||
}
|
||||
|
||||
checkAuthenticationIssue(resp, rl)
|
||||
|
||||
rl.With(
|
||||
"status", resp.StatusCode(),
|
||||
"body", string(resp.Body()),
|
||||
"content-type", resp.Header()["Content-Type"],
|
||||
).Debug("got response")
|
||||
if resp.StatusCode() != http.StatusOK {
|
||||
return detailedError(resp, nil)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cl *client) doPost(req *resty.Request, url string) error {
|
||||
rl := cl.log.With("method", "POST", "path", url)
|
||||
if cl.client.UserInfo != nil {
|
||||
rl = rl.With("username", cl.client.UserInfo.Username)
|
||||
}
|
||||
b, _ := json.Marshal(req.Body)
|
||||
rl.With("body", string(b)).Debug("do post")
|
||||
resp, err := req.Post(url)
|
||||
if err != nil {
|
||||
rl.With("status", resp.StatusCode(), "body", string(resp.Body()), "error", err).Debug("error in do post")
|
||||
return detailedError(resp, err)
|
||||
}
|
||||
|
||||
checkAuthenticationIssue(resp, rl)
|
||||
|
||||
rl.With(
|
||||
"status", resp.StatusCode(),
|
||||
"body", string(resp.Body()),
|
||||
"content-type", contentType(resp),
|
||||
).Debug("got response")
|
||||
if resp.StatusCode() != http.StatusOK {
|
||||
return detailedError(resp, nil)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cl *client) doPut(req *resty.Request, url string) error {
|
||||
rl := cl.log.With("method", "PUT", "path", url)
|
||||
if cl.client.UserInfo != nil {
|
||||
rl = rl.With("username", cl.client.UserInfo.Username)
|
||||
}
|
||||
b, _ := json.Marshal(req.Body)
|
||||
rl.With("body", string(b)).Debug("do put")
|
||||
resp, err := req.Put(url)
|
||||
if err != nil {
|
||||
rl.With("status", resp.StatusCode(), "body", string(resp.Body()), "error", err).Debug("error in do put")
|
||||
return detailedError(resp, err)
|
||||
}
|
||||
|
||||
checkAuthenticationIssue(resp, rl)
|
||||
|
||||
rl.With(
|
||||
"status", resp.StatusCode(),
|
||||
"body", string(resp.Body()),
|
||||
"content-type", contentType(resp),
|
||||
).Debug("got response")
|
||||
if resp.StatusCode() != http.StatusOK {
|
||||
return detailedError(resp, nil)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkAuthenticationIssue(resp *resty.Response, rl *zap.SugaredLogger) {
|
||||
if resp != nil && (resp.StatusCode() == http.StatusUnauthorized || resp.StatusCode() == http.StatusForbidden) {
|
||||
rl.With("status", resp.StatusCode()).Error("there seems to be an authentication issue - " +
|
||||
"please check https://github.com/bakito/adguardhome-sync/wiki/FAQ")
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,6 @@ package client
|
||||
|
||||
import (
|
||||
"crypto/tls"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
@@ -10,9 +9,12 @@ import (
|
||||
"os"
|
||||
"path"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/client/model"
|
||||
"github.com/bakito/adguardhome-sync/pkg/log"
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
"github.com/bakito/adguardhome-sync/pkg/utils"
|
||||
"github.com/go-resty/resty/v2"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@@ -56,7 +58,13 @@ func New(config types.AdGuardInstance) (Client, error) {
|
||||
cl.SetTLSClientConfig(&tls.Config{InsecureSkipVerify: true})
|
||||
}
|
||||
|
||||
if config.Username != "" && config.Password != "" {
|
||||
cookieParts := strings.Split(config.Cookie, "=")
|
||||
if len(cookieParts) == 2 {
|
||||
cl.SetCookie(&http.Cookie{
|
||||
Name: cookieParts[0],
|
||||
Value: cookieParts[1],
|
||||
})
|
||||
} else if config.Username != "" && config.Password != "" {
|
||||
cl = cl.SetBasicAuth(config.Username, config.Password)
|
||||
}
|
||||
|
||||
@@ -72,52 +80,56 @@ func New(config types.AdGuardInstance) (Client, error) {
|
||||
}
|
||||
|
||||
return &client{
|
||||
host: u.Host,
|
||||
host: config.Host,
|
||||
client: cl,
|
||||
log: l.With("host", u.Host),
|
||||
log: l.With("host", config.Host),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Client AdguardHome API client interface
|
||||
type Client interface {
|
||||
Host() string
|
||||
Status() (*types.Status, error)
|
||||
Status() (*model.ServerStatus, error)
|
||||
ToggleProtection(enable bool) error
|
||||
RewriteList() (*types.RewriteEntries, error)
|
||||
AddRewriteEntries(e ...types.RewriteEntry) error
|
||||
DeleteRewriteEntries(e ...types.RewriteEntry) error
|
||||
Filtering() (*types.FilteringStatus, error)
|
||||
ToggleFiltering(enabled bool, interval float64) error
|
||||
AddFilters(whitelist bool, e ...types.Filter) error
|
||||
DeleteFilters(whitelist bool, e ...types.Filter) error
|
||||
UpdateFilters(whitelist bool, e ...types.Filter) error
|
||||
RewriteList() (*model.RewriteEntries, error)
|
||||
AddRewriteEntries(e ...model.RewriteEntry) error
|
||||
DeleteRewriteEntries(e ...model.RewriteEntry) error
|
||||
Filtering() (*model.FilterStatus, error)
|
||||
ToggleFiltering(enabled bool, interval int) error
|
||||
AddFilter(whitelist bool, f model.Filter) error
|
||||
DeleteFilter(whitelist bool, f model.Filter) error
|
||||
UpdateFilter(whitelist bool, f model.Filter) error
|
||||
RefreshFilters(whitelist bool) error
|
||||
SetCustomRules(rules types.UserRules) error
|
||||
SetCustomRules(rules *[]string) error
|
||||
SafeBrowsing() (bool, error)
|
||||
ToggleSafeBrowsing(enable bool) error
|
||||
Parental() (bool, error)
|
||||
ToggleParental(enable bool) error
|
||||
SafeSearch() (bool, error)
|
||||
ToggleSafeSearch(enable bool) error
|
||||
Services() (types.Services, error)
|
||||
SetServices(services types.Services) error
|
||||
Clients() (*types.Clients, error)
|
||||
AddClients(client ...types.Client) error
|
||||
UpdateClients(client ...types.Client) error
|
||||
DeleteClients(client ...types.Client) error
|
||||
QueryLogConfig() (*types.QueryLogConfig, error)
|
||||
SetQueryLogConfig(enabled bool, interval float64, anonymizeClientIP bool) error
|
||||
StatsConfig() (*types.IntervalConfig, error)
|
||||
SetStatsConfig(interval float64) error
|
||||
SafeSearchConfig() (*model.SafeSearchConfig, error)
|
||||
SetSafeSearchConfig(settings *model.SafeSearchConfig) error
|
||||
ProfileInfo() (*model.ProfileInfo, error)
|
||||
SetProfileInfo(settings *model.ProfileInfo) error
|
||||
BlockedServices() (*model.BlockedServicesArray, error)
|
||||
BlockedServicesSchedule() (*model.BlockedServicesSchedule, error)
|
||||
SetBlockedServices(services *model.BlockedServicesArray) error
|
||||
SetBlockedServicesSchedule(schedule *model.BlockedServicesSchedule) error
|
||||
Clients() (*model.Clients, error)
|
||||
AddClient(client *model.Client) error
|
||||
UpdateClient(client *model.Client) error
|
||||
DeleteClient(client *model.Client) error
|
||||
QueryLogConfig() (*model.QueryLogConfig, error)
|
||||
SetQueryLogConfig(*model.QueryLogConfig) error
|
||||
StatsConfig() (*model.StatsConfig, error)
|
||||
SetStatsConfig(sc *model.StatsConfig) error
|
||||
Setup() error
|
||||
AccessList() (*types.AccessList, error)
|
||||
SetAccessList(*types.AccessList) error
|
||||
DNSConfig() (*types.DNSConfig, error)
|
||||
SetDNSConfig(*types.DNSConfig) error
|
||||
DHCPServerConfig() (*types.DHCPServerConfig, error)
|
||||
SetDHCPServerConfig(*types.DHCPServerConfig) error
|
||||
AddDHCPStaticLeases(leases ...types.Lease) error
|
||||
DeleteDHCPStaticLeases(leases ...types.Lease) error
|
||||
AccessList() (*model.AccessList, error)
|
||||
SetAccessList(*model.AccessList) error
|
||||
DNSConfig() (*model.DNSConfig, error)
|
||||
SetDNSConfig(*model.DNSConfig) error
|
||||
DhcpConfig() (*model.DhcpStatus, error)
|
||||
SetDhcpConfig(*model.DhcpStatus) error
|
||||
AddDHCPStaticLease(lease model.DhcpStaticLease) error
|
||||
DeleteDHCPStaticLease(lease model.DhcpStaticLease) error
|
||||
}
|
||||
|
||||
type client struct {
|
||||
@@ -131,58 +143,6 @@ func (cl *client) Host() string {
|
||||
return cl.host
|
||||
}
|
||||
|
||||
func (cl *client) doGet(req *resty.Request, url string) error {
|
||||
rl := cl.log.With("method", "GET", "path", url)
|
||||
if cl.client.UserInfo != nil {
|
||||
rl = rl.With("username", cl.client.UserInfo.Username)
|
||||
}
|
||||
req.ForceContentType("application/json")
|
||||
rl.Debug("do get")
|
||||
resp, err := req.Get(url)
|
||||
if err != nil {
|
||||
if resp != nil && resp.StatusCode() == http.StatusFound {
|
||||
loc := resp.Header().Get("Location")
|
||||
if loc == "/install.html" || loc == "/control/install.html" {
|
||||
return ErrSetupNeeded
|
||||
}
|
||||
}
|
||||
rl.With("status", resp.StatusCode(), "body", string(resp.Body()), "error", err).Debug("error in do get")
|
||||
return detailedError(resp, err)
|
||||
}
|
||||
rl.With(
|
||||
"status", resp.StatusCode(),
|
||||
"body", string(resp.Body()),
|
||||
"content-type", resp.Header()["Content-Type"],
|
||||
).Debug("got response")
|
||||
if resp.StatusCode() != http.StatusOK {
|
||||
return detailedError(resp, nil)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cl *client) doPost(req *resty.Request, url string) error {
|
||||
rl := cl.log.With("method", "POST", "path", url)
|
||||
if cl.client.UserInfo != nil {
|
||||
rl = rl.With("username", cl.client.UserInfo.Username)
|
||||
}
|
||||
b, _ := json.Marshal(req.Body)
|
||||
rl.With("body", string(b)).Debug("do post")
|
||||
resp, err := req.Post(url)
|
||||
if err != nil {
|
||||
rl.With("status", resp.StatusCode(), "body", string(resp.Body()), "error", err).Debug("error in do post")
|
||||
return detailedError(resp, err)
|
||||
}
|
||||
rl.With(
|
||||
"status", resp.StatusCode(),
|
||||
"body", string(resp.Body()),
|
||||
"content-type", contentType(resp),
|
||||
).Debug("got response")
|
||||
if resp.StatusCode() != http.StatusOK {
|
||||
return detailedError(resp, nil)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func contentType(resp *resty.Response) string {
|
||||
if ct, ok := resp.Header()["Content-Type"]; ok {
|
||||
if len(ct) != 1 {
|
||||
@@ -193,23 +153,23 @@ func contentType(resp *resty.Response) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (cl *client) Status() (*types.Status, error) {
|
||||
status := &types.Status{}
|
||||
func (cl *client) Status() (*model.ServerStatus, error) {
|
||||
status := &model.ServerStatus{}
|
||||
err := cl.doGet(cl.client.R().EnableTrace().SetResult(status), "status")
|
||||
cl.version = status.Version
|
||||
return status, err
|
||||
}
|
||||
|
||||
func (cl *client) RewriteList() (*types.RewriteEntries, error) {
|
||||
rewrites := &types.RewriteEntries{}
|
||||
func (cl *client) RewriteList() (*model.RewriteEntries, error) {
|
||||
rewrites := &model.RewriteEntries{}
|
||||
err := cl.doGet(cl.client.R().EnableTrace().SetResult(&rewrites), "/rewrite/list")
|
||||
return rewrites, err
|
||||
}
|
||||
|
||||
func (cl *client) AddRewriteEntries(entries ...types.RewriteEntry) error {
|
||||
func (cl *client) AddRewriteEntries(entries ...model.RewriteEntry) error {
|
||||
for i := range entries {
|
||||
e := entries[i]
|
||||
cl.log.With("domain", e.Domain, "answer", e.Answer).Info("Add rewrite entry")
|
||||
cl.log.With("domain", e.Domain, "answer", e.Answer).Info("Add DNS rewrite entry")
|
||||
err := cl.doPost(cl.client.R().EnableTrace().SetBody(&e), "/rewrite/add")
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -218,10 +178,10 @@ func (cl *client) AddRewriteEntries(entries ...types.RewriteEntry) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cl *client) DeleteRewriteEntries(entries ...types.RewriteEntry) error {
|
||||
func (cl *client) DeleteRewriteEntries(entries ...model.RewriteEntry) error {
|
||||
for i := range entries {
|
||||
e := entries[i]
|
||||
cl.log.With("domain", e.Domain, "answer", e.Answer).Info("Delete rewrite entry")
|
||||
cl.log.With("domain", e.Domain, "answer", e.Answer).Info("Delete DNS rewrite entry")
|
||||
err := cl.doPost(cl.client.R().EnableTrace().SetBody(&e), "/rewrite/delete")
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -246,16 +206,8 @@ func (cl *client) ToggleParental(enable bool) error {
|
||||
return cl.toggleBool("parental", enable)
|
||||
}
|
||||
|
||||
func (cl *client) SafeSearch() (bool, error) {
|
||||
return cl.toggleStatus("safesearch")
|
||||
}
|
||||
|
||||
func (cl *client) ToggleSafeSearch(enable bool) error {
|
||||
return cl.toggleBool("safesearch", enable)
|
||||
}
|
||||
|
||||
func (cl *client) toggleStatus(mode string) (bool, error) {
|
||||
fs := &types.EnableConfig{}
|
||||
fs := &model.EnableConfig{}
|
||||
err := cl.doGet(cl.client.R().EnableTrace().SetResult(fs), fmt.Sprintf("/%s/status", mode))
|
||||
return fs.Enabled, err
|
||||
}
|
||||
@@ -271,51 +223,36 @@ func (cl *client) toggleBool(mode string, enable bool) error {
|
||||
return cl.doPost(cl.client.R().EnableTrace(), fmt.Sprintf("/%s/%s", mode, target))
|
||||
}
|
||||
|
||||
func (cl *client) Filtering() (*types.FilteringStatus, error) {
|
||||
f := &types.FilteringStatus{}
|
||||
func (cl *client) Filtering() (*model.FilterStatus, error) {
|
||||
f := &model.FilterStatus{}
|
||||
err := cl.doGet(cl.client.R().EnableTrace().SetResult(f), "/filtering/status")
|
||||
return f, err
|
||||
}
|
||||
|
||||
func (cl *client) AddFilters(whitelist bool, filters ...types.Filter) error {
|
||||
for _, f := range filters {
|
||||
cl.log.With("url", f.URL, "whitelist", whitelist, "enabled", f.Enabled).Info("Add filter")
|
||||
ff := &types.Filter{Name: f.Name, URL: f.URL, Whitelist: whitelist}
|
||||
err := cl.doPost(cl.client.R().EnableTrace().SetBody(ff), "/filtering/add_url")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
func (cl *client) AddFilter(whitelist bool, f model.Filter) error {
|
||||
cl.log.With("url", f.Url, "whitelist", whitelist, "enabled", f.Enabled).Info("Add filter")
|
||||
ff := &model.AddUrlRequest{Name: utils.Ptr(f.Name), Url: utils.Ptr(f.Url), Whitelist: utils.Ptr(whitelist)}
|
||||
return cl.doPost(cl.client.R().EnableTrace().SetBody(ff), "/filtering/add_url")
|
||||
}
|
||||
|
||||
func (cl *client) DeleteFilters(whitelist bool, filters ...types.Filter) error {
|
||||
for _, f := range filters {
|
||||
cl.log.With("url", f.URL, "whitelist", whitelist, "enabled", f.Enabled).Info("Delete filter")
|
||||
ff := &types.Filter{URL: f.URL, Whitelist: whitelist}
|
||||
err := cl.doPost(cl.client.R().EnableTrace().SetBody(ff), "/filtering/remove_url")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
func (cl *client) DeleteFilter(whitelist bool, f model.Filter) error {
|
||||
cl.log.With("url", f.Url, "whitelist", whitelist, "enabled", f.Enabled).Info("Delete filter")
|
||||
ff := &model.RemoveUrlRequest{Url: utils.Ptr(f.Url), Whitelist: utils.Ptr(whitelist)}
|
||||
return cl.doPost(cl.client.R().EnableTrace().SetBody(ff), "/filtering/remove_url")
|
||||
}
|
||||
|
||||
func (cl *client) UpdateFilters(whitelist bool, filters ...types.Filter) error {
|
||||
for _, f := range filters {
|
||||
cl.log.With("url", f.URL, "whitelist", whitelist, "enabled", f.Enabled).Info("Update filter")
|
||||
fu := &types.FilterUpdate{Whitelist: whitelist, URL: f.URL, Data: types.Filter{ID: f.ID, Name: f.Name, URL: f.URL, Whitelist: whitelist, Enabled: f.Enabled}}
|
||||
err := cl.doPost(cl.client.R().EnableTrace().SetBody(fu), "/filtering/set_url")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
func (cl *client) UpdateFilter(whitelist bool, f model.Filter) error {
|
||||
cl.log.With("url", f.Url, "whitelist", whitelist, "enabled", f.Enabled).Info("Update filter")
|
||||
fu := &model.FilterSetUrl{
|
||||
Whitelist: utils.Ptr(whitelist), Url: utils.Ptr(f.Url),
|
||||
Data: &model.FilterSetUrlData{Name: f.Name, Url: f.Url, Enabled: f.Enabled},
|
||||
}
|
||||
return nil
|
||||
return cl.doPost(cl.client.R().EnableTrace().SetBody(fu), "/filtering/set_url")
|
||||
}
|
||||
|
||||
func (cl *client) RefreshFilters(whitelist bool) error {
|
||||
cl.log.With("whitelist", whitelist).Info("Refresh filter")
|
||||
return cl.doPost(cl.client.R().EnableTrace().SetBody(&types.RefreshFilter{Whitelist: 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 {
|
||||
@@ -323,95 +260,82 @@ func (cl *client) ToggleProtection(enable bool) error {
|
||||
return cl.doPost(cl.client.R().EnableTrace().SetBody(&types.Protection{ProtectionEnabled: enable}), "/dns_config")
|
||||
}
|
||||
|
||||
func (cl *client) SetCustomRules(rules types.UserRules) error {
|
||||
cl.log.With("rules", len(rules)).Info("Set user rules")
|
||||
return cl.doPost(cl.client.R().EnableTrace().SetBody(rules.ToPayload(cl.version)), "/filtering/set_rules")
|
||||
func (cl *client) SetCustomRules(rules *[]string) error {
|
||||
cl.log.With("rules", len(*rules)).Info("Set user rules")
|
||||
return cl.doPost(cl.client.R().EnableTrace().SetBody(&model.SetRulesRequest{Rules: rules}), "/filtering/set_rules")
|
||||
}
|
||||
|
||||
func (cl *client) ToggleFiltering(enabled bool, interval float64) error {
|
||||
func (cl *client) ToggleFiltering(enabled bool, interval int) error {
|
||||
cl.log.With("enabled", enabled, "interval", interval).Info("Toggle filtering")
|
||||
return cl.doPost(cl.client.R().EnableTrace().SetBody(&types.FilteringConfig{
|
||||
EnableConfig: types.EnableConfig{Enabled: enabled},
|
||||
IntervalConfig: types.IntervalConfig{Interval: interval},
|
||||
return cl.doPost(cl.client.R().EnableTrace().SetBody(&model.FilterConfig{
|
||||
Enabled: utils.Ptr(enabled),
|
||||
Interval: utils.Ptr(interval),
|
||||
}), "/filtering/config")
|
||||
}
|
||||
|
||||
func (cl *client) Services() (types.Services, error) {
|
||||
svcs := types.Services{}
|
||||
err := cl.doGet(cl.client.R().EnableTrace().SetResult(&svcs), "/blocked_services/list")
|
||||
func (cl *client) BlockedServices() (*model.BlockedServicesArray, error) {
|
||||
svcs := &model.BlockedServicesArray{}
|
||||
err := cl.doGet(cl.client.R().EnableTrace().SetResult(svcs), "/blocked_services/list")
|
||||
return svcs, err
|
||||
}
|
||||
|
||||
func (cl *client) SetServices(services types.Services) error {
|
||||
cl.log.With("services", len(services)).Info("Set services")
|
||||
return cl.doPost(cl.client.R().EnableTrace().SetBody(&services), "/blocked_services/set")
|
||||
func (cl *client) SetBlockedServices(services *model.BlockedServicesArray) error {
|
||||
cl.log.With("services", model.ArrayString(services)).Info("Set blocked services")
|
||||
return cl.doPost(cl.client.R().EnableTrace().SetBody(services), "/blocked_services/set")
|
||||
}
|
||||
|
||||
func (cl *client) Clients() (*types.Clients, error) {
|
||||
clients := &types.Clients{}
|
||||
func (cl *client) BlockedServicesSchedule() (*model.BlockedServicesSchedule, error) {
|
||||
sched := &model.BlockedServicesSchedule{}
|
||||
err := cl.doGet(cl.client.R().EnableTrace().SetResult(sched), "/blocked_services/get")
|
||||
return sched, err
|
||||
}
|
||||
|
||||
func (cl *client) SetBlockedServicesSchedule(schedule *model.BlockedServicesSchedule) error {
|
||||
cl.log.With("services", schedule.ServicesString()).Info("Set blocked services schedule")
|
||||
return cl.doPut(cl.client.R().EnableTrace().SetBody(schedule), "/blocked_services/update")
|
||||
}
|
||||
|
||||
func (cl *client) Clients() (*model.Clients, error) {
|
||||
clients := &model.Clients{}
|
||||
err := cl.doGet(cl.client.R().EnableTrace().SetResult(clients), "/clients")
|
||||
return clients, err
|
||||
}
|
||||
|
||||
func (cl *client) AddClients(clients ...types.Client) error {
|
||||
for i := range clients {
|
||||
client := clients[i]
|
||||
cl.log.With("name", client.Name).Info("Add client")
|
||||
err := cl.doPost(cl.client.R().EnableTrace().SetBody(&client), "/clients/add")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
func (cl *client) AddClient(client *model.Client) error {
|
||||
cl.log.With("name", *client.Name).Info("Add client settings")
|
||||
return cl.doPost(cl.client.R().EnableTrace().SetBody(client), "/clients/add")
|
||||
}
|
||||
|
||||
func (cl *client) UpdateClients(clients ...types.Client) error {
|
||||
for _, client := range clients {
|
||||
cl.log.With("name", client.Name).Info("Update client")
|
||||
err := cl.doPost(cl.client.R().EnableTrace().SetBody(&types.ClientUpdate{Name: client.Name, Data: client}), "/clients/update")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
func (cl *client) UpdateClient(client *model.Client) error {
|
||||
cl.log.With("name", *client.Name).Info("Update client settings")
|
||||
return cl.doPost(cl.client.R().EnableTrace().SetBody(&model.ClientUpdate{Name: client.Name, Data: client}), "/clients/update")
|
||||
}
|
||||
|
||||
func (cl *client) DeleteClients(clients ...types.Client) error {
|
||||
for i := range clients {
|
||||
client := clients[i]
|
||||
cl.log.With("name", client.Name).Info("Delete client")
|
||||
err := cl.doPost(cl.client.R().EnableTrace().SetBody(&client), "/clients/delete")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
func (cl *client) DeleteClient(client *model.Client) error {
|
||||
cl.log.With("name", *client.Name).Info("Delete client settings")
|
||||
return cl.doPost(cl.client.R().EnableTrace().SetBody(client), "/clients/delete")
|
||||
}
|
||||
|
||||
func (cl *client) QueryLogConfig() (*types.QueryLogConfig, error) {
|
||||
qlc := &types.QueryLogConfig{}
|
||||
func (cl *client) QueryLogConfig() (*model.QueryLogConfig, error) {
|
||||
qlc := &model.QueryLogConfig{}
|
||||
err := cl.doGet(cl.client.R().EnableTrace().SetResult(qlc), "/querylog_info")
|
||||
return qlc, err
|
||||
}
|
||||
|
||||
func (cl *client) SetQueryLogConfig(enabled bool, interval float64, anonymizeClientIP bool) error {
|
||||
cl.log.With("enabled", enabled, "interval", interval, "anonymizeClientIP", anonymizeClientIP).Info("Set query log config")
|
||||
return cl.doPost(cl.client.R().EnableTrace().SetBody(&types.QueryLogConfig{
|
||||
EnableConfig: types.EnableConfig{Enabled: enabled},
|
||||
IntervalConfig: types.IntervalConfig{Interval: interval},
|
||||
AnonymizeClientIP: anonymizeClientIP,
|
||||
}), "/querylog_config")
|
||||
func (cl *client) SetQueryLogConfig(qlc *model.QueryLogConfig) error {
|
||||
cl.log.With("enabled", *qlc.Enabled, "interval", *qlc.Interval, "anonymizeClientIP", *qlc.AnonymizeClientIp).Info("Set query log config")
|
||||
return cl.doPost(cl.client.R().EnableTrace().SetBody(qlc), "/querylog_config")
|
||||
}
|
||||
|
||||
func (cl *client) StatsConfig() (*types.IntervalConfig, error) {
|
||||
stats := &types.IntervalConfig{}
|
||||
func (cl *client) StatsConfig() (*model.StatsConfig, error) {
|
||||
stats := &model.StatsConfig{}
|
||||
err := cl.doGet(cl.client.R().EnableTrace().SetResult(stats), "/stats_info")
|
||||
return stats, err
|
||||
}
|
||||
|
||||
func (cl *client) SetStatsConfig(interval float64) error {
|
||||
cl.log.With("interval", interval).Info("Set stats config")
|
||||
return cl.doPost(cl.client.R().EnableTrace().SetBody(&types.IntervalConfig{Interval: interval}), "/stats_config")
|
||||
func (cl *client) SetStatsConfig(sc *model.StatsConfig) error {
|
||||
cl.log.With("interval", *sc.Interval).Info("Set stats config")
|
||||
return cl.doPost(cl.client.R().EnableTrace().SetBody(sc), "/stats_config")
|
||||
}
|
||||
|
||||
func (cl *client) Setup() error {
|
||||
@@ -440,57 +364,75 @@ func (cl *client) Setup() error {
|
||||
return cl.doPost(req, "/install/configure")
|
||||
}
|
||||
|
||||
func (cl *client) AccessList() (*types.AccessList, error) {
|
||||
al := &types.AccessList{}
|
||||
func (cl *client) AccessList() (*model.AccessList, error) {
|
||||
al := &model.AccessList{}
|
||||
err := cl.doGet(cl.client.R().EnableTrace().SetResult(al), "/access/list")
|
||||
return al, err
|
||||
}
|
||||
|
||||
func (cl *client) SetAccessList(list *types.AccessList) error {
|
||||
func (cl *client) SetAccessList(list *model.AccessList) error {
|
||||
cl.log.Info("Set access list")
|
||||
return cl.doPost(cl.client.R().EnableTrace().SetBody(list), "/access/set")
|
||||
}
|
||||
|
||||
func (cl *client) DNSConfig() (*types.DNSConfig, error) {
|
||||
cfg := &types.DNSConfig{}
|
||||
func (cl *client) DNSConfig() (*model.DNSConfig, error) {
|
||||
cfg := &model.DNSConfig{}
|
||||
err := cl.doGet(cl.client.R().EnableTrace().SetResult(cfg), "/dns_info")
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
func (cl *client) SetDNSConfig(config *types.DNSConfig) error {
|
||||
func (cl *client) SetDNSConfig(config *model.DNSConfig) error {
|
||||
cl.log.Info("Set dns config list")
|
||||
return cl.doPost(cl.client.R().EnableTrace().SetBody(config), "/dns_config")
|
||||
}
|
||||
|
||||
func (cl *client) DHCPServerConfig() (*types.DHCPServerConfig, error) {
|
||||
cfg := &types.DHCPServerConfig{}
|
||||
func (cl *client) DhcpConfig() (*model.DhcpStatus, error) {
|
||||
cfg := &model.DhcpStatus{}
|
||||
err := cl.doGet(cl.client.R().EnableTrace().SetResult(cfg), "/dhcp/status")
|
||||
return cfg, err
|
||||
}
|
||||
|
||||
func (cl *client) SetDHCPServerConfig(config *types.DHCPServerConfig) error {
|
||||
func (cl *client) SetDhcpConfig(config *model.DhcpStatus) error {
|
||||
cl.log.Info("Set dhcp server config")
|
||||
return cl.doPost(cl.client.R().EnableTrace().SetBody(config), "/dhcp/set_config")
|
||||
}
|
||||
|
||||
func (cl *client) AddDHCPStaticLeases(leases ...types.Lease) error {
|
||||
for _, l := range leases {
|
||||
cl.log.With("mac", l.HWAddr, "ip", l.IP, "hostname", l.Hostname).Info("Add static dhcp lease")
|
||||
err := cl.doPost(cl.client.R().EnableTrace().SetBody(l), "/dhcp/add_static_lease")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
func (cl *client) AddDHCPStaticLease(l model.DhcpStaticLease) error {
|
||||
cl.log.With("mac", l.Mac, "ip", l.Ip, "hostname", l.Hostname).Info("Add static dhcp lease")
|
||||
err := cl.doPost(cl.client.R().EnableTrace().SetBody(l), "/dhcp/add_static_lease")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cl *client) DeleteDHCPStaticLeases(leases ...types.Lease) error {
|
||||
for _, l := range leases {
|
||||
cl.log.With("mac", l.HWAddr, "ip", l.IP, "hostname", l.Hostname).Info("Delete static dhcp lease")
|
||||
err := cl.doPost(cl.client.R().EnableTrace().SetBody(l), "/dhcp/remove_static_lease")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
func (cl *client) DeleteDHCPStaticLease(l model.DhcpStaticLease) error {
|
||||
cl.log.With("mac", l.Mac, "ip", l.Ip, "hostname", l.Hostname).Info("Delete static dhcp lease")
|
||||
err := cl.doPost(cl.client.R().EnableTrace().SetBody(l), "/dhcp/remove_static_lease")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (cl *client) SafeSearchConfig() (*model.SafeSearchConfig, error) {
|
||||
sss := &model.SafeSearchConfig{}
|
||||
err := cl.doGet(cl.client.R().EnableTrace().SetResult(sss), "/safesearch/status")
|
||||
return sss, err
|
||||
}
|
||||
|
||||
func (cl *client) SetSafeSearchConfig(settings *model.SafeSearchConfig) error {
|
||||
cl.log.With("enabled", *settings.Enabled).Info("Set safesearch settings")
|
||||
return cl.doPut(cl.client.R().EnableTrace().SetBody(settings), "/safesearch/settings")
|
||||
}
|
||||
|
||||
func (cl *client) ProfileInfo() (*model.ProfileInfo, error) {
|
||||
p := &model.ProfileInfo{}
|
||||
err := cl.doGet(cl.client.R().EnableTrace().SetResult(p), "/profile")
|
||||
return p, err
|
||||
}
|
||||
|
||||
func (cl *client) SetProfileInfo(profile *model.ProfileInfo) error {
|
||||
cl.log.With("language", profile.Language, "theme", profile.Theme).Info("Set profile")
|
||||
return cl.doPut(cl.client.R().EnableTrace().SetBody(profile), "/profile/update")
|
||||
}
|
||||
|
||||
@@ -9,7 +9,9 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/client"
|
||||
"github.com/bakito/adguardhome-sync/pkg/client/model"
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
"github.com/bakito/adguardhome-sync/pkg/utils"
|
||||
"github.com/google/uuid"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
@@ -33,19 +35,22 @@ var _ = Describe("Client", func() {
|
||||
|
||||
Context("Host", func() {
|
||||
It("should read the current host", func() {
|
||||
cl, _ := client.New(types.AdGuardInstance{URL: "https://foo.bar:3000"})
|
||||
inst := types.AdGuardInstance{URL: "https://foo.bar:3000"}
|
||||
err := inst.Init()
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
cl, _ := client.New(inst)
|
||||
host := cl.Host()
|
||||
Ω(host).Should(Equal("foo.bar:3000"))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Filtering", func() {
|
||||
It("should read filtering status", func() {
|
||||
Context("Filter", func() {
|
||||
It("should read filter status", func() {
|
||||
ts, cl = ClientGet("filtering-status.json", "/filtering/status")
|
||||
fs, err := cl.Filtering()
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(fs.Enabled).Should(BeTrue())
|
||||
Ω(fs.Filters).Should(HaveLen(2))
|
||||
Ω(*fs.Enabled).Should(BeTrue())
|
||||
Ω(*fs.Filters).Should(HaveLen(2))
|
||||
})
|
||||
It("should enable protection", func() {
|
||||
ts, cl = ClientPost("/filtering/config", `{"enabled":true,"interval":123}`)
|
||||
@@ -64,35 +69,32 @@ var _ = Describe("Client", func() {
|
||||
})
|
||||
It("should add Filters", func() {
|
||||
ts, cl = ClientPost("/filtering/add_url",
|
||||
`{"id":0,"enabled":false,"url":"foo","name":"","rules_count":0,"whitelist":true}`,
|
||||
`{"id":0,"enabled":false,"url":"bar","name":"","rules_count":0,"whitelist":true}`,
|
||||
`{"name":"","url":"foo","whitelist":true}`,
|
||||
`{"name":"","url":"bar","whitelist":true}`,
|
||||
)
|
||||
err := cl.AddFilters(true, types.Filter{URL: "foo"}, types.Filter{URL: "bar"})
|
||||
err := cl.AddFilter(true, model.Filter{Url: "foo"})
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
err = cl.AddFilter(true, model.Filter{Url: "bar"})
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should update Filters", func() {
|
||||
ts, cl = ClientPost("/filtering/set_url",
|
||||
`{"url":"foo","data":{"id":0,"enabled":false,"url":"foo","name":"","rules_count":0,"whitelist":true},"whitelist":true}`,
|
||||
`{"url":"bar","data":{"id":0,"enabled":false,"url":"bar","name":"","rules_count":0,"whitelist":true},"whitelist":true}`,
|
||||
`{"data":{"enabled":false,"name":"","url":"foo"},"url":"foo","whitelist":true}`,
|
||||
`{"data":{"enabled":false,"name":"","url":"bar"},"url":"bar","whitelist":true}`,
|
||||
)
|
||||
err := cl.UpdateFilters(true, types.Filter{URL: "foo"}, types.Filter{URL: "bar"})
|
||||
err := cl.UpdateFilter(true, model.Filter{Url: "foo"})
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
err = cl.UpdateFilter(true, model.Filter{Url: "bar"})
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should delete Filters", func() {
|
||||
ts, cl = ClientPost("/filtering/remove_url",
|
||||
`{"id":0,"enabled":false,"url":"foo","name":"","rules_count":0,"whitelist":true}`,
|
||||
`{"id":0,"enabled":false,"url":"bar","name":"","rules_count":0,"whitelist":true}`,
|
||||
`{"url":"foo","whitelist":true}`,
|
||||
`{"url":"bar","whitelist":true}`,
|
||||
)
|
||||
err := cl.DeleteFilters(true, types.Filter{URL: "foo"}, types.Filter{URL: "bar"})
|
||||
err := cl.DeleteFilter(true, model.Filter{Url: "foo"})
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
||||
Context("CustomRules", func() {
|
||||
It("should set SetCustomRules", func() {
|
||||
ts, cl = ClientPost("/filtering/set_rules", `foo
|
||||
bar`)
|
||||
err := cl.SetCustomRules([]string{"foo", "bar"})
|
||||
err = cl.DeleteFilter(true, model.Filter{Url: "bar"})
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
@@ -102,8 +104,8 @@ bar`)
|
||||
ts, cl = ClientGet("status.json", "/status")
|
||||
fs, err := cl.Status()
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(fs.DNSAddresses).Should(HaveLen(1))
|
||||
Ω(fs.DNSAddresses[0]).Should(Equal("192.168.1.2"))
|
||||
Ω(fs.DnsAddresses).Should(HaveLen(1))
|
||||
Ω(fs.DnsAddresses[0]).Should(Equal("192.168.1.2"))
|
||||
Ω(fs.Version).Should(Equal("v0.105.2"))
|
||||
})
|
||||
It("should return ErrSetupNeeded", func() {
|
||||
@@ -135,13 +137,19 @@ bar`)
|
||||
Ω(*rwl).Should(HaveLen(2))
|
||||
})
|
||||
It("should add RewriteList", func() {
|
||||
ts, cl = ClientPost("/rewrite/add", `{"domain":"foo","answer":"foo"}`, `{"domain":"bar","answer":"bar"}`)
|
||||
err := cl.AddRewriteEntries(types.RewriteEntry{Answer: "foo", Domain: "foo"}, types.RewriteEntry{Answer: "bar", Domain: "bar"})
|
||||
ts, cl = ClientPost("/rewrite/add", `{"answer":"foo","domain":"foo"}`, `{"answer":"bar","domain":"bar"}`)
|
||||
err := cl.AddRewriteEntries(
|
||||
model.RewriteEntry{Answer: utils.Ptr("foo"), Domain: utils.Ptr("foo")},
|
||||
model.RewriteEntry{Answer: utils.Ptr("bar"), Domain: utils.Ptr("bar")},
|
||||
)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should delete RewriteList", func() {
|
||||
ts, cl = ClientPost("/rewrite/delete", `{"domain":"foo","answer":"foo"}`, `{"domain":"bar","answer":"bar"}`)
|
||||
err := cl.DeleteRewriteEntries(types.RewriteEntry{Answer: "foo", Domain: "foo"}, types.RewriteEntry{Answer: "bar", Domain: "bar"})
|
||||
ts, cl = ClientPost("/rewrite/delete", `{"answer":"foo","domain":"foo"}`, `{"answer":"bar","domain":"bar"}`)
|
||||
err := cl.DeleteRewriteEntries(
|
||||
model.RewriteEntry{Answer: utils.Ptr("foo"), Domain: utils.Ptr("foo")},
|
||||
model.RewriteEntry{Answer: utils.Ptr("bar"), Domain: utils.Ptr("bar")},
|
||||
)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
@@ -165,21 +173,22 @@ bar`)
|
||||
})
|
||||
})
|
||||
|
||||
Context("SafeSearch", func() {
|
||||
Context("SafeSearchConfig", func() {
|
||||
It("should read safesearch status", func() {
|
||||
ts, cl = ClientGet("safesearch-status.json", "/safesearch/status")
|
||||
ss, err := cl.SafeSearch()
|
||||
ss, err := cl.SafeSearchConfig()
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(ss).Should(BeTrue())
|
||||
Ω(ss.Enabled).ShouldNot(BeNil())
|
||||
Ω(*ss.Enabled).Should(BeTrue())
|
||||
})
|
||||
It("should enable safesearch", func() {
|
||||
ts, cl = ClientPost("/safesearch/enable", "")
|
||||
err := cl.ToggleSafeSearch(true)
|
||||
ts, cl = ClientPut("/safesearch/settings", `{"enabled":true}`)
|
||||
err := cl.SetSafeSearchConfig(&model.SafeSearchConfig{Enabled: utils.Ptr(true)})
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should disable safesearch", func() {
|
||||
ts, cl = ClientPost("/safesearch/disable", "")
|
||||
err := cl.ToggleSafeSearch(false)
|
||||
ts, cl = ClientPut("/safesearch/settings", `{"enabled":false}`)
|
||||
err := cl.SetSafeSearchConfig(&model.SafeSearchConfig{Enabled: utils.Ptr(false)})
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
@@ -216,16 +225,39 @@ bar`)
|
||||
})
|
||||
})
|
||||
|
||||
Context("Services", func() {
|
||||
It("should read Services", func() {
|
||||
Context("BlockedServices", func() {
|
||||
It("should read BlockedServices", func() {
|
||||
ts, cl = ClientGet("blockedservices-list.json", "/blocked_services/list")
|
||||
s, err := cl.Services()
|
||||
s, err := cl.BlockedServices()
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(s).Should(HaveLen(2))
|
||||
Ω(*s).Should(HaveLen(2))
|
||||
})
|
||||
It("should set Services", func() {
|
||||
ts, cl = ClientPost("/blocked_services/set", `["foo","bar"]`)
|
||||
err := cl.SetServices([]string{"foo", "bar"})
|
||||
It("should set BlockedServices", func() {
|
||||
ts, cl = ClientPost("/blocked_services/set", `["bar","foo"]`)
|
||||
err := cl.SetBlockedServices(&model.BlockedServicesArray{"foo", "bar"})
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
||||
Context("BlockedServicesSchedule", func() {
|
||||
It("should read BlockedServicesSchedule", func() {
|
||||
ts, cl = ClientGet("blockedservicesschedule-get.json", "/blocked_services/get")
|
||||
s, err := cl.BlockedServicesSchedule()
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(*s.Ids).Should(HaveLen(3))
|
||||
})
|
||||
It("should set BlockedServicesSchedule", func() {
|
||||
ts, cl = ClientPost("/blocked_services/update",
|
||||
`{"ids":["bar","foo"],"schedule":{"mon":{"end":99,"start":1}}}`)
|
||||
err := cl.SetBlockedServicesSchedule(&model.BlockedServicesSchedule{
|
||||
Ids: utils.Ptr([]string{"foo", "bar"}),
|
||||
Schedule: &model.Schedule{
|
||||
Mon: &model.DayRange{
|
||||
Start: utils.Ptr(float32(1.0)),
|
||||
End: utils.Ptr(float32(99.0)),
|
||||
},
|
||||
},
|
||||
})
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
@@ -235,27 +267,27 @@ bar`)
|
||||
ts, cl = ClientGet("clients.json", "/clients")
|
||||
c, err := cl.Clients()
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(c.Clients).Should(HaveLen(2))
|
||||
Ω(*c.Clients).Should(HaveLen(2))
|
||||
})
|
||||
It("should add Clients", func() {
|
||||
ts, cl = ClientPost("/clients/add",
|
||||
`{"ids":["id"],"use_global_settings":false,"use_global_blocked_services":false,"name":"foo","filtering_enabled":false,"parental_enabled":false,"safesearch_enabled":false,"safebrowsing_enabled":false,"disallowed":false,"disallowed_rule":""}`,
|
||||
`{"ids":["id"],"name":"foo"}`,
|
||||
)
|
||||
err := cl.AddClients(types.Client{Name: "foo", Ids: []string{"id"}})
|
||||
err := cl.AddClient(&model.Client{Name: utils.Ptr("foo"), Ids: utils.Ptr([]string{"id"})})
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should update Clients", func() {
|
||||
ts, cl = ClientPost("/clients/update",
|
||||
`{"name":"foo","data":{"ids":["id"],"use_global_settings":false,"use_global_blocked_services":false,"name":"foo","filtering_enabled":false,"parental_enabled":false,"safesearch_enabled":false,"safebrowsing_enabled":false,"disallowed":false,"disallowed_rule":""}}`,
|
||||
`{"data":{"ids":["id"],"name":"foo"},"name":"foo"}`,
|
||||
)
|
||||
err := cl.UpdateClients(types.Client{Name: "foo", Ids: []string{"id"}})
|
||||
err := cl.UpdateClient(&model.Client{Name: utils.Ptr("foo"), Ids: utils.Ptr([]string{"id"})})
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should delete Clients", func() {
|
||||
ts, cl = ClientPost("/clients/delete",
|
||||
`{"ids":["id"],"use_global_settings":false,"use_global_blocked_services":false,"name":"foo","filtering_enabled":false,"parental_enabled":false,"safesearch_enabled":false,"safebrowsing_enabled":false,"disallowed":false,"disallowed_rule":""}`,
|
||||
`{"ids":["id"],"name":"foo"}`,
|
||||
)
|
||||
err := cl.DeleteClients(types.Client{Name: "foo", Ids: []string{"id"}})
|
||||
err := cl.DeleteClient(&model.Client{Name: utils.Ptr("foo"), Ids: utils.Ptr([]string{"id"})})
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
@@ -265,12 +297,16 @@ bar`)
|
||||
ts, cl = ClientGet("querylog_info.json", "/querylog_info")
|
||||
qlc, err := cl.QueryLogConfig()
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(qlc.Enabled).Should(BeTrue())
|
||||
Ω(qlc.Interval).Should(Equal(90.0))
|
||||
Ω(qlc.Enabled).ShouldNot(BeNil())
|
||||
Ω(*qlc.Enabled).Should(BeTrue())
|
||||
Ω(qlc.Interval).ShouldNot(BeNil())
|
||||
Ω(*qlc.Interval).Should(Equal(model.QueryLogConfigInterval(90)))
|
||||
})
|
||||
It("should set QueryLogConfig", func() {
|
||||
ts, cl = ClientPost("/querylog_config", `{"enabled":true,"interval":123,"anonymize_client_ip":true}`)
|
||||
err := cl.SetQueryLogConfig(true, 123, true)
|
||||
ts, cl = ClientPost("/querylog_config", `{"anonymize_client_ip":true,"enabled":true,"interval":123}`)
|
||||
|
||||
var interval model.QueryLogConfigInterval = 123
|
||||
err := cl.SetQueryLogConfig(&model.QueryLogConfig{AnonymizeClientIp: utils.Ptr(true), Interval: &interval, Enabled: utils.Ptr(true)})
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
@@ -279,11 +315,14 @@ bar`)
|
||||
ts, cl = ClientGet("stats_info.json", "/stats_info")
|
||||
sc, err := cl.StatsConfig()
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(sc.Interval).Should(Equal(1.0))
|
||||
Ω(sc.Interval).ShouldNot(BeNil())
|
||||
Ω(*sc.Interval).Should(Equal(model.StatsConfigInterval(1)))
|
||||
})
|
||||
It("should set StatsConfig", func() {
|
||||
ts, cl = ClientPost("/stats_config", `{"interval":123}`)
|
||||
err := cl.SetStatsConfig(123.0)
|
||||
|
||||
var interval model.StatsConfigInterval = 123
|
||||
err := cl.SetStatsConfig(&model.StatsConfig{Interval: &interval})
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
@@ -308,7 +347,8 @@ bar`)
|
||||
|
||||
Context("doPost", func() {
|
||||
It("should return an error on status code != 200", func() {
|
||||
err := cl.SetStatsConfig(123)
|
||||
var interval model.StatsConfigInterval = 123
|
||||
err := cl.SetStatsConfig(&model.StatsConfig{Interval: &interval})
|
||||
Ω(err).Should(HaveOccurred())
|
||||
Ω(err.Error()).Should(Equal("401 Unauthorized"))
|
||||
})
|
||||
@@ -344,3 +384,18 @@ func ClientPost(path string, content ...string) (*httptest.Server, client.Client
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
return ts, cl
|
||||
}
|
||||
|
||||
func ClientPut(path string, content ...string) (*httptest.Server, client.Client) {
|
||||
index := 0
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
Ω(r.URL.Path).Should(Equal(types.DefaultAPIPath + path))
|
||||
body, err := io.ReadAll(r.Body)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(body).Should(Equal([]byte(content[index])))
|
||||
index++
|
||||
}))
|
||||
|
||||
cl, err := client.New(types.AdGuardInstance{URL: ts.URL, Username: username, Password: password})
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
return ts, cl
|
||||
}
|
||||
|
||||
144
pkg/client/model/client/client.go
Normal file
144
pkg/client/model/client/client.go
Normal file
@@ -0,0 +1,144 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/client/model"
|
||||
"github.com/bakito/adguardhome-sync/pkg/log"
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var l = log.GetLogger("client")
|
||||
|
||||
// New create a new api client
|
||||
func New(config types.AdGuardInstance) (Client, error) {
|
||||
var apiURL string
|
||||
if config.APIPath == "" {
|
||||
apiURL = fmt.Sprintf("%s/control", config.URL)
|
||||
} else {
|
||||
apiURL = fmt.Sprintf("%s/%s", config.URL, config.APIPath)
|
||||
}
|
||||
u, err := url.Parse(apiURL)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
u.Path = path.Clean(u.Path)
|
||||
|
||||
httpClient := &http.Client{}
|
||||
if config.InsecureSkipVerify {
|
||||
// #nosec G402 has to be explicitly enabled
|
||||
httpClient.Transport = &http.Transport{
|
||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||
}
|
||||
}
|
||||
|
||||
aghClient, err := model.NewClient(u.String(), func(client *model.AdguardHomeClient) error {
|
||||
client.Client = httpClient
|
||||
client.RequestEditors = append(client.RequestEditors, func(ctx context.Context, req *http.Request) error {
|
||||
if config.Username != "" && config.Password != "" {
|
||||
req.Header.Add("Authorization", "Basic "+basicAuth(config.Username, config.Password))
|
||||
}
|
||||
return nil
|
||||
})
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &apiClient{
|
||||
host: u.Host,
|
||||
client: aghClient,
|
||||
log: l.With("host", u.Host),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func basicAuth(username, password string) string {
|
||||
auth := username + ":" + password
|
||||
return base64.StdEncoding.EncodeToString([]byte(auth))
|
||||
}
|
||||
|
||||
type apiClient struct {
|
||||
host string
|
||||
client *model.AdguardHomeClient
|
||||
log *zap.SugaredLogger
|
||||
}
|
||||
|
||||
func (a apiClient) Host(context.Context) string {
|
||||
return a.host
|
||||
}
|
||||
|
||||
func (a apiClient) GetServerStatus(ctx context.Context) (*model.ServerStatus, error) {
|
||||
sr, err := read(ctx, a.client.Status, model.ParseStatusResp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sr.JSON200, nil
|
||||
}
|
||||
|
||||
func (a apiClient) GetFilteringStatus(ctx context.Context) (*model.FilterStatus, error) {
|
||||
sr, err := read(ctx, a.client.FilteringStatus, model.ParseFilteringStatusResp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return sr.JSON200, nil
|
||||
}
|
||||
|
||||
func (a apiClient) SetFilteringConfig(ctx context.Context, config model.FilterConfig) error {
|
||||
return write(ctx, config, a.client.FilteringConfig)
|
||||
}
|
||||
|
||||
func write[B interface{}](
|
||||
ctx context.Context,
|
||||
body B,
|
||||
req func(ctx context.Context, body B, reqEditors ...model.RequestEditorFn) (*http.Response, error),
|
||||
) error {
|
||||
resp, err := req(ctx, body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return detailedError(resp)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func read[I interface{}](
|
||||
ctx context.Context,
|
||||
req func(ctx context.Context, reqEditors ...model.RequestEditorFn) (*http.Response, error),
|
||||
parse func(rsp *http.Response) (*I, error),
|
||||
) (*I, error) {
|
||||
resp, err := req(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return nil, detailedError(resp)
|
||||
}
|
||||
return parse(resp)
|
||||
}
|
||||
|
||||
func detailedError(resp *http.Response) error {
|
||||
e := resp.Status
|
||||
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(body) > 0 {
|
||||
e += fmt.Sprintf("(%s)", string(body))
|
||||
}
|
||||
return errors.New(e)
|
||||
}
|
||||
15
pkg/client/model/client/interface.go
Normal file
15
pkg/client/model/client/interface.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/client/model"
|
||||
)
|
||||
|
||||
type Client interface {
|
||||
Host(ctx context.Context) string
|
||||
GetServerStatus(ctx context.Context) (*model.ServerStatus, error)
|
||||
|
||||
GetFilteringStatus(ctx context.Context) (*model.FilterStatus, error)
|
||||
SetFilteringConfig(ctx context.Context, config model.FilterConfig) error
|
||||
}
|
||||
27
pkg/client/model/client/resty.go
Normal file
27
pkg/client/model/client/resty.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package client
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/client/model"
|
||||
"github.com/go-resty/resty/v2"
|
||||
)
|
||||
|
||||
var _ model.HttpRequestDoer = &adapter{}
|
||||
|
||||
func RestyAdapter(r *resty.Client) model.HttpRequestDoer {
|
||||
return &adapter{
|
||||
client: r,
|
||||
}
|
||||
}
|
||||
|
||||
type adapter struct {
|
||||
client *resty.Client
|
||||
}
|
||||
|
||||
func (a adapter) Do(req *http.Request) (*http.Response, error) {
|
||||
r, err := a.client.R().
|
||||
SetHeaderMultiValues(req.Header).
|
||||
Execute(req.Method, req.URL.String())
|
||||
return r.RawResponse, err
|
||||
}
|
||||
388
pkg/client/model/model-functions.go
Normal file
388
pkg/client/model/model-functions.go
Normal file
@@ -0,0 +1,388 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/utils"
|
||||
"github.com/jinzhu/copier"
|
||||
)
|
||||
|
||||
// Clone the config
|
||||
func (c *DhcpStatus) Clone() *DhcpStatus {
|
||||
clone := &DhcpStatus{}
|
||||
_ = copier.Copy(clone, c)
|
||||
return clone
|
||||
}
|
||||
|
||||
// Equals dhcp server config equal check
|
||||
func (c *DhcpStatus) Equals(o *DhcpStatus) bool {
|
||||
return utils.JsonEquals(c, o)
|
||||
}
|
||||
|
||||
func (c *DhcpStatus) HasConfig() bool {
|
||||
return (c.V4 != nil && c.V4.isValid()) || (c.V6 != nil && c.V6.isValid())
|
||||
}
|
||||
|
||||
func (j DhcpConfigV4) isValid() bool {
|
||||
return j.GatewayIp != nil && j.SubnetMask != nil && j.RangeStart != nil && j.RangeEnd != nil
|
||||
}
|
||||
|
||||
func (j DhcpConfigV6) isValid() bool {
|
||||
return j.RangeStart != nil
|
||||
}
|
||||
|
||||
type DhcpStaticLeases []DhcpStaticLease
|
||||
|
||||
// MergeDhcpStaticLeases the leases
|
||||
func MergeDhcpStaticLeases(l *[]DhcpStaticLease, other *[]DhcpStaticLease) (DhcpStaticLeases, DhcpStaticLeases) {
|
||||
var thisLeases []DhcpStaticLease
|
||||
var otherLeases []DhcpStaticLease
|
||||
|
||||
if l != nil {
|
||||
thisLeases = *l
|
||||
}
|
||||
if other != nil {
|
||||
otherLeases = *other
|
||||
}
|
||||
current := make(map[string]DhcpStaticLease)
|
||||
|
||||
var adds DhcpStaticLeases
|
||||
var removes DhcpStaticLeases
|
||||
for _, le := range thisLeases {
|
||||
current[le.Mac] = le
|
||||
}
|
||||
|
||||
for _, le := range otherLeases {
|
||||
if _, ok := current[le.Mac]; ok {
|
||||
delete(current, le.Mac)
|
||||
} else {
|
||||
adds = append(adds, le)
|
||||
}
|
||||
}
|
||||
|
||||
for _, rr := range current {
|
||||
removes = append(removes, rr)
|
||||
}
|
||||
|
||||
return adds, removes
|
||||
}
|
||||
|
||||
// Equals dns config equal check
|
||||
func (c *DNSConfig) Equals(o *DNSConfig) bool {
|
||||
cc := c.Clone()
|
||||
oo := o.Clone()
|
||||
cc.Sort()
|
||||
oo.Sort()
|
||||
|
||||
return utils.JsonEquals(cc, oo)
|
||||
}
|
||||
|
||||
func (c *DNSConfig) Clone() *DNSConfig {
|
||||
return utils.Clone(c, &DNSConfig{})
|
||||
}
|
||||
|
||||
// Sort sort dns config
|
||||
func (c *DNSConfig) Sort() {
|
||||
if c.UpstreamDns != nil {
|
||||
sort.Strings(*c.UpstreamDns)
|
||||
}
|
||||
|
||||
if c.UpstreamDns != nil {
|
||||
sort.Strings(*c.BootstrapDns)
|
||||
}
|
||||
|
||||
if c.UpstreamDns != nil {
|
||||
sort.Strings(*c.LocalPtrUpstreams)
|
||||
}
|
||||
}
|
||||
|
||||
// Equals access list equal check
|
||||
func (al *AccessList) Equals(o *AccessList) bool {
|
||||
return EqualsStringSlice(al.AllowedClients, o.AllowedClients, true) &&
|
||||
EqualsStringSlice(al.DisallowedClients, o.DisallowedClients, true) &&
|
||||
EqualsStringSlice(al.BlockedHosts, o.BlockedHosts, true)
|
||||
}
|
||||
|
||||
func EqualsStringSlice(a *[]string, b *[]string, sortIt bool) bool {
|
||||
if a == nil && b == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
if a == nil || b == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
aa := *a
|
||||
bb := *b
|
||||
if sortIt {
|
||||
sort.Strings(aa)
|
||||
sort.Strings(bb)
|
||||
}
|
||||
if len(aa) != len(bb) {
|
||||
return false
|
||||
}
|
||||
for i, v := range aa {
|
||||
if v != bb[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Sort clients
|
||||
func (cl *Client) Sort() {
|
||||
if cl.Ids != nil {
|
||||
sort.Strings(*cl.Ids)
|
||||
}
|
||||
if cl.Tags != nil {
|
||||
sort.Strings(*cl.Tags)
|
||||
}
|
||||
if cl.BlockedServices != nil {
|
||||
sort.Strings(*cl.BlockedServices)
|
||||
}
|
||||
if cl.Upstreams != nil {
|
||||
sort.Strings(*cl.Upstreams)
|
||||
}
|
||||
}
|
||||
|
||||
// Equals Clients equal check
|
||||
func (cl *Client) Equals(o *Client) bool {
|
||||
cl.Sort()
|
||||
o.Sort()
|
||||
|
||||
return utils.JsonEquals(cl, o)
|
||||
}
|
||||
|
||||
// Add ac client
|
||||
func (clients *Clients) Add(cl Client) {
|
||||
if clients.Clients == nil {
|
||||
clients.Clients = &ClientsArray{cl}
|
||||
} else {
|
||||
a := append(*clients.Clients, cl)
|
||||
clients.Clients = &a
|
||||
}
|
||||
}
|
||||
|
||||
// Merge merge Clients
|
||||
func (clients *Clients) Merge(other *Clients) ([]*Client, []*Client, []*Client) {
|
||||
current := make(map[string]*Client)
|
||||
if clients.Clients != nil {
|
||||
cc := *clients.Clients
|
||||
for i := range cc {
|
||||
client := cc[i]
|
||||
current[*client.Name] = &client
|
||||
}
|
||||
}
|
||||
|
||||
expected := make(map[string]*Client)
|
||||
if other.Clients != nil {
|
||||
oc := *other.Clients
|
||||
for i := range oc {
|
||||
client := oc[i]
|
||||
expected[*client.Name] = &client
|
||||
}
|
||||
}
|
||||
|
||||
var adds []*Client
|
||||
var removes []*Client
|
||||
var updates []*Client
|
||||
|
||||
for _, cl := range expected {
|
||||
if oc, ok := current[*cl.Name]; ok {
|
||||
if !cl.Equals(oc) {
|
||||
updates = append(updates, cl)
|
||||
}
|
||||
delete(current, *cl.Name)
|
||||
} else {
|
||||
adds = append(adds, cl)
|
||||
}
|
||||
}
|
||||
|
||||
for _, rr := range current {
|
||||
removes = append(removes, rr)
|
||||
}
|
||||
|
||||
return adds, updates, removes
|
||||
}
|
||||
|
||||
// Key RewriteEntry key
|
||||
func (re *RewriteEntry) Key() string {
|
||||
var d string
|
||||
var a string
|
||||
if re.Domain != nil {
|
||||
d = *re.Domain
|
||||
}
|
||||
if re.Answer != nil {
|
||||
a = *re.Answer
|
||||
}
|
||||
return fmt.Sprintf("%s#%s", d, a)
|
||||
}
|
||||
|
||||
// RewriteEntries list of RewriteEntry
|
||||
type RewriteEntries []RewriteEntry
|
||||
|
||||
// Merge RewriteEntries
|
||||
func (rwe *RewriteEntries) Merge(other *RewriteEntries) (RewriteEntries, RewriteEntries, RewriteEntries) {
|
||||
current := make(map[string]RewriteEntry)
|
||||
|
||||
var adds RewriteEntries
|
||||
var removes RewriteEntries
|
||||
var duplicates RewriteEntries
|
||||
processed := make(map[string]bool)
|
||||
for _, rr := range *rwe {
|
||||
if _, ok := processed[rr.Key()]; !ok {
|
||||
current[rr.Key()] = rr
|
||||
processed[rr.Key()] = true
|
||||
} else {
|
||||
// remove duplicate
|
||||
removes = append(removes, rr)
|
||||
}
|
||||
}
|
||||
|
||||
for _, rr := range *other {
|
||||
if _, ok := current[rr.Key()]; ok {
|
||||
delete(current, rr.Key())
|
||||
} else {
|
||||
if _, ok := processed[rr.Key()]; !ok {
|
||||
adds = append(adds, rr)
|
||||
processed[rr.Key()] = true
|
||||
} else {
|
||||
// skip duplicate
|
||||
duplicates = append(duplicates, rr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, rr := range current {
|
||||
removes = append(removes, rr)
|
||||
}
|
||||
|
||||
return adds, removes, duplicates
|
||||
}
|
||||
|
||||
func MergeFilters(this *[]Filter, other *[]Filter) ([]Filter, []Filter, []Filter) {
|
||||
if this == nil && other == nil {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
current := make(map[string]*Filter)
|
||||
|
||||
var adds []Filter
|
||||
var updates []Filter
|
||||
var removes []Filter
|
||||
if this != nil {
|
||||
for i := range *this {
|
||||
fi := (*this)[i]
|
||||
current[fi.Url] = &fi
|
||||
}
|
||||
}
|
||||
|
||||
if other != nil {
|
||||
for i := range *other {
|
||||
rr := (*other)[i]
|
||||
if c, ok := current[rr.Url]; ok {
|
||||
if !c.Equals(&rr) {
|
||||
updates = append(updates, rr)
|
||||
}
|
||||
delete(current, rr.Url)
|
||||
} else {
|
||||
adds = append(adds, rr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, rr := range current {
|
||||
removes = append(removes, *rr)
|
||||
}
|
||||
|
||||
return adds, updates, removes
|
||||
}
|
||||
|
||||
// Equals Filter equal check
|
||||
func (f *Filter) Equals(o *Filter) bool {
|
||||
return f.Enabled == o.Enabled && f.Url == o.Url && f.Name == o.Name
|
||||
}
|
||||
|
||||
// Equals QueryLogConfig equal check
|
||||
func (qlc *QueryLogConfig) Equals(o *QueryLogConfig) bool {
|
||||
return ptrEquals(qlc.Enabled, o.Enabled) &&
|
||||
ptrEquals(qlc.AnonymizeClientIp, o.AnonymizeClientIp) &&
|
||||
qlc.Interval.Equals(o.Interval)
|
||||
}
|
||||
|
||||
// Equals QueryLogConfigInterval equal check
|
||||
func (qlc *QueryLogConfigInterval) Equals(o *QueryLogConfigInterval) bool {
|
||||
return ptrEquals(qlc, o)
|
||||
}
|
||||
|
||||
func ptrEquals[T comparable](a *T, b *T) bool {
|
||||
if a == nil && b == nil {
|
||||
return true
|
||||
}
|
||||
var aa T
|
||||
if a != nil {
|
||||
aa = *a
|
||||
}
|
||||
var bb T
|
||||
if b != nil {
|
||||
bb = *b
|
||||
}
|
||||
|
||||
return aa == bb
|
||||
}
|
||||
|
||||
// EnableConfig API struct
|
||||
type EnableConfig struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
func (ssc *SafeSearchConfig) Equals(o *SafeSearchConfig) bool {
|
||||
return ptrEquals(ssc.Enabled, o.Enabled) &&
|
||||
ptrEquals(ssc.Bing, o.Bing) &&
|
||||
ptrEquals(ssc.Duckduckgo, o.Duckduckgo) &&
|
||||
ptrEquals(ssc.Google, o.Google) &&
|
||||
ptrEquals(ssc.Pixabay, o.Pixabay) &&
|
||||
ptrEquals(ssc.Yandex, o.Yandex) &&
|
||||
ptrEquals(ssc.Youtube, o.Youtube)
|
||||
}
|
||||
|
||||
func (pi *ProfileInfo) Equals(o *ProfileInfo) bool {
|
||||
return pi.Language == o.Language &&
|
||||
pi.Theme == o.Theme
|
||||
}
|
||||
|
||||
func (pi *ProfileInfo) ShouldSyncFor(o *ProfileInfo) *ProfileInfo {
|
||||
if pi.Equals(o) {
|
||||
return nil
|
||||
}
|
||||
merged := &ProfileInfo{Name: pi.Name, Language: pi.Language, Theme: pi.Theme}
|
||||
if o.Language != "" {
|
||||
merged.Language = o.Language
|
||||
}
|
||||
if o.Theme != "" {
|
||||
merged.Theme = o.Theme
|
||||
}
|
||||
if merged.Name == "" || merged.Language == "" || merged.Theme == "" || merged.Equals(pi) {
|
||||
return nil
|
||||
}
|
||||
return merged
|
||||
}
|
||||
|
||||
func (bss *BlockedServicesSchedule) Equals(o *BlockedServicesSchedule) bool {
|
||||
return utils.JsonEquals(bss, o)
|
||||
}
|
||||
|
||||
func (bss *BlockedServicesSchedule) ServicesString() string {
|
||||
return ArrayString(bss.Ids)
|
||||
}
|
||||
|
||||
func ArrayString(a *[]string) string {
|
||||
if a == nil {
|
||||
return "[]"
|
||||
}
|
||||
sorted := *a
|
||||
sort.Strings(sorted)
|
||||
return fmt.Sprintf("[%s]", strings.Join(sorted, ","))
|
||||
}
|
||||
10592
pkg/client/model/model_generated.go
Normal file
10592
pkg/client/model/model_generated.go
Normal file
File diff suppressed because it is too large
Load Diff
13
pkg/client/model/model_suite_test.go
Normal file
13
pkg/client/model/model_suite_test.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package model_test
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestTypes(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Model Suite")
|
||||
}
|
||||
430
pkg/client/model/model_test.go
Normal file
430
pkg/client/model/model_test.go
Normal file
@@ -0,0 +1,430 @@
|
||||
package model_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"os"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/client/model"
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
"github.com/bakito/adguardhome-sync/pkg/utils"
|
||||
"github.com/google/uuid"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Types", func() {
|
||||
var (
|
||||
url string
|
||||
apiPath string
|
||||
)
|
||||
BeforeEach(func() {
|
||||
url = "https://" + uuid.NewString()
|
||||
apiPath = "/" + uuid.NewString()
|
||||
})
|
||||
|
||||
Context("FilteringStatus", func() {
|
||||
It("should correctly parse json", func() {
|
||||
b, err := os.ReadFile("../../../testdata/filtering-status.json")
|
||||
fs := &model.FilterStatus{}
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
err = json.Unmarshal(b, fs)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
||||
Context("Filters", func() {
|
||||
Context("Merge", func() {
|
||||
var (
|
||||
originFilters []model.Filter
|
||||
replicaFilters []model.Filter
|
||||
)
|
||||
BeforeEach(func() {
|
||||
originFilters = []model.Filter{}
|
||||
replicaFilters = []model.Filter{}
|
||||
})
|
||||
|
||||
It("should add a missing filter", func() {
|
||||
originFilters = append(originFilters, model.Filter{Url: url})
|
||||
a, u, d := model.MergeFilters(&replicaFilters, &originFilters)
|
||||
Ω(a).Should(HaveLen(1))
|
||||
Ω(u).Should(BeEmpty())
|
||||
Ω(d).Should(BeEmpty())
|
||||
|
||||
Ω(a[0].Url).Should(Equal(url))
|
||||
})
|
||||
|
||||
It("should remove additional filter", func() {
|
||||
replicaFilters = append(replicaFilters, model.Filter{Url: url})
|
||||
a, u, d := model.MergeFilters(&replicaFilters, &originFilters)
|
||||
Ω(a).Should(BeEmpty())
|
||||
Ω(u).Should(BeEmpty())
|
||||
Ω(d).Should(HaveLen(1))
|
||||
|
||||
Ω(d[0].Url).Should(Equal(url))
|
||||
})
|
||||
|
||||
It("should update existing filter when enabled differs", func() {
|
||||
enabled := true
|
||||
originFilters = append(originFilters, model.Filter{Url: url, Enabled: enabled})
|
||||
replicaFilters = append(replicaFilters, model.Filter{Url: url, Enabled: !enabled})
|
||||
a, u, d := model.MergeFilters(&replicaFilters, &originFilters)
|
||||
Ω(a).Should(BeEmpty())
|
||||
Ω(u).Should(HaveLen(1))
|
||||
Ω(d).Should(BeEmpty())
|
||||
|
||||
Ω(u[0].Enabled).Should(Equal(enabled))
|
||||
})
|
||||
|
||||
It("should update existing filter when name differs", func() {
|
||||
name1 := uuid.NewString()
|
||||
name2 := uuid.NewString()
|
||||
originFilters = append(originFilters, model.Filter{Url: url, Name: name1})
|
||||
replicaFilters = append(replicaFilters, model.Filter{Url: url, Name: name2})
|
||||
a, u, d := model.MergeFilters(&replicaFilters, &originFilters)
|
||||
Ω(a).Should(BeEmpty())
|
||||
Ω(u).Should(HaveLen(1))
|
||||
Ω(d).Should(BeEmpty())
|
||||
|
||||
Ω(u[0].Name).Should(Equal(name1))
|
||||
})
|
||||
|
||||
It("should have no changes", func() {
|
||||
originFilters = append(originFilters, model.Filter{Url: url})
|
||||
replicaFilters = append(replicaFilters, model.Filter{Url: url})
|
||||
a, u, d := model.MergeFilters(&replicaFilters, &originFilters)
|
||||
Ω(a).Should(BeEmpty())
|
||||
Ω(u).Should(BeEmpty())
|
||||
Ω(d).Should(BeEmpty())
|
||||
})
|
||||
})
|
||||
})
|
||||
Context("AdGuardInstance", func() {
|
||||
It("should build a key with url and api apiPath", func() {
|
||||
i := &types.AdGuardInstance{URL: url, APIPath: apiPath}
|
||||
Ω(i.Key()).Should(Equal(url + "#" + apiPath))
|
||||
})
|
||||
})
|
||||
Context("RewriteEntry", func() {
|
||||
It("should build a key with url and api apiPath", func() {
|
||||
domain := uuid.NewString()
|
||||
answer := uuid.NewString()
|
||||
re := &model.RewriteEntry{Domain: utils.Ptr(domain), Answer: utils.Ptr(answer)}
|
||||
Ω(re.Key()).Should(Equal(domain + "#" + answer))
|
||||
})
|
||||
})
|
||||
Context("QueryLogConfig", func() {
|
||||
Context("Equal", func() {
|
||||
var (
|
||||
a *model.QueryLogConfig
|
||||
b *model.QueryLogConfig
|
||||
)
|
||||
BeforeEach(func() {
|
||||
a = &model.QueryLogConfig{}
|
||||
b = &model.QueryLogConfig{}
|
||||
})
|
||||
It("should be equal", func() {
|
||||
a.Enabled = utils.Ptr(true)
|
||||
var interval model.QueryLogConfigInterval = 1
|
||||
a.Interval = &interval
|
||||
a.AnonymizeClientIp = utils.Ptr(true)
|
||||
b.Enabled = utils.Ptr(true)
|
||||
b.Interval = &interval
|
||||
b.AnonymizeClientIp = utils.Ptr(true)
|
||||
Ω(a.Equals(b)).Should(BeTrue())
|
||||
})
|
||||
It("should not be equal when enabled differs", func() {
|
||||
a.Enabled = utils.Ptr(true)
|
||||
b.Enabled = utils.Ptr(false)
|
||||
Ω(a.Equals(b)).ShouldNot(BeTrue())
|
||||
})
|
||||
It("should not be equal when interval differs", func() {
|
||||
var interval1 model.QueryLogConfigInterval = 1
|
||||
var interval2 model.QueryLogConfigInterval = 2
|
||||
a.Interval = &interval1
|
||||
b.Interval = &interval2
|
||||
Ω(a.Equals(b)).ShouldNot(BeTrue())
|
||||
})
|
||||
It("should not be equal when anonymizeClientIP differs", func() {
|
||||
a.AnonymizeClientIp = utils.Ptr(true)
|
||||
b.AnonymizeClientIp = utils.Ptr(false)
|
||||
Ω(a.Equals(b)).ShouldNot(BeTrue())
|
||||
})
|
||||
})
|
||||
})
|
||||
Context("RewriteEntries", func() {
|
||||
Context("Merge", func() {
|
||||
var (
|
||||
originRE model.RewriteEntries
|
||||
replicaRE model.RewriteEntries
|
||||
domain string
|
||||
)
|
||||
BeforeEach(func() {
|
||||
originRE = model.RewriteEntries{}
|
||||
replicaRE = model.RewriteEntries{}
|
||||
domain = uuid.NewString()
|
||||
})
|
||||
|
||||
It("should add a missing rewrite entry", func() {
|
||||
originRE = append(originRE, model.RewriteEntry{Domain: utils.Ptr(domain)})
|
||||
a, r, d := replicaRE.Merge(&originRE)
|
||||
Ω(a).Should(HaveLen(1))
|
||||
Ω(r).Should(BeEmpty())
|
||||
Ω(d).Should(BeEmpty())
|
||||
|
||||
Ω(*a[0].Domain).Should(Equal(domain))
|
||||
})
|
||||
|
||||
It("should remove additional rewrite entry", func() {
|
||||
replicaRE = append(replicaRE, model.RewriteEntry{Domain: utils.Ptr(domain)})
|
||||
a, r, d := replicaRE.Merge(&originRE)
|
||||
Ω(a).Should(BeEmpty())
|
||||
Ω(r).Should(HaveLen(1))
|
||||
Ω(d).Should(BeEmpty())
|
||||
|
||||
Ω(*r[0].Domain).Should(Equal(domain))
|
||||
})
|
||||
|
||||
It("should have no changes", func() {
|
||||
originRE = append(originRE, model.RewriteEntry{Domain: utils.Ptr(domain)})
|
||||
replicaRE = append(replicaRE, model.RewriteEntry{Domain: utils.Ptr(domain)})
|
||||
a, r, d := replicaRE.Merge(&originRE)
|
||||
Ω(a).Should(BeEmpty())
|
||||
Ω(r).Should(BeEmpty())
|
||||
Ω(d).Should(BeEmpty())
|
||||
})
|
||||
|
||||
It("should remove target duplicate", func() {
|
||||
originRE = append(originRE, model.RewriteEntry{Domain: utils.Ptr(domain)})
|
||||
replicaRE = append(replicaRE, model.RewriteEntry{Domain: utils.Ptr(domain)})
|
||||
replicaRE = append(replicaRE, model.RewriteEntry{Domain: utils.Ptr(domain)})
|
||||
a, r, d := replicaRE.Merge(&originRE)
|
||||
Ω(a).Should(BeEmpty())
|
||||
Ω(r).Should(HaveLen(1))
|
||||
Ω(d).Should(BeEmpty())
|
||||
})
|
||||
|
||||
It("should remove target duplicate", func() {
|
||||
originRE = append(originRE, model.RewriteEntry{Domain: utils.Ptr(domain)})
|
||||
originRE = append(originRE, model.RewriteEntry{Domain: utils.Ptr(domain)})
|
||||
replicaRE = append(replicaRE, model.RewriteEntry{Domain: utils.Ptr(domain)})
|
||||
a, r, d := replicaRE.Merge(&originRE)
|
||||
Ω(a).Should(BeEmpty())
|
||||
Ω(r).Should(BeEmpty())
|
||||
Ω(d).Should(HaveLen(1))
|
||||
})
|
||||
})
|
||||
})
|
||||
Context("Config", func() {
|
||||
var cfg *types.Config
|
||||
BeforeEach(func() {
|
||||
cfg = &types.Config{}
|
||||
})
|
||||
Context("UniqueReplicas", func() {
|
||||
It("should be empty if noting defined", func() {
|
||||
r := cfg.UniqueReplicas()
|
||||
Ω(r).Should(BeEmpty())
|
||||
})
|
||||
It("should be empty if replica url is not set", func() {
|
||||
cfg.Replica = &types.AdGuardInstance{URL: ""}
|
||||
r := cfg.UniqueReplicas()
|
||||
Ω(r).Should(BeEmpty())
|
||||
})
|
||||
It("should be empty if replicas url is not set", func() {
|
||||
cfg.Replicas = []types.AdGuardInstance{{URL: ""}}
|
||||
r := cfg.UniqueReplicas()
|
||||
Ω(r).Should(BeEmpty())
|
||||
})
|
||||
It("should return only one replica if same url and apiPath", func() {
|
||||
cfg.Replica = &types.AdGuardInstance{URL: url, APIPath: apiPath}
|
||||
cfg.Replicas = []types.AdGuardInstance{{URL: url, APIPath: apiPath}, {URL: url, APIPath: apiPath}}
|
||||
r := cfg.UniqueReplicas()
|
||||
Ω(r).Should(HaveLen(1))
|
||||
})
|
||||
It("should return 3 one replicas if urls are different", func() {
|
||||
cfg.Replica = &types.AdGuardInstance{URL: url, APIPath: apiPath}
|
||||
cfg.Replicas = []types.AdGuardInstance{{URL: url + "1", APIPath: apiPath}, {URL: url, APIPath: apiPath + "1"}}
|
||||
r := cfg.UniqueReplicas()
|
||||
Ω(r).Should(HaveLen(3))
|
||||
})
|
||||
It("should set default api apiPath if not set", func() {
|
||||
cfg.Replica = &types.AdGuardInstance{URL: url}
|
||||
cfg.Replicas = []types.AdGuardInstance{{URL: url + "1"}}
|
||||
r := cfg.UniqueReplicas()
|
||||
Ω(r).Should(HaveLen(2))
|
||||
Ω(r[0].APIPath).Should(Equal(types.DefaultAPIPath))
|
||||
Ω(r[1].APIPath).Should(Equal(types.DefaultAPIPath))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Context("Clients", func() {
|
||||
Context("Merge", func() {
|
||||
var (
|
||||
originClients *model.Clients
|
||||
replicaClients model.Clients
|
||||
name string
|
||||
)
|
||||
BeforeEach(func() {
|
||||
originClients = &model.Clients{}
|
||||
replicaClients = model.Clients{}
|
||||
name = uuid.NewString()
|
||||
})
|
||||
|
||||
It("should add a missing client", func() {
|
||||
originClients.Add(model.Client{Name: utils.Ptr(name)})
|
||||
a, u, d := replicaClients.Merge(originClients)
|
||||
Ω(a).Should(HaveLen(1))
|
||||
Ω(u).Should(BeEmpty())
|
||||
Ω(d).Should(BeEmpty())
|
||||
|
||||
Ω(*a[0].Name).Should(Equal(name))
|
||||
})
|
||||
|
||||
It("should remove additional client", func() {
|
||||
replicaClients.Add(model.Client{Name: utils.Ptr(name)})
|
||||
a, u, d := replicaClients.Merge(originClients)
|
||||
Ω(a).Should(BeEmpty())
|
||||
Ω(u).Should(BeEmpty())
|
||||
Ω(d).Should(HaveLen(1))
|
||||
|
||||
Ω(*d[0].Name).Should(Equal(name))
|
||||
})
|
||||
|
||||
It("should update existing client when name differs", func() {
|
||||
disallowed := true
|
||||
originClients.Add(model.Client{Name: utils.Ptr(name), FilteringEnabled: utils.Ptr(disallowed)})
|
||||
replicaClients.Add(model.Client{Name: utils.Ptr(name), FilteringEnabled: utils.Ptr(!disallowed)})
|
||||
a, u, d := replicaClients.Merge(originClients)
|
||||
Ω(a).Should(BeEmpty())
|
||||
Ω(u).Should(HaveLen(1))
|
||||
Ω(d).Should(BeEmpty())
|
||||
|
||||
Ω(*u[0].FilteringEnabled).Should(Equal(disallowed))
|
||||
})
|
||||
})
|
||||
})
|
||||
Context("BlockedServices", func() {
|
||||
Context("Equals", func() {
|
||||
It("should be equal", func() {
|
||||
s1 := &model.BlockedServicesArray{"a", "b"}
|
||||
s2 := &model.BlockedServicesArray{"b", "a"}
|
||||
Ω(model.EqualsStringSlice(s1, s2, true)).Should(BeTrue())
|
||||
})
|
||||
It("should not be equal different values", func() {
|
||||
s1 := &model.BlockedServicesArray{"a", "b"}
|
||||
s2 := &model.BlockedServicesArray{"B", "a"}
|
||||
Ω(model.EqualsStringSlice(s1, s2, true)).ShouldNot(BeTrue())
|
||||
})
|
||||
It("should not be equal different length", func() {
|
||||
s1 := &model.BlockedServicesArray{"a", "b"}
|
||||
s2 := &model.BlockedServicesArray{"b", "a", "c"}
|
||||
Ω(model.EqualsStringSlice(s1, s2, true)).ShouldNot(BeTrue())
|
||||
})
|
||||
})
|
||||
})
|
||||
Context("DNSConfig", func() {
|
||||
Context("Equals", func() {
|
||||
It("should be equal", func() {
|
||||
dc1 := &model.DNSConfig{LocalPtrUpstreams: utils.Ptr([]string{"a"})}
|
||||
dc2 := &model.DNSConfig{LocalPtrUpstreams: utils.Ptr([]string{"a"})}
|
||||
Ω(dc1.Equals(dc2)).Should(BeTrue())
|
||||
})
|
||||
It("should not be equal", func() {
|
||||
dc1 := &model.DNSConfig{LocalPtrUpstreams: utils.Ptr([]string{"a"})}
|
||||
dc2 := &model.DNSConfig{LocalPtrUpstreams: utils.Ptr([]string{"b"})}
|
||||
Ω(dc1.Equals(dc2)).ShouldNot(BeTrue())
|
||||
})
|
||||
})
|
||||
})
|
||||
Context("DHCPServerConfig", func() {
|
||||
Context("Equals", func() {
|
||||
It("should be equal", func() {
|
||||
dc1 := &model.DhcpStatus{
|
||||
V4: &model.DhcpConfigV4{
|
||||
GatewayIp: utils.Ptr("1.2.3.4"),
|
||||
LeaseDuration: utils.Ptr(123),
|
||||
RangeStart: utils.Ptr("1.2.3.5"),
|
||||
RangeEnd: utils.Ptr("1.2.3.6"),
|
||||
SubnetMask: utils.Ptr("255.255.255.0"),
|
||||
},
|
||||
}
|
||||
dc2 := &model.DhcpStatus{
|
||||
V4: &model.DhcpConfigV4{
|
||||
GatewayIp: utils.Ptr("1.2.3.4"),
|
||||
LeaseDuration: utils.Ptr(123),
|
||||
RangeStart: utils.Ptr("1.2.3.5"),
|
||||
RangeEnd: utils.Ptr("1.2.3.6"),
|
||||
SubnetMask: utils.Ptr("255.255.255.0"),
|
||||
},
|
||||
}
|
||||
Ω(dc1.Equals(dc2)).Should(BeTrue())
|
||||
})
|
||||
It("should not be equal", func() {
|
||||
dc1 := &model.DhcpStatus{
|
||||
V4: &model.DhcpConfigV4{
|
||||
GatewayIp: utils.Ptr("1.2.3.3"),
|
||||
LeaseDuration: utils.Ptr(123),
|
||||
RangeStart: utils.Ptr("1.2.3.5"),
|
||||
RangeEnd: utils.Ptr("1.2.3.6"),
|
||||
SubnetMask: utils.Ptr("255.255.255.0"),
|
||||
},
|
||||
}
|
||||
dc2 := &model.DhcpStatus{
|
||||
V4: &model.DhcpConfigV4{
|
||||
GatewayIp: utils.Ptr("1.2.3.4"),
|
||||
LeaseDuration: utils.Ptr(123),
|
||||
RangeStart: utils.Ptr("1.2.3.5"),
|
||||
RangeEnd: utils.Ptr("1.2.3.6"),
|
||||
SubnetMask: utils.Ptr("255.255.255.0"),
|
||||
},
|
||||
}
|
||||
Ω(dc1.Equals(dc2)).ShouldNot(BeTrue())
|
||||
})
|
||||
})
|
||||
Context("Clone", func() {
|
||||
It("clone should be equal", func() {
|
||||
dc1 := &model.DhcpStatus{
|
||||
V4: &model.DhcpConfigV4{
|
||||
GatewayIp: utils.Ptr("1.2.3.4"),
|
||||
LeaseDuration: utils.Ptr(123),
|
||||
RangeStart: utils.Ptr("1.2.3.5"),
|
||||
RangeEnd: utils.Ptr("1.2.3.6"),
|
||||
SubnetMask: utils.Ptr("255.255.255.0"),
|
||||
},
|
||||
}
|
||||
Ω(dc1.Clone().Equals(dc1)).Should(BeTrue())
|
||||
})
|
||||
})
|
||||
Context("HasConfig", func() {
|
||||
It("should not have a config", func() {
|
||||
dc1 := &model.DhcpStatus{
|
||||
V4: &model.DhcpConfigV4{},
|
||||
V6: &model.DhcpConfigV6{},
|
||||
}
|
||||
Ω(dc1.HasConfig()).Should(BeFalse())
|
||||
})
|
||||
It("should not have a v4 config", func() {
|
||||
dc1 := &model.DhcpStatus{
|
||||
V4: &model.DhcpConfigV4{
|
||||
GatewayIp: utils.Ptr("1.2.3.4"),
|
||||
LeaseDuration: utils.Ptr(123),
|
||||
RangeStart: utils.Ptr("1.2.3.5"),
|
||||
RangeEnd: utils.Ptr("1.2.3.6"),
|
||||
SubnetMask: utils.Ptr("255.255.255.0"),
|
||||
},
|
||||
V6: &model.DhcpConfigV6{},
|
||||
}
|
||||
Ω(dc1.HasConfig()).Should(BeTrue())
|
||||
})
|
||||
It("should not have a v6 config", func() {
|
||||
dc1 := &model.DhcpStatus{
|
||||
V4: &model.DhcpConfigV4{},
|
||||
V6: &model.DhcpConfigV6{
|
||||
RangeStart: utils.Ptr("1.2.3.5"),
|
||||
},
|
||||
}
|
||||
Ω(dc1.HasConfig()).Should(BeTrue())
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -7,7 +7,7 @@ package client
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
types "github.com/bakito/adguardhome-sync/pkg/types"
|
||||
model "github.com/bakito/adguardhome-sync/pkg/client/model"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
@@ -35,10 +35,10 @@ func (m *MockClient) EXPECT() *MockClientMockRecorder {
|
||||
}
|
||||
|
||||
// AccessList mocks base method.
|
||||
func (m *MockClient) AccessList() (*types.AccessList, error) {
|
||||
func (m *MockClient) AccessList() (*model.AccessList, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AccessList")
|
||||
ret0, _ := ret[0].(*types.AccessList)
|
||||
ret0, _ := ret[0].(*model.AccessList)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
@@ -49,63 +49,50 @@ func (mr *MockClientMockRecorder) AccessList() *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AccessList", reflect.TypeOf((*MockClient)(nil).AccessList))
|
||||
}
|
||||
|
||||
// AddClients mocks base method.
|
||||
func (m *MockClient) AddClients(arg0 ...types.Client) error {
|
||||
// AddClient mocks base method.
|
||||
func (m *MockClient) AddClient(arg0 *model.Client) error {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{}
|
||||
for _, a := range arg0 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "AddClients", varargs...)
|
||||
ret := m.ctrl.Call(m, "AddClient", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// AddClients indicates an expected call of AddClients.
|
||||
func (mr *MockClientMockRecorder) AddClients(arg0 ...interface{}) *gomock.Call {
|
||||
// AddClient indicates an expected call of AddClient.
|
||||
func (mr *MockClientMockRecorder) AddClient(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddClients", reflect.TypeOf((*MockClient)(nil).AddClients), arg0...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddClient", reflect.TypeOf((*MockClient)(nil).AddClient), arg0)
|
||||
}
|
||||
|
||||
// AddDHCPStaticLeases mocks base method.
|
||||
func (m *MockClient) AddDHCPStaticLeases(arg0 ...types.Lease) error {
|
||||
// AddDHCPStaticLease mocks base method.
|
||||
func (m *MockClient) AddDHCPStaticLease(arg0 model.DhcpStaticLease) error {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{}
|
||||
for _, a := range arg0 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "AddDHCPStaticLeases", varargs...)
|
||||
ret := m.ctrl.Call(m, "AddDHCPStaticLease", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// AddDHCPStaticLeases indicates an expected call of AddDHCPStaticLeases.
|
||||
func (mr *MockClientMockRecorder) AddDHCPStaticLeases(arg0 ...interface{}) *gomock.Call {
|
||||
// AddDHCPStaticLease indicates an expected call of AddDHCPStaticLease.
|
||||
func (mr *MockClientMockRecorder) AddDHCPStaticLease(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddDHCPStaticLeases", reflect.TypeOf((*MockClient)(nil).AddDHCPStaticLeases), arg0...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddDHCPStaticLease", reflect.TypeOf((*MockClient)(nil).AddDHCPStaticLease), arg0)
|
||||
}
|
||||
|
||||
// AddFilters mocks base method.
|
||||
func (m *MockClient) AddFilters(arg0 bool, arg1 ...types.Filter) error {
|
||||
// AddFilter mocks base method.
|
||||
func (m *MockClient) AddFilter(arg0 bool, arg1 model.Filter) error {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{arg0}
|
||||
for _, a := range arg1 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "AddFilters", varargs...)
|
||||
ret := m.ctrl.Call(m, "AddFilter", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// AddFilters indicates an expected call of AddFilters.
|
||||
func (mr *MockClientMockRecorder) AddFilters(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
|
||||
// AddFilter indicates an expected call of AddFilter.
|
||||
func (mr *MockClientMockRecorder) AddFilter(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]interface{}{arg0}, arg1...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddFilters", reflect.TypeOf((*MockClient)(nil).AddFilters), varargs...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddFilter", reflect.TypeOf((*MockClient)(nil).AddFilter), arg0, arg1)
|
||||
}
|
||||
|
||||
// AddRewriteEntries mocks base method.
|
||||
func (m *MockClient) AddRewriteEntries(arg0 ...types.RewriteEntry) error {
|
||||
func (m *MockClient) AddRewriteEntries(arg0 ...model.RewriteEntry) error {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{}
|
||||
for _, a := range arg0 {
|
||||
@@ -122,11 +109,41 @@ func (mr *MockClientMockRecorder) AddRewriteEntries(arg0 ...interface{}) *gomock
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddRewriteEntries", reflect.TypeOf((*MockClient)(nil).AddRewriteEntries), arg0...)
|
||||
}
|
||||
|
||||
// BlockedServices mocks base method.
|
||||
func (m *MockClient) BlockedServices() (*[]string, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "BlockedServices")
|
||||
ret0, _ := ret[0].(*[]string)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// BlockedServices indicates an expected call of BlockedServices.
|
||||
func (mr *MockClientMockRecorder) BlockedServices() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockedServices", reflect.TypeOf((*MockClient)(nil).BlockedServices))
|
||||
}
|
||||
|
||||
// BlockedServicesSchedule mocks base method.
|
||||
func (m *MockClient) BlockedServicesSchedule() (*model.BlockedServicesSchedule, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "BlockedServicesSchedule")
|
||||
ret0, _ := ret[0].(*model.BlockedServicesSchedule)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// BlockedServicesSchedule indicates an expected call of BlockedServicesSchedule.
|
||||
func (mr *MockClientMockRecorder) BlockedServicesSchedule() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BlockedServicesSchedule", reflect.TypeOf((*MockClient)(nil).BlockedServicesSchedule))
|
||||
}
|
||||
|
||||
// Clients mocks base method.
|
||||
func (m *MockClient) Clients() (*types.Clients, error) {
|
||||
func (m *MockClient) Clients() (*model.Clients, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Clients")
|
||||
ret0, _ := ret[0].(*types.Clients)
|
||||
ret0, _ := ret[0].(*model.Clients)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
@@ -137,26 +154,11 @@ func (mr *MockClientMockRecorder) Clients() *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Clients", reflect.TypeOf((*MockClient)(nil).Clients))
|
||||
}
|
||||
|
||||
// DHCPServerConfig mocks base method.
|
||||
func (m *MockClient) DHCPServerConfig() (*types.DHCPServerConfig, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DHCPServerConfig")
|
||||
ret0, _ := ret[0].(*types.DHCPServerConfig)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// DHCPServerConfig indicates an expected call of DHCPServerConfig.
|
||||
func (mr *MockClientMockRecorder) DHCPServerConfig() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DHCPServerConfig", reflect.TypeOf((*MockClient)(nil).DHCPServerConfig))
|
||||
}
|
||||
|
||||
// DNSConfig mocks base method.
|
||||
func (m *MockClient) DNSConfig() (*types.DNSConfig, error) {
|
||||
func (m *MockClient) DNSConfig() (*model.DNSConfig, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DNSConfig")
|
||||
ret0, _ := ret[0].(*types.DNSConfig)
|
||||
ret0, _ := ret[0].(*model.DNSConfig)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
@@ -167,63 +169,50 @@ func (mr *MockClientMockRecorder) DNSConfig() *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DNSConfig", reflect.TypeOf((*MockClient)(nil).DNSConfig))
|
||||
}
|
||||
|
||||
// DeleteClients mocks base method.
|
||||
func (m *MockClient) DeleteClients(arg0 ...types.Client) error {
|
||||
// DeleteClient mocks base method.
|
||||
func (m *MockClient) DeleteClient(arg0 *model.Client) error {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{}
|
||||
for _, a := range arg0 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "DeleteClients", varargs...)
|
||||
ret := m.ctrl.Call(m, "DeleteClient", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// DeleteClients indicates an expected call of DeleteClients.
|
||||
func (mr *MockClientMockRecorder) DeleteClients(arg0 ...interface{}) *gomock.Call {
|
||||
// DeleteClient indicates an expected call of DeleteClient.
|
||||
func (mr *MockClientMockRecorder) DeleteClient(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteClients", reflect.TypeOf((*MockClient)(nil).DeleteClients), arg0...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteClient", reflect.TypeOf((*MockClient)(nil).DeleteClient), arg0)
|
||||
}
|
||||
|
||||
// DeleteDHCPStaticLeases mocks base method.
|
||||
func (m *MockClient) DeleteDHCPStaticLeases(arg0 ...types.Lease) error {
|
||||
// DeleteDHCPStaticLease mocks base method.
|
||||
func (m *MockClient) DeleteDHCPStaticLease(arg0 model.DhcpStaticLease) error {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{}
|
||||
for _, a := range arg0 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "DeleteDHCPStaticLeases", varargs...)
|
||||
ret := m.ctrl.Call(m, "DeleteDHCPStaticLease", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// DeleteDHCPStaticLeases indicates an expected call of DeleteDHCPStaticLeases.
|
||||
func (mr *MockClientMockRecorder) DeleteDHCPStaticLeases(arg0 ...interface{}) *gomock.Call {
|
||||
// DeleteDHCPStaticLease indicates an expected call of DeleteDHCPStaticLease.
|
||||
func (mr *MockClientMockRecorder) DeleteDHCPStaticLease(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteDHCPStaticLeases", reflect.TypeOf((*MockClient)(nil).DeleteDHCPStaticLeases), arg0...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteDHCPStaticLease", reflect.TypeOf((*MockClient)(nil).DeleteDHCPStaticLease), arg0)
|
||||
}
|
||||
|
||||
// DeleteFilters mocks base method.
|
||||
func (m *MockClient) DeleteFilters(arg0 bool, arg1 ...types.Filter) error {
|
||||
// DeleteFilter mocks base method.
|
||||
func (m *MockClient) DeleteFilter(arg0 bool, arg1 model.Filter) error {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{arg0}
|
||||
for _, a := range arg1 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "DeleteFilters", varargs...)
|
||||
ret := m.ctrl.Call(m, "DeleteFilter", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// DeleteFilters indicates an expected call of DeleteFilters.
|
||||
func (mr *MockClientMockRecorder) DeleteFilters(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
|
||||
// DeleteFilter indicates an expected call of DeleteFilter.
|
||||
func (mr *MockClientMockRecorder) DeleteFilter(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]interface{}{arg0}, arg1...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteFilters", reflect.TypeOf((*MockClient)(nil).DeleteFilters), varargs...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteFilter", reflect.TypeOf((*MockClient)(nil).DeleteFilter), arg0, arg1)
|
||||
}
|
||||
|
||||
// DeleteRewriteEntries mocks base method.
|
||||
func (m *MockClient) DeleteRewriteEntries(arg0 ...types.RewriteEntry) error {
|
||||
func (m *MockClient) DeleteRewriteEntries(arg0 ...model.RewriteEntry) error {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{}
|
||||
for _, a := range arg0 {
|
||||
@@ -240,11 +229,26 @@ func (mr *MockClientMockRecorder) DeleteRewriteEntries(arg0 ...interface{}) *gom
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRewriteEntries", reflect.TypeOf((*MockClient)(nil).DeleteRewriteEntries), arg0...)
|
||||
}
|
||||
|
||||
// DhcpConfig mocks base method.
|
||||
func (m *MockClient) DhcpConfig() (*model.DhcpStatus, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DhcpConfig")
|
||||
ret0, _ := ret[0].(*model.DhcpStatus)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// DhcpConfig indicates an expected call of DhcpConfig.
|
||||
func (mr *MockClientMockRecorder) DhcpConfig() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DhcpConfig", reflect.TypeOf((*MockClient)(nil).DhcpConfig))
|
||||
}
|
||||
|
||||
// Filtering mocks base method.
|
||||
func (m *MockClient) Filtering() (*types.FilteringStatus, error) {
|
||||
func (m *MockClient) Filtering() (*model.FilterStatus, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Filtering")
|
||||
ret0, _ := ret[0].(*types.FilteringStatus)
|
||||
ret0, _ := ret[0].(*model.FilterStatus)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
@@ -284,11 +288,26 @@ func (mr *MockClientMockRecorder) Parental() *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Parental", reflect.TypeOf((*MockClient)(nil).Parental))
|
||||
}
|
||||
|
||||
// ProfileInfo mocks base method.
|
||||
func (m *MockClient) ProfileInfo() (*model.ProfileInfo, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ProfileInfo")
|
||||
ret0, _ := ret[0].(*model.ProfileInfo)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ProfileInfo indicates an expected call of ProfileInfo.
|
||||
func (mr *MockClientMockRecorder) ProfileInfo() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ProfileInfo", reflect.TypeOf((*MockClient)(nil).ProfileInfo))
|
||||
}
|
||||
|
||||
// QueryLogConfig mocks base method.
|
||||
func (m *MockClient) QueryLogConfig() (*types.QueryLogConfig, error) {
|
||||
func (m *MockClient) QueryLogConfig() (*model.QueryLogConfig, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "QueryLogConfig")
|
||||
ret0, _ := ret[0].(*types.QueryLogConfig)
|
||||
ret0, _ := ret[0].(*model.QueryLogConfig)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
@@ -314,10 +333,10 @@ func (mr *MockClientMockRecorder) RefreshFilters(arg0 interface{}) *gomock.Call
|
||||
}
|
||||
|
||||
// RewriteList mocks base method.
|
||||
func (m *MockClient) RewriteList() (*types.RewriteEntries, error) {
|
||||
func (m *MockClient) RewriteList() (*model.RewriteEntries, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "RewriteList")
|
||||
ret0, _ := ret[0].(*types.RewriteEntries)
|
||||
ret0, _ := ret[0].(*model.RewriteEntries)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
@@ -343,38 +362,23 @@ func (mr *MockClientMockRecorder) SafeBrowsing() *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SafeBrowsing", reflect.TypeOf((*MockClient)(nil).SafeBrowsing))
|
||||
}
|
||||
|
||||
// SafeSearch mocks base method.
|
||||
func (m *MockClient) SafeSearch() (bool, error) {
|
||||
// SafeSearchConfig mocks base method.
|
||||
func (m *MockClient) SafeSearchConfig() (*model.SafeSearchConfig, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SafeSearch")
|
||||
ret0, _ := ret[0].(bool)
|
||||
ret := m.ctrl.Call(m, "SafeSearchConfig")
|
||||
ret0, _ := ret[0].(*model.SafeSearchConfig)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// SafeSearch indicates an expected call of SafeSearch.
|
||||
func (mr *MockClientMockRecorder) SafeSearch() *gomock.Call {
|
||||
// SafeSearchConfig indicates an expected call of SafeSearchConfig.
|
||||
func (mr *MockClientMockRecorder) SafeSearchConfig() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SafeSearch", reflect.TypeOf((*MockClient)(nil).SafeSearch))
|
||||
}
|
||||
|
||||
// Services mocks base method.
|
||||
func (m *MockClient) Services() (types.Services, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Services")
|
||||
ret0, _ := ret[0].(types.Services)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// Services indicates an expected call of Services.
|
||||
func (mr *MockClientMockRecorder) Services() *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Services", reflect.TypeOf((*MockClient)(nil).Services))
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SafeSearchConfig", reflect.TypeOf((*MockClient)(nil).SafeSearchConfig))
|
||||
}
|
||||
|
||||
// SetAccessList mocks base method.
|
||||
func (m *MockClient) SetAccessList(arg0 *types.AccessList) error {
|
||||
func (m *MockClient) SetAccessList(arg0 *model.AccessList) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SetAccessList", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
@@ -387,8 +391,36 @@ func (mr *MockClientMockRecorder) SetAccessList(arg0 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetAccessList", reflect.TypeOf((*MockClient)(nil).SetAccessList), arg0)
|
||||
}
|
||||
|
||||
// SetBlockedServices mocks base method.
|
||||
func (m *MockClient) SetBlockedServices(arg0 *[]string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SetBlockedServices", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SetBlockedServices indicates an expected call of SetBlockedServices.
|
||||
func (mr *MockClientMockRecorder) SetBlockedServices(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetBlockedServices", reflect.TypeOf((*MockClient)(nil).SetBlockedServices), arg0)
|
||||
}
|
||||
|
||||
// SetBlockedServicesSchedule mocks base method.
|
||||
func (m *MockClient) SetBlockedServicesSchedule(arg0 *model.BlockedServicesSchedule) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SetBlockedServicesSchedule", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SetBlockedServicesSchedule indicates an expected call of SetBlockedServicesSchedule.
|
||||
func (mr *MockClientMockRecorder) SetBlockedServicesSchedule(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetBlockedServicesSchedule", reflect.TypeOf((*MockClient)(nil).SetBlockedServicesSchedule), arg0)
|
||||
}
|
||||
|
||||
// SetCustomRules mocks base method.
|
||||
func (m *MockClient) SetCustomRules(arg0 types.UserRules) error {
|
||||
func (m *MockClient) SetCustomRules(arg0 *[]string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SetCustomRules", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
@@ -401,22 +433,8 @@ func (mr *MockClientMockRecorder) SetCustomRules(arg0 interface{}) *gomock.Call
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetCustomRules", reflect.TypeOf((*MockClient)(nil).SetCustomRules), arg0)
|
||||
}
|
||||
|
||||
// SetDHCPServerConfig mocks base method.
|
||||
func (m *MockClient) SetDHCPServerConfig(arg0 *types.DHCPServerConfig) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SetDHCPServerConfig", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SetDHCPServerConfig indicates an expected call of SetDHCPServerConfig.
|
||||
func (mr *MockClientMockRecorder) SetDHCPServerConfig(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDHCPServerConfig", reflect.TypeOf((*MockClient)(nil).SetDHCPServerConfig), arg0)
|
||||
}
|
||||
|
||||
// SetDNSConfig mocks base method.
|
||||
func (m *MockClient) SetDNSConfig(arg0 *types.DNSConfig) error {
|
||||
func (m *MockClient) SetDNSConfig(arg0 *model.DNSConfig) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SetDNSConfig", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
@@ -429,36 +447,64 @@ func (mr *MockClientMockRecorder) SetDNSConfig(arg0 interface{}) *gomock.Call {
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDNSConfig", reflect.TypeOf((*MockClient)(nil).SetDNSConfig), arg0)
|
||||
}
|
||||
|
||||
// SetQueryLogConfig mocks base method.
|
||||
func (m *MockClient) SetQueryLogConfig(arg0 bool, arg1 float64, arg2 bool) error {
|
||||
// SetDhcpConfig mocks base method.
|
||||
func (m *MockClient) SetDhcpConfig(arg0 *model.DhcpStatus) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SetQueryLogConfig", arg0, arg1, arg2)
|
||||
ret := m.ctrl.Call(m, "SetDhcpConfig", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SetDhcpConfig indicates an expected call of SetDhcpConfig.
|
||||
func (mr *MockClientMockRecorder) SetDhcpConfig(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDhcpConfig", reflect.TypeOf((*MockClient)(nil).SetDhcpConfig), arg0)
|
||||
}
|
||||
|
||||
// SetProfileInfo mocks base method.
|
||||
func (m *MockClient) SetProfileInfo(arg0 *model.ProfileInfo) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SetProfileInfo", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SetProfileInfo indicates an expected call of SetProfileInfo.
|
||||
func (mr *MockClientMockRecorder) SetProfileInfo(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetProfileInfo", reflect.TypeOf((*MockClient)(nil).SetProfileInfo), arg0)
|
||||
}
|
||||
|
||||
// SetQueryLogConfig mocks base method.
|
||||
func (m *MockClient) SetQueryLogConfig(arg0 *model.QueryLogConfig) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SetQueryLogConfig", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SetQueryLogConfig indicates an expected call of SetQueryLogConfig.
|
||||
func (mr *MockClientMockRecorder) SetQueryLogConfig(arg0, arg1, arg2 interface{}) *gomock.Call {
|
||||
func (mr *MockClientMockRecorder) SetQueryLogConfig(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetQueryLogConfig", reflect.TypeOf((*MockClient)(nil).SetQueryLogConfig), arg0, arg1, arg2)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetQueryLogConfig", reflect.TypeOf((*MockClient)(nil).SetQueryLogConfig), arg0)
|
||||
}
|
||||
|
||||
// SetServices mocks base method.
|
||||
func (m *MockClient) SetServices(arg0 types.Services) error {
|
||||
// SetSafeSearchConfig mocks base method.
|
||||
func (m *MockClient) SetSafeSearchConfig(arg0 *model.SafeSearchConfig) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SetServices", arg0)
|
||||
ret := m.ctrl.Call(m, "SetSafeSearchConfig", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SetServices indicates an expected call of SetServices.
|
||||
func (mr *MockClientMockRecorder) SetServices(arg0 interface{}) *gomock.Call {
|
||||
// SetSafeSearchConfig indicates an expected call of SetSafeSearchConfig.
|
||||
func (mr *MockClientMockRecorder) SetSafeSearchConfig(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetServices", reflect.TypeOf((*MockClient)(nil).SetServices), arg0)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetSafeSearchConfig", reflect.TypeOf((*MockClient)(nil).SetSafeSearchConfig), arg0)
|
||||
}
|
||||
|
||||
// SetStatsConfig mocks base method.
|
||||
func (m *MockClient) SetStatsConfig(arg0 float64) error {
|
||||
func (m *MockClient) SetStatsConfig(arg0 *model.StatsConfig) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SetStatsConfig", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
@@ -486,10 +532,10 @@ func (mr *MockClientMockRecorder) Setup() *gomock.Call {
|
||||
}
|
||||
|
||||
// StatsConfig mocks base method.
|
||||
func (m *MockClient) StatsConfig() (*types.IntervalConfig, error) {
|
||||
func (m *MockClient) StatsConfig() (*model.StatsConfig, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "StatsConfig")
|
||||
ret0, _ := ret[0].(*types.IntervalConfig)
|
||||
ret0, _ := ret[0].(*model.StatsConfig)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
@@ -501,10 +547,10 @@ func (mr *MockClientMockRecorder) StatsConfig() *gomock.Call {
|
||||
}
|
||||
|
||||
// Status mocks base method.
|
||||
func (m *MockClient) Status() (*types.Status, error) {
|
||||
func (m *MockClient) Status() (*model.ServerStatus, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Status")
|
||||
ret0, _ := ret[0].(*types.Status)
|
||||
ret0, _ := ret[0].(*model.ServerStatus)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
@@ -516,7 +562,7 @@ func (mr *MockClientMockRecorder) Status() *gomock.Call {
|
||||
}
|
||||
|
||||
// ToggleFiltering mocks base method.
|
||||
func (m *MockClient) ToggleFiltering(arg0 bool, arg1 float64) error {
|
||||
func (m *MockClient) ToggleFiltering(arg0 bool, arg1 int) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ToggleFiltering", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
@@ -571,53 +617,30 @@ func (mr *MockClientMockRecorder) ToggleSafeBrowsing(arg0 interface{}) *gomock.C
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ToggleSafeBrowsing", reflect.TypeOf((*MockClient)(nil).ToggleSafeBrowsing), arg0)
|
||||
}
|
||||
|
||||
// ToggleSafeSearch mocks base method.
|
||||
func (m *MockClient) ToggleSafeSearch(arg0 bool) error {
|
||||
// UpdateClient mocks base method.
|
||||
func (m *MockClient) UpdateClient(arg0 *model.Client) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ToggleSafeSearch", arg0)
|
||||
ret := m.ctrl.Call(m, "UpdateClient", arg0)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// ToggleSafeSearch indicates an expected call of ToggleSafeSearch.
|
||||
func (mr *MockClientMockRecorder) ToggleSafeSearch(arg0 interface{}) *gomock.Call {
|
||||
// UpdateClient indicates an expected call of UpdateClient.
|
||||
func (mr *MockClientMockRecorder) UpdateClient(arg0 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ToggleSafeSearch", reflect.TypeOf((*MockClient)(nil).ToggleSafeSearch), arg0)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateClient", reflect.TypeOf((*MockClient)(nil).UpdateClient), arg0)
|
||||
}
|
||||
|
||||
// UpdateClients mocks base method.
|
||||
func (m *MockClient) UpdateClients(arg0 ...types.Client) error {
|
||||
// UpdateFilter mocks base method.
|
||||
func (m *MockClient) UpdateFilter(arg0 bool, arg1 model.Filter) error {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{}
|
||||
for _, a := range arg0 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "UpdateClients", varargs...)
|
||||
ret := m.ctrl.Call(m, "UpdateFilter", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// UpdateClients indicates an expected call of UpdateClients.
|
||||
func (mr *MockClientMockRecorder) UpdateClients(arg0 ...interface{}) *gomock.Call {
|
||||
// UpdateFilter indicates an expected call of UpdateFilter.
|
||||
func (mr *MockClientMockRecorder) UpdateFilter(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateClients", reflect.TypeOf((*MockClient)(nil).UpdateClients), arg0...)
|
||||
}
|
||||
|
||||
// UpdateFilters mocks base method.
|
||||
func (m *MockClient) UpdateFilters(arg0 bool, arg1 ...types.Filter) error {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{arg0}
|
||||
for _, a := range arg1 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "UpdateFilters", varargs...)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// UpdateFilters indicates an expected call of UpdateFilters.
|
||||
func (mr *MockClientMockRecorder) UpdateFilters(arg0 interface{}, arg1 ...interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]interface{}{arg0}, arg1...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateFilters", reflect.TypeOf((*MockClient)(nil).UpdateFilters), varargs...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateFilter", reflect.TypeOf((*MockClient)(nil).UpdateFilter), arg0, arg1)
|
||||
}
|
||||
|
||||
283
pkg/sync/action-general.go
Normal file
283
pkg/sync/action-general.go
Normal file
@@ -0,0 +1,283 @@
|
||||
package sync
|
||||
|
||||
import (
|
||||
"github.com/bakito/adguardhome-sync/pkg/client"
|
||||
"github.com/bakito/adguardhome-sync/pkg/client/model"
|
||||
"github.com/bakito/adguardhome-sync/pkg/utils"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var (
|
||||
actionProfileInfo = func(ac *actionContext) error {
|
||||
if pro, err := ac.client.ProfileInfo(); err != nil {
|
||||
return err
|
||||
} else if merged := pro.ShouldSyncFor(ac.origin.profileInfo); merged != nil {
|
||||
return ac.client.SetProfileInfo(merged)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
actionProtection = func(ac *actionContext) error {
|
||||
if ac.origin.status.ProtectionEnabled != ac.replicaStatus.ProtectionEnabled {
|
||||
return ac.client.ToggleProtection(ac.origin.status.ProtectionEnabled)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
actionParental = func(ac *actionContext) error {
|
||||
if rp, err := ac.client.Parental(); err != nil {
|
||||
return err
|
||||
} else if ac.origin.parental != rp {
|
||||
return ac.client.ToggleParental(ac.origin.parental)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
actionSafeSearchConfig = func(ac *actionContext) error {
|
||||
if ssc, err := ac.client.SafeSearchConfig(); err != nil {
|
||||
return err
|
||||
} else if !ac.origin.safeSearch.Equals(ssc) {
|
||||
return ac.client.SetSafeSearchConfig(ac.origin.safeSearch)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
actionSafeBrowsing = func(ac *actionContext) error {
|
||||
if rs, err := ac.client.SafeBrowsing(); err != nil {
|
||||
return err
|
||||
} else if ac.origin.safeBrowsing != rs {
|
||||
if err = ac.client.ToggleSafeBrowsing(ac.origin.safeBrowsing); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
actionQueryLogConfig = func(ac *actionContext) error {
|
||||
qlc, err := ac.client.QueryLogConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !ac.origin.queryLogConfig.Equals(qlc) {
|
||||
return ac.client.SetQueryLogConfig(ac.origin.queryLogConfig)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
actionStatsConfig = func(ac *actionContext) error {
|
||||
sc, err := ac.client.StatsConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if ac.origin.statsConfig.Interval != sc.Interval {
|
||||
return ac.client.SetStatsConfig(ac.origin.statsConfig)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
actionDNSRewrites = func(ac *actionContext) error {
|
||||
replicaRewrites, err := ac.client.RewriteList()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a, r, d := replicaRewrites.Merge(ac.origin.rewrites)
|
||||
|
||||
if err = ac.client.DeleteRewriteEntries(r...); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = ac.client.AddRewriteEntries(a...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, dupl := range d {
|
||||
ac.rl.With("domain", dupl.Domain, "answer", dupl.Answer).Warn("Skipping duplicated rewrite from source")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
actionFilters = func(ac *actionContext) error {
|
||||
rf, err := ac.client.Filtering()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = syncFilterType(ac.rl, ac.origin.filters.Filters, rf.Filters, false, ac.client, ac.continueOnError); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = syncFilterType(ac.rl, ac.origin.filters.WhitelistFilters, rf.WhitelistFilters, true, ac.client, ac.continueOnError); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if utils.PtrToString(ac.origin.filters.UserRules) != utils.PtrToString(rf.UserRules) {
|
||||
return ac.client.SetCustomRules(ac.origin.filters.UserRules)
|
||||
}
|
||||
|
||||
if ac.origin.filters.Enabled != rf.Enabled || ac.origin.filters.Interval != rf.Interval {
|
||||
return ac.client.ToggleFiltering(*ac.origin.filters.Enabled, *ac.origin.filters.Interval)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
actionBlockedServices = func(ac *actionContext) error {
|
||||
rs, err := ac.client.BlockedServices()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !model.EqualsStringSlice(ac.origin.blockedServices, rs, true) {
|
||||
return ac.client.SetBlockedServices(ac.origin.blockedServices)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
actionBlockedServicesSchedule = func(ac *actionContext) error {
|
||||
rbss, err := ac.client.BlockedServicesSchedule()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !ac.origin.blockedServicesSchedule.Equals(rbss) {
|
||||
return ac.client.SetBlockedServicesSchedule(ac.origin.blockedServicesSchedule)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
actionClientSettings = func(ac *actionContext) error {
|
||||
rc, err := ac.client.Clients()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a, u, r := rc.Merge(ac.origin.clients)
|
||||
|
||||
for _, client := range r {
|
||||
if err := ac.client.DeleteClient(client); err != nil {
|
||||
ac.rl.With("client-name", client.Name, "error", err).Error("error deleting client setting")
|
||||
if !ac.continueOnError {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, client := range a {
|
||||
if err := ac.client.AddClient(client); err != nil {
|
||||
ac.rl.With("client-name", client.Name, "error", err).Error("error adding client setting")
|
||||
if !ac.continueOnError {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, client := range u {
|
||||
if err := ac.client.UpdateClient(client); err != nil {
|
||||
ac.rl.With("client-name", client.Name, "error", err).Error("error updating client setting")
|
||||
if !ac.continueOnError {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
actionDNSAccessLists = func(ac *actionContext) error {
|
||||
al, err := ac.client.AccessList()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !al.Equals(ac.origin.accessList) {
|
||||
return ac.client.SetAccessList(ac.origin.accessList)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
actionDNSServerConfig = func(ac *actionContext) error {
|
||||
dc, err := ac.client.DNSConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !dc.Equals(ac.origin.dnsConfig) {
|
||||
if err = ac.client.SetDNSConfig(ac.origin.dnsConfig); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
actionDHCPServerConfig = func(ac *actionContext) error {
|
||||
if ac.origin.dhcpServerConfig.HasConfig() {
|
||||
sc, err := ac.client.DhcpConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
origClone := ac.origin.dhcpServerConfig.Clone()
|
||||
if ac.replica.InterfaceName != "" {
|
||||
// overwrite interface name
|
||||
origClone.InterfaceName = utils.Ptr(ac.replica.InterfaceName)
|
||||
}
|
||||
if ac.replica.DHCPServerEnabled != nil {
|
||||
// overwrite dhcp enabled
|
||||
origClone.Enabled = ac.replica.DHCPServerEnabled
|
||||
}
|
||||
|
||||
if !sc.Equals(origClone) {
|
||||
return ac.client.SetDhcpConfig(origClone)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
actionDHCPStaticLeases = func(ac *actionContext) error {
|
||||
sc, err := ac.client.DhcpConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a, r := model.MergeDhcpStaticLeases(sc.StaticLeases, ac.origin.dhcpServerConfig.StaticLeases)
|
||||
|
||||
for _, lease := range r {
|
||||
if err := ac.client.DeleteDHCPStaticLease(lease); err != nil {
|
||||
ac.rl.With("hostname", lease.Hostname, "error", err).Error("error deleting dhcp static lease")
|
||||
if !ac.continueOnError {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, lease := range a {
|
||||
if err := ac.client.AddDHCPStaticLease(lease); err != nil {
|
||||
ac.rl.With("hostname", lease.Hostname, "error", err).Error("error adding dhcp static lease")
|
||||
if !ac.continueOnError {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
)
|
||||
|
||||
func syncFilterType(rl *zap.SugaredLogger, of *[]model.Filter, rFilters *[]model.Filter, whitelist bool, replica client.Client, continueOnError bool) error {
|
||||
fa, fu, fd := model.MergeFilters(rFilters, of)
|
||||
|
||||
for _, f := range fd {
|
||||
if err := replica.DeleteFilter(whitelist, f); err != nil {
|
||||
rl.With("filter", f.Name, "url", f.Url, "whitelist", whitelist, "error", err).Error("error deleting filter")
|
||||
if !continueOnError {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, f := range fa {
|
||||
if err := replica.AddFilter(whitelist, f); err != nil {
|
||||
rl.With("filter", f.Name, "url", f.Url, "whitelist", whitelist, "error", err).Error("error adding filter")
|
||||
if !continueOnError {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, f := range fu {
|
||||
if err := replica.UpdateFilter(whitelist, f); err != nil {
|
||||
rl.With("filter", f.Name, "url", f.Url, "whitelist", whitelist, "error", err).Error("error updating filter")
|
||||
if !continueOnError {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(fa) > 0 || len(fu) > 0 {
|
||||
if err := replica.RefreshFilters(whitelist); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
104
pkg/sync/action.go
Normal file
104
pkg/sync/action.go
Normal file
@@ -0,0 +1,104 @@
|
||||
package sync
|
||||
|
||||
import (
|
||||
"github.com/bakito/adguardhome-sync/pkg/client"
|
||||
"github.com/bakito/adguardhome-sync/pkg/client/model"
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
func setupActions(cfg *types.Config) (actions []syncAction) {
|
||||
if cfg.Features.GeneralSettings {
|
||||
actions = append(actions,
|
||||
action("profile info", actionProfileInfo),
|
||||
action("protection", actionProtection),
|
||||
action("parental", actionParental),
|
||||
action("safe search config", actionSafeSearchConfig),
|
||||
action("safe browsing", actionSafeBrowsing),
|
||||
)
|
||||
}
|
||||
if cfg.Features.QueryLogConfig {
|
||||
actions = append(actions,
|
||||
action("query log config", actionQueryLogConfig),
|
||||
)
|
||||
}
|
||||
if cfg.Features.StatsConfig {
|
||||
actions = append(actions,
|
||||
action("stats config", actionStatsConfig),
|
||||
)
|
||||
}
|
||||
if cfg.Features.DNS.Rewrites {
|
||||
actions = append(actions,
|
||||
action("DNS rewrites", actionDNSRewrites),
|
||||
)
|
||||
}
|
||||
if cfg.Features.Filters {
|
||||
actions = append(actions,
|
||||
action("actionFilters", actionFilters),
|
||||
)
|
||||
}
|
||||
if cfg.Features.Services {
|
||||
actions = append(actions,
|
||||
action("blocked services", actionBlockedServices),
|
||||
action("blocked services schedule", actionBlockedServicesSchedule),
|
||||
)
|
||||
}
|
||||
if cfg.Features.ClientSettings {
|
||||
actions = append(actions,
|
||||
action("client settings", actionClientSettings),
|
||||
)
|
||||
}
|
||||
if cfg.Features.DNS.AccessLists {
|
||||
actions = append(actions,
|
||||
action("DNS access lists", actionDNSAccessLists),
|
||||
)
|
||||
}
|
||||
|
||||
if cfg.Features.DNS.ServerConfig {
|
||||
actions = append(actions,
|
||||
action("DNS server config", actionDNSServerConfig),
|
||||
)
|
||||
}
|
||||
if cfg.Features.DHCP.ServerConfig {
|
||||
actions = append(actions,
|
||||
action("DHCP server config", actionDHCPServerConfig),
|
||||
)
|
||||
}
|
||||
if cfg.Features.DHCP.StaticLeases {
|
||||
actions = append(actions,
|
||||
action("DHCP static leases", actionDHCPStaticLeases),
|
||||
)
|
||||
}
|
||||
return actions
|
||||
}
|
||||
|
||||
type syncAction interface {
|
||||
sync(ac *actionContext) error
|
||||
name() string
|
||||
}
|
||||
|
||||
type actionContext struct {
|
||||
rl *zap.SugaredLogger
|
||||
origin *origin
|
||||
client client.Client
|
||||
replicaStatus *model.ServerStatus
|
||||
continueOnError bool
|
||||
replica types.AdGuardInstance
|
||||
}
|
||||
|
||||
type defaultAction struct {
|
||||
myName string
|
||||
doSync func(ac *actionContext) error
|
||||
}
|
||||
|
||||
func action(name string, f func(ac *actionContext) error) syncAction {
|
||||
return &defaultAction{myName: name, doSync: f}
|
||||
}
|
||||
|
||||
func (d *defaultAction) sync(ac *actionContext) error {
|
||||
return d.doSync(ac)
|
||||
}
|
||||
|
||||
func (d *defaultAction) name() string {
|
||||
return d.myName
|
||||
}
|
||||
@@ -33,9 +33,10 @@ func (w *worker) handleSync(c *gin.Context) {
|
||||
|
||||
func (w *worker) handleRoot(c *gin.Context) {
|
||||
c.HTML(http.StatusOK, "index.html", map[string]interface{}{
|
||||
"DarkMode": w.cfg.API.DarkMode,
|
||||
"Version": version.Version,
|
||||
"Build": version.Build,
|
||||
"DarkMode": w.cfg.API.DarkMode,
|
||||
"Version": version.Version,
|
||||
"Build": version.Build,
|
||||
"SyncStatus": w.status(),
|
||||
},
|
||||
)
|
||||
}
|
||||
@@ -48,6 +49,10 @@ func (w *worker) handleLogs(c *gin.Context) {
|
||||
c.Data(http.StatusOK, "text/plain", []byte(strings.Join(log.Logs(), "")))
|
||||
}
|
||||
|
||||
func (w *worker) handleStatus(c *gin.Context) {
|
||||
c.JSON(http.StatusOK, w.status())
|
||||
}
|
||||
|
||||
func (w *worker) listenAndServe() {
|
||||
l.With("port", w.cfg.API.Port).Info("Starting API server")
|
||||
|
||||
@@ -69,6 +74,7 @@ func (w *worker) listenAndServe() {
|
||||
r.SetHTMLTemplate(template.Must(template.New("index.html").Parse(string(index))))
|
||||
r.POST("/api/v1/sync", w.handleSync)
|
||||
r.GET("/api/v1/logs", w.handleLogs)
|
||||
r.GET("/api/v1/status", w.handleStatus)
|
||||
r.GET("/favicon.ico", w.handleFavicon)
|
||||
r.GET("/", w.handleRoot)
|
||||
|
||||
@@ -115,3 +121,16 @@ func (w *worker) listenAndServe() {
|
||||
|
||||
defer os.Exit(0)
|
||||
}
|
||||
|
||||
type syncStatus struct {
|
||||
Origin replicaStatus `json:"origin"`
|
||||
Replicas []replicaStatus `json:"replicas"`
|
||||
}
|
||||
|
||||
type replicaStatus struct {
|
||||
Host string `json:"host"`
|
||||
URL string `json:"url"`
|
||||
Status string `json:"status"`
|
||||
Error string `json:"error,omitempty"`
|
||||
ProtectionEnabled *bool `json:"protection_enabled"`
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
<html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>AdGuardHome sync</title>
|
||||
<script type="text/javascript" src="https://code.jquery.com/jquery-3.6.0.min.js">
|
||||
@@ -18,21 +18,35 @@
|
||||
$('#logs').html(data);
|
||||
}
|
||||
);
|
||||
$.get("api/v1/status", {}, function (status) {
|
||||
$('#origin').removeClass(function (index, className) {
|
||||
return (className.match(/(^|\s)btn-\S+/g) || []).join(' ');
|
||||
}).addClass("btn-" + status.origin.status).attr('title', status.origin.error);
|
||||
status.replicas.forEach(function (replica, i) {
|
||||
$('#replica_' + i).removeClass(function (index, className) {
|
||||
return (className.match(/(^|\s)btn-\S+/g) || []).join(' ');
|
||||
}).addClass("btn-" + replica.status).attr('title', replica.error);
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
$("#sync").click(function () {
|
||||
$.post("api/v1/sync", {}, function (data) {
|
||||
});
|
||||
$("#showLogs").click();
|
||||
});
|
||||
$("#showLogs").click()
|
||||
$("#showLogs").click();
|
||||
});
|
||||
</script>
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
</head>
|
||||
<body>
|
||||
<div class="container-fluid px-4">
|
||||
<div class="container-fluid px-4">
|
||||
<div class="row">
|
||||
<p class="h1">AdGuardHome sync
|
||||
<p class="h6">{{ .Version }} ({{ .Build }})</p></p>
|
||||
<p class="h1">
|
||||
AdGuardHome sync
|
||||
<p class="h6">{{ .Version }} ({{ .Build }})</p>
|
||||
</p>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
@@ -41,6 +55,18 @@
|
||||
<input class="btn btn-secondary" type="button" id="showLogs" value="Update Logs"/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col col-md-auto">
|
||||
<div class="float-right">
|
||||
<a href="{{ .SyncStatus.Origin.URL }}" target="_blank" class="btn btn-{{ .SyncStatus.Origin.Status }}"
|
||||
type="button" id="origin"
|
||||
{{ if .SyncStatus.Origin.Error }} title="{{ .SyncStatus.Origin.Error }}" {{ end }}>Origin {{ .SyncStatus.Origin.Host }}</a>
|
||||
{{ range $i, $r := .SyncStatus.Replicas }}
|
||||
<a href="{{ $r.URL }}" target="_blank" class="btn btn-{{ $r.Status }}"
|
||||
type="button" id="replica_{{ $i }}"
|
||||
{{ if $r.Error }} title="{{ $r.Error }}" {{ end }} >Replica {{ $r.Host }}</a>
|
||||
{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row mt-3">
|
||||
<div class="col-12">
|
||||
@@ -49,4 +75,4 @@
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
412
pkg/sync/sync.go
412
pkg/sync/sync.go
@@ -4,11 +4,14 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/client"
|
||||
"github.com/bakito/adguardhome-sync/pkg/client/model"
|
||||
"github.com/bakito/adguardhome-sync/pkg/log"
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
"github.com/bakito/adguardhome-sync/pkg/utils"
|
||||
"github.com/bakito/adguardhome-sync/pkg/versions"
|
||||
"github.com/bakito/adguardhome-sync/version"
|
||||
"github.com/robfig/cron/v3"
|
||||
@@ -87,6 +90,55 @@ type worker struct {
|
||||
running bool
|
||||
cron *cron.Cron
|
||||
createClient func(instance types.AdGuardInstance) (client.Client, error)
|
||||
actions []syncAction
|
||||
}
|
||||
|
||||
func (w *worker) status() *syncStatus {
|
||||
syncStatus := &syncStatus{
|
||||
Origin: w.getStatus(w.cfg.Origin),
|
||||
}
|
||||
|
||||
for _, replica := range w.cfg.Replicas {
|
||||
st := w.getStatus(replica)
|
||||
if w.running {
|
||||
st.Status = "info"
|
||||
}
|
||||
syncStatus.Replicas = append(syncStatus.Replicas, st)
|
||||
}
|
||||
|
||||
sort.Slice(syncStatus.Replicas, func(i, j int) bool {
|
||||
return syncStatus.Replicas[i].Host < syncStatus.Replicas[j].Host
|
||||
})
|
||||
|
||||
return syncStatus
|
||||
}
|
||||
|
||||
func (w *worker) getStatus(inst types.AdGuardInstance) (st replicaStatus) {
|
||||
st = replicaStatus{Host: inst.WebHost, URL: inst.WebURL}
|
||||
|
||||
oc, err := w.createClient(inst)
|
||||
if err != nil {
|
||||
l.With("error", err, "url", w.cfg.Origin.URL).Error("Error creating origin client")
|
||||
st.Status = "danger"
|
||||
st.Error = err.Error()
|
||||
return
|
||||
}
|
||||
sl := l.With("from", inst.WebHost)
|
||||
status, err := oc.Status()
|
||||
if err != nil {
|
||||
if errors.Is(err, client.ErrSetupNeeded) {
|
||||
st.Status = "warning"
|
||||
st.Error = err.Error()
|
||||
return
|
||||
}
|
||||
sl.With("error", err).Error("Error getting origin status")
|
||||
st.Status = "danger"
|
||||
st.Error = err.Error()
|
||||
return
|
||||
}
|
||||
st.Status = "success"
|
||||
st.ProtectionEnabled = utils.Ptr(status.ProtectionEnabled)
|
||||
return
|
||||
}
|
||||
|
||||
func (w *worker) sync() {
|
||||
@@ -119,12 +171,18 @@ func (w *worker) sync() {
|
||||
|
||||
sl.With("version", o.status.Version).Info("Connected to origin")
|
||||
|
||||
o.profileInfo, err = oc.ProfileInfo()
|
||||
if err != nil {
|
||||
sl.With("error", err).Error("Error getting profileInfo info")
|
||||
return
|
||||
}
|
||||
|
||||
o.parental, err = oc.Parental()
|
||||
if err != nil {
|
||||
sl.With("error", err).Error("Error getting parental status")
|
||||
return
|
||||
}
|
||||
o.safeSearch, err = oc.SafeSearch()
|
||||
o.safeSearch, err = oc.SafeSearchConfig()
|
||||
if err != nil {
|
||||
sl.With("error", err).Error("Error getting safe search status")
|
||||
return
|
||||
@@ -141,15 +199,21 @@ func (w *worker) sync() {
|
||||
return
|
||||
}
|
||||
|
||||
o.services, err = oc.Services()
|
||||
o.blockedServices, err = oc.BlockedServices()
|
||||
if err != nil {
|
||||
sl.With("error", err).Error("Error getting origin services")
|
||||
sl.With("error", err).Error("Error getting origin blocked services")
|
||||
return
|
||||
}
|
||||
|
||||
o.blockedServicesSchedule, err = oc.BlockedServicesSchedule()
|
||||
if err != nil {
|
||||
sl.With("error", err).Error("Error getting origin blocked services schedule")
|
||||
return
|
||||
}
|
||||
|
||||
o.filters, err = oc.Filtering()
|
||||
if err != nil {
|
||||
sl.With("error", err).Error("Error getting origin filters")
|
||||
sl.With("error", err).Error("Error getting origin actionFilters")
|
||||
return
|
||||
}
|
||||
o.clients, err = oc.Clients()
|
||||
@@ -181,13 +245,15 @@ func (w *worker) sync() {
|
||||
}
|
||||
|
||||
if w.cfg.Features.DHCP.ServerConfig || w.cfg.Features.DHCP.StaticLeases {
|
||||
o.dhcpServerConfig, err = oc.DHCPServerConfig()
|
||||
o.dhcpServerConfig, err = oc.DhcpConfig()
|
||||
if err != nil {
|
||||
sl.With("error", err).Error("Error getting dhcp server config")
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
w.actions = setupActions(w.cfg)
|
||||
|
||||
replicas := w.cfg.UniqueReplicas()
|
||||
for _, replica := range replicas {
|
||||
w.syncTo(sl, o, replica)
|
||||
@@ -204,78 +270,44 @@ func (w *worker) syncTo(l *zap.SugaredLogger, o *origin, replica types.AdGuardIn
|
||||
rl := l.With("to", rc.Host())
|
||||
rl.Info("Start sync")
|
||||
|
||||
rs, err := w.statusWithSetup(rl, replica, rc)
|
||||
replicaStatus, err := w.statusWithSetup(rl, replica, rc)
|
||||
if err != nil {
|
||||
rl.With("error", err).Error("Error getting replica status")
|
||||
return
|
||||
}
|
||||
|
||||
rl.With("version", rs.Version).Info("Connected to replica")
|
||||
rl.With("version", replicaStatus.Version).Info("Connected to replica")
|
||||
|
||||
if versions.IsNewerThan(versions.MinAgh, rs.Version) {
|
||||
rl.With("error", err, "version", rs.Version).Errorf("Replica AdGuard Home version must be >= %s", versions.MinAgh)
|
||||
if versions.IsNewerThan(versions.MinAgh, replicaStatus.Version) {
|
||||
rl.With("error", err, "version", replicaStatus.Version).Errorf("Replica AdGuard Home version must be >= %s", versions.MinAgh)
|
||||
return
|
||||
}
|
||||
|
||||
if versions.IsSame(rs.Version, versions.IncompatibleAPI) {
|
||||
rl.With("error", err, "version", rs.Version).Errorf("Replica AdGuard Home runs with an incompatible API - Please ugrade to version %s or newer", versions.FixedIncompatibleAPI)
|
||||
return
|
||||
if o.status.Version != replicaStatus.Version {
|
||||
rl.With("originVersion", o.status.Version, "replicaVersion", replicaStatus.Version).Warn("Versions do not match")
|
||||
}
|
||||
|
||||
if o.status.Version != rs.Version {
|
||||
rl.With("originVersion", o.status.Version, "replicaVersion", rs.Version).Warn("Versions do not match")
|
||||
ac := &actionContext{
|
||||
continueOnError: w.cfg.ContinueOnError,
|
||||
rl: rl,
|
||||
origin: o,
|
||||
replicaStatus: replicaStatus,
|
||||
client: rc,
|
||||
replica: replica,
|
||||
}
|
||||
|
||||
err = w.syncGeneralSettings(o, rs, rc)
|
||||
if err != nil {
|
||||
rl.With("error", err).Error("Error syncing general settings")
|
||||
return
|
||||
}
|
||||
|
||||
err = w.syncConfigs(o, rc)
|
||||
if err != nil {
|
||||
rl.With("error", err).Error("Error syncing configs")
|
||||
return
|
||||
}
|
||||
|
||||
err = w.syncRewrites(rl, o.rewrites, rc)
|
||||
if err != nil {
|
||||
rl.With("error", err).Error("Error syncing rewrites")
|
||||
return
|
||||
}
|
||||
err = w.syncFilters(o.filters, rc)
|
||||
if err != nil {
|
||||
rl.With("error", err).Error("Error syncing filters")
|
||||
return
|
||||
}
|
||||
|
||||
err = w.syncServices(o.services, rc)
|
||||
if err != nil {
|
||||
rl.With("error", err).Error("Error syncing services")
|
||||
return
|
||||
}
|
||||
|
||||
if err = w.syncClients(o.clients, rc); err != nil {
|
||||
rl.With("error", err).Error("Error syncing clients")
|
||||
return
|
||||
}
|
||||
|
||||
if err = w.syncDNS(o.accessList, o.dnsConfig, rc); err != nil {
|
||||
rl.With("error", err).Error("Error syncing dns")
|
||||
return
|
||||
}
|
||||
|
||||
if w.cfg.Features.DHCP.ServerConfig || w.cfg.Features.DHCP.StaticLeases {
|
||||
if err = w.syncDHCPServer(o.dhcpServerConfig, rc, replica); err != nil {
|
||||
rl.With("error", err).Error("Error syncing dhcp")
|
||||
return
|
||||
for _, action := range w.actions {
|
||||
if err := action.sync(ac); err != nil {
|
||||
rl.With("error", err).Errorf("Error syncing %s", action.name())
|
||||
if !w.cfg.ContinueOnError {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rl.Info("Sync done")
|
||||
}
|
||||
|
||||
func (w *worker) statusWithSetup(rl *zap.SugaredLogger, replica types.AdGuardInstance, rc client.Client) (*types.Status, error) {
|
||||
func (w *worker) statusWithSetup(rl *zap.SugaredLogger, replica types.AdGuardInstance, rc client.Client) (*model.ServerStatus, error) {
|
||||
rs, err := rc.Status()
|
||||
if err != nil {
|
||||
if replica.AutoSetup && errors.Is(err, client.ErrSetupNeeded) {
|
||||
@@ -290,252 +322,20 @@ func (w *worker) statusWithSetup(rl *zap.SugaredLogger, replica types.AdGuardIns
|
||||
return rs, err
|
||||
}
|
||||
|
||||
func (w *worker) syncServices(os types.Services, replica client.Client) error {
|
||||
if w.cfg.Features.Services {
|
||||
rs, err := replica.Services()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !os.Equals(rs) {
|
||||
if err := replica.SetServices(os); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *worker) syncFilters(of *types.FilteringStatus, replica client.Client) error {
|
||||
if w.cfg.Features.Filters {
|
||||
rf, err := replica.Filtering()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = w.syncFilterType(of.Filters, rf.Filters, false, replica); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = w.syncFilterType(of.WhitelistFilters, rf.WhitelistFilters, true, replica); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if of.UserRules.String() != rf.UserRules.String() {
|
||||
return replica.SetCustomRules(of.UserRules)
|
||||
}
|
||||
|
||||
if of.Enabled != rf.Enabled || of.Interval != rf.Interval {
|
||||
if err = replica.ToggleFiltering(of.Enabled, of.Interval); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *worker) syncFilterType(of types.Filters, rFilters types.Filters, whitelist bool, replica client.Client) error {
|
||||
fa, fu, fd := rFilters.Merge(of)
|
||||
|
||||
if err := replica.DeleteFilters(whitelist, fd...); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := replica.AddFilters(whitelist, fa...); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := replica.UpdateFilters(whitelist, fu...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(fa) > 0 || len(fu) > 0 {
|
||||
if err := replica.RefreshFilters(whitelist); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *worker) syncRewrites(rl *zap.SugaredLogger, or *types.RewriteEntries, replica client.Client) error {
|
||||
if w.cfg.Features.DNS.Rewrites {
|
||||
replicaRewrites, err := replica.RewriteList()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a, r, d := replicaRewrites.Merge(or)
|
||||
|
||||
if err = replica.DeleteRewriteEntries(r...); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = replica.AddRewriteEntries(a...); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, dupl := range d {
|
||||
rl.With("domain", dupl.Domain, "answer", dupl.Answer).Warn("Skipping duplicated rewrite from source")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *worker) syncClients(oc *types.Clients, replica client.Client) error {
|
||||
if w.cfg.Features.ClientSettings {
|
||||
rc, err := replica.Clients()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
a, u, r := rc.Merge(oc)
|
||||
|
||||
if err = replica.DeleteClients(r...); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = replica.AddClients(a...); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = replica.UpdateClients(u...); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *worker) syncGeneralSettings(o *origin, rs *types.Status, replica client.Client) error {
|
||||
if w.cfg.Features.GeneralSettings {
|
||||
if o.status.ProtectionEnabled != rs.ProtectionEnabled {
|
||||
if err := replica.ToggleProtection(o.status.ProtectionEnabled); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if rp, err := replica.Parental(); err != nil {
|
||||
return err
|
||||
} else if o.parental != rp {
|
||||
if err = replica.ToggleParental(o.parental); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if rs, err := replica.SafeSearch(); err != nil {
|
||||
return err
|
||||
} else if o.safeSearch != rs {
|
||||
if err = replica.ToggleSafeSearch(o.safeSearch); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if rs, err := replica.SafeBrowsing(); err != nil {
|
||||
return err
|
||||
} else if o.safeBrowsing != rs {
|
||||
if err = replica.ToggleSafeBrowsing(o.safeBrowsing); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *worker) syncConfigs(o *origin, rc client.Client) error {
|
||||
if w.cfg.Features.QueryLogConfig {
|
||||
qlc, err := rc.QueryLogConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !o.queryLogConfig.Equals(qlc) {
|
||||
if err = rc.SetQueryLogConfig(o.queryLogConfig.Enabled, o.queryLogConfig.Interval, o.queryLogConfig.AnonymizeClientIP); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if w.cfg.Features.StatsConfig {
|
||||
sc, err := rc.StatsConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if o.statsConfig.Interval != sc.Interval {
|
||||
if err = rc.SetStatsConfig(o.statsConfig.Interval); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *worker) syncDNS(oal *types.AccessList, odc *types.DNSConfig, rc client.Client) error {
|
||||
if w.cfg.Features.DNS.AccessLists {
|
||||
al, err := rc.AccessList()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !al.Equals(oal) {
|
||||
if err = rc.SetAccessList(oal); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
if w.cfg.Features.DNS.ServerConfig {
|
||||
dc, err := rc.DNSConfig()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !dc.Equals(odc) {
|
||||
if err = rc.SetDNSConfig(odc); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *worker) syncDHCPServer(osc *types.DHCPServerConfig, rc client.Client, replica types.AdGuardInstance) error {
|
||||
if !w.cfg.Features.DHCP.ServerConfig && !w.cfg.Features.DHCP.StaticLeases {
|
||||
return nil
|
||||
}
|
||||
sc, err := rc.DHCPServerConfig()
|
||||
if w.cfg.Features.DHCP.ServerConfig && osc.HasConfig() {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
origClone := osc.Clone()
|
||||
if replica.InterfaceName != "" {
|
||||
// overwrite interface name
|
||||
origClone.InterfaceName = replica.InterfaceName
|
||||
}
|
||||
if replica.DHCPServerEnabled != nil {
|
||||
// overwrite dhcp enabled
|
||||
origClone.Enabled = *replica.DHCPServerEnabled
|
||||
}
|
||||
|
||||
if !sc.Equals(origClone) {
|
||||
if err = rc.SetDHCPServerConfig(origClone); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if w.cfg.Features.DHCP.StaticLeases {
|
||||
a, r := sc.StaticLeases.Merge(osc.StaticLeases)
|
||||
|
||||
if err = rc.DeleteDHCPStaticLeases(r...); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = rc.AddDHCPStaticLeases(a...); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type origin struct {
|
||||
status *types.Status
|
||||
rewrites *types.RewriteEntries
|
||||
services types.Services
|
||||
filters *types.FilteringStatus
|
||||
clients *types.Clients
|
||||
queryLogConfig *types.QueryLogConfig
|
||||
statsConfig *types.IntervalConfig
|
||||
accessList *types.AccessList
|
||||
dnsConfig *types.DNSConfig
|
||||
dhcpServerConfig *types.DHCPServerConfig
|
||||
parental bool
|
||||
safeSearch bool
|
||||
safeBrowsing bool
|
||||
status *model.ServerStatus
|
||||
rewrites *model.RewriteEntries
|
||||
blockedServices *model.BlockedServicesArray
|
||||
blockedServicesSchedule *model.BlockedServicesSchedule
|
||||
filters *model.FilterStatus
|
||||
clients *model.Clients
|
||||
queryLogConfig *model.QueryLogConfig
|
||||
statsConfig *model.StatsConfig
|
||||
accessList *model.AccessList
|
||||
dnsConfig *model.DNSConfig
|
||||
dhcpServerConfig *model.DhcpStatus
|
||||
parental bool
|
||||
safeSearch *model.SafeSearchConfig
|
||||
profileInfo *model.ProfileInfo
|
||||
safeBrowsing bool
|
||||
}
|
||||
|
||||
@@ -2,11 +2,12 @@ package sync
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/client"
|
||||
"github.com/bakito/adguardhome-sync/pkg/client/model"
|
||||
clientmock "github.com/bakito/adguardhome-sync/pkg/mocks/client"
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
"github.com/bakito/adguardhome-sync/pkg/utils"
|
||||
"github.com/bakito/adguardhome-sync/pkg/versions"
|
||||
gm "github.com/golang/mock/gomock"
|
||||
"github.com/google/uuid"
|
||||
@@ -14,14 +15,13 @@ import (
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var boolTrue = true
|
||||
|
||||
var _ = Describe("Sync", func() {
|
||||
var (
|
||||
mockCtrl *gm.Controller
|
||||
cl *clientmock.MockClient
|
||||
w *worker
|
||||
te error
|
||||
ac *actionContext
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
@@ -49,251 +49,290 @@ var _ = Describe("Sync", func() {
|
||||
StatsConfig: true,
|
||||
QueryLogConfig: true,
|
||||
},
|
||||
Replicas: []types.AdGuardInstance{
|
||||
{},
|
||||
},
|
||||
},
|
||||
}
|
||||
te = errors.New(uuid.NewString())
|
||||
|
||||
ac = &actionContext{
|
||||
continueOnError: false,
|
||||
rl: l,
|
||||
origin: &origin{
|
||||
profileInfo: &model.ProfileInfo{
|
||||
Name: "origin",
|
||||
Language: "en",
|
||||
Theme: "auto",
|
||||
},
|
||||
status: &model.ServerStatus{},
|
||||
safeSearch: &model.SafeSearchConfig{},
|
||||
queryLogConfig: &model.QueryLogConfig{},
|
||||
statsConfig: &model.StatsConfig{},
|
||||
},
|
||||
replicaStatus: &model.ServerStatus{},
|
||||
client: cl,
|
||||
replica: w.cfg.Replicas[0],
|
||||
}
|
||||
})
|
||||
AfterEach(func() {
|
||||
defer mockCtrl.Finish()
|
||||
})
|
||||
|
||||
Context("worker", func() {
|
||||
Context("syncRewrites", func() {
|
||||
Context("actionDNSRewrites", func() {
|
||||
var (
|
||||
domain string
|
||||
answer string
|
||||
reO types.RewriteEntries
|
||||
reR types.RewriteEntries
|
||||
reO model.RewriteEntries
|
||||
reR model.RewriteEntries
|
||||
)
|
||||
|
||||
BeforeEach(func() {
|
||||
domain = uuid.NewString()
|
||||
answer = uuid.NewString()
|
||||
reO = []types.RewriteEntry{{Domain: domain, Answer: answer}}
|
||||
reR = []types.RewriteEntry{{Domain: domain, Answer: answer}}
|
||||
reO = model.RewriteEntries{{Domain: utils.Ptr(domain), Answer: utils.Ptr(answer)}}
|
||||
reR = model.RewriteEntries{{Domain: utils.Ptr(domain), Answer: utils.Ptr(answer)}}
|
||||
})
|
||||
It("should have no changes (empty slices)", func() {
|
||||
ac.origin.rewrites = &reO
|
||||
cl.EXPECT().RewriteList().Return(&reR, nil)
|
||||
cl.EXPECT().AddRewriteEntries()
|
||||
cl.EXPECT().DeleteRewriteEntries()
|
||||
err := w.syncRewrites(l, &reO, cl)
|
||||
err := actionDNSRewrites(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should add one rewrite entry", func() {
|
||||
reR = []types.RewriteEntry{}
|
||||
reR = []model.RewriteEntry{}
|
||||
ac.origin.rewrites = &reO
|
||||
cl.EXPECT().RewriteList().Return(&reR, nil)
|
||||
cl.EXPECT().AddRewriteEntries(reO[0])
|
||||
cl.EXPECT().DeleteRewriteEntries()
|
||||
err := w.syncRewrites(l, &reO, cl)
|
||||
err := actionDNSRewrites(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should remove one rewrite entry", func() {
|
||||
reO = []types.RewriteEntry{}
|
||||
reO = []model.RewriteEntry{}
|
||||
ac.origin.rewrites = &reO
|
||||
cl.EXPECT().RewriteList().Return(&reR, nil)
|
||||
cl.EXPECT().AddRewriteEntries()
|
||||
cl.EXPECT().DeleteRewriteEntries(reR[0])
|
||||
err := w.syncRewrites(l, &reO, cl)
|
||||
err := actionDNSRewrites(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should remove one rewrite entry", func() {
|
||||
reO = []types.RewriteEntry{}
|
||||
reO = []model.RewriteEntry{}
|
||||
ac.origin.rewrites = &reO
|
||||
cl.EXPECT().RewriteList().Return(&reR, nil)
|
||||
cl.EXPECT().AddRewriteEntries()
|
||||
cl.EXPECT().DeleteRewriteEntries(reR[0])
|
||||
err := w.syncRewrites(l, &reO, cl)
|
||||
err := actionDNSRewrites(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should return error when error on RewriteList()", func() {
|
||||
ac.origin.rewrites = &reO
|
||||
cl.EXPECT().RewriteList().Return(nil, te)
|
||||
err := w.syncRewrites(l, &reO, cl)
|
||||
err := actionDNSRewrites(ac)
|
||||
Ω(err).Should(HaveOccurred())
|
||||
})
|
||||
It("should return error when error on AddRewriteEntries()", func() {
|
||||
ac.origin.rewrites = &reO
|
||||
cl.EXPECT().RewriteList().Return(&reR, nil)
|
||||
cl.EXPECT().DeleteRewriteEntries()
|
||||
cl.EXPECT().AddRewriteEntries().Return(te)
|
||||
err := w.syncRewrites(l, &reO, cl)
|
||||
err := actionDNSRewrites(ac)
|
||||
Ω(err).Should(HaveOccurred())
|
||||
})
|
||||
It("should return error when error on DeleteRewriteEntries()", func() {
|
||||
ac.origin.rewrites = &reO
|
||||
cl.EXPECT().RewriteList().Return(&reR, nil)
|
||||
cl.EXPECT().DeleteRewriteEntries().Return(te)
|
||||
err := w.syncRewrites(l, &reO, cl)
|
||||
err := actionDNSRewrites(ac)
|
||||
Ω(err).Should(HaveOccurred())
|
||||
})
|
||||
})
|
||||
Context("syncClients", func() {
|
||||
Context("actionClientSettings", func() {
|
||||
var (
|
||||
clO *types.Clients
|
||||
clR *types.Clients
|
||||
clR *model.Clients
|
||||
name string
|
||||
)
|
||||
BeforeEach(func() {
|
||||
name = uuid.NewString()
|
||||
clO = &types.Clients{Clients: []types.Client{{Name: name}}}
|
||||
clR = &types.Clients{Clients: []types.Client{{Name: name}}}
|
||||
ac.origin.clients = &model.Clients{Clients: &model.ClientsArray{{Name: utils.Ptr(name)}}}
|
||||
clR = &model.Clients{Clients: &model.ClientsArray{{Name: utils.Ptr(name)}}}
|
||||
})
|
||||
It("should have no changes (empty slices)", func() {
|
||||
cl.EXPECT().Clients().Return(clR, nil)
|
||||
cl.EXPECT().AddClients()
|
||||
cl.EXPECT().UpdateClients()
|
||||
cl.EXPECT().DeleteClients()
|
||||
err := w.syncClients(clO, cl)
|
||||
err := actionClientSettings(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should add one client", func() {
|
||||
clR.Clients = []types.Client{}
|
||||
clR.Clients = &model.ClientsArray{}
|
||||
cl.EXPECT().Clients().Return(clR, nil)
|
||||
cl.EXPECT().AddClients(clO.Clients[0])
|
||||
cl.EXPECT().UpdateClients()
|
||||
cl.EXPECT().DeleteClients()
|
||||
err := w.syncClients(clO, cl)
|
||||
cl.EXPECT().AddClient(&(*ac.origin.clients.Clients)[0])
|
||||
err := actionClientSettings(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should update one client", func() {
|
||||
clR.Clients[0].Disallowed = true
|
||||
(*clR.Clients)[0].FilteringEnabled = utils.Ptr(true)
|
||||
cl.EXPECT().Clients().Return(clR, nil)
|
||||
cl.EXPECT().AddClients()
|
||||
cl.EXPECT().UpdateClients(clO.Clients[0])
|
||||
cl.EXPECT().DeleteClients()
|
||||
err := w.syncClients(clO, cl)
|
||||
cl.EXPECT().UpdateClient(&(*ac.origin.clients.Clients)[0])
|
||||
err := actionClientSettings(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should delete one client", func() {
|
||||
clO.Clients = []types.Client{}
|
||||
ac.origin.clients.Clients = &model.ClientsArray{}
|
||||
cl.EXPECT().Clients().Return(clR, nil)
|
||||
cl.EXPECT().AddClients()
|
||||
cl.EXPECT().UpdateClients()
|
||||
cl.EXPECT().DeleteClients(clR.Clients[0])
|
||||
err := w.syncClients(clO, cl)
|
||||
cl.EXPECT().DeleteClient(&(*clR.Clients)[0])
|
||||
err := actionClientSettings(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should return error when error on Clients()", func() {
|
||||
cl.EXPECT().Clients().Return(nil, te)
|
||||
err := w.syncClients(clO, cl)
|
||||
Ω(err).Should(HaveOccurred())
|
||||
})
|
||||
It("should return error when error on AddClients()", func() {
|
||||
cl.EXPECT().Clients().Return(clR, nil)
|
||||
cl.EXPECT().DeleteClients()
|
||||
cl.EXPECT().AddClients().Return(te)
|
||||
err := w.syncClients(clO, cl)
|
||||
Ω(err).Should(HaveOccurred())
|
||||
})
|
||||
It("should return error when error on UpdateClients()", func() {
|
||||
cl.EXPECT().Clients().Return(clR, nil)
|
||||
cl.EXPECT().DeleteClients()
|
||||
cl.EXPECT().AddClients()
|
||||
cl.EXPECT().UpdateClients().Return(te)
|
||||
err := w.syncClients(clO, cl)
|
||||
Ω(err).Should(HaveOccurred())
|
||||
})
|
||||
It("should return error when error on DeleteClients()", func() {
|
||||
cl.EXPECT().Clients().Return(clR, nil)
|
||||
cl.EXPECT().DeleteClients().Return(te)
|
||||
err := w.syncClients(clO, cl)
|
||||
err := actionClientSettings(ac)
|
||||
Ω(err).Should(HaveOccurred())
|
||||
})
|
||||
})
|
||||
Context("syncGeneralSettings", func() {
|
||||
var (
|
||||
o *origin
|
||||
rs *types.Status
|
||||
)
|
||||
BeforeEach(func() {
|
||||
o = &origin{
|
||||
status: &types.Status{},
|
||||
}
|
||||
rs = &types.Status{}
|
||||
})
|
||||
Context("actionParental", func() {
|
||||
It("should have no changes", func() {
|
||||
cl.EXPECT().Parental()
|
||||
cl.EXPECT().SafeSearch()
|
||||
cl.EXPECT().SafeBrowsing()
|
||||
err := w.syncGeneralSettings(o, rs, cl)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should have protection enabled changes", func() {
|
||||
o.status.ProtectionEnabled = true
|
||||
cl.EXPECT().ToggleProtection(true)
|
||||
cl.EXPECT().Parental()
|
||||
cl.EXPECT().SafeSearch()
|
||||
cl.EXPECT().SafeBrowsing()
|
||||
err := w.syncGeneralSettings(o, rs, cl)
|
||||
err := actionParental(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should have parental enabled changes", func() {
|
||||
o.parental = true
|
||||
ac.origin.parental = true
|
||||
cl.EXPECT().Parental()
|
||||
cl.EXPECT().ToggleParental(true)
|
||||
cl.EXPECT().SafeSearch()
|
||||
cl.EXPECT().SafeBrowsing()
|
||||
err := w.syncGeneralSettings(o, rs, cl)
|
||||
err := actionParental(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
Context("actionProtection", func() {
|
||||
It("should have no changes", func() {
|
||||
err := actionProtection(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should have protection enabled changes", func() {
|
||||
ac.origin.status.ProtectionEnabled = true
|
||||
cl.EXPECT().ToggleProtection(true)
|
||||
err := actionProtection(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
Context("actionSafeSearchConfig", func() {
|
||||
It("should have no changes", func() {
|
||||
cl.EXPECT().SafeSearchConfig().Return(ac.origin.safeSearch, nil)
|
||||
|
||||
err := actionSafeSearchConfig(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should have safeSearch enabled changes", func() {
|
||||
o.safeSearch = true
|
||||
cl.EXPECT().Parental()
|
||||
cl.EXPECT().SafeSearch()
|
||||
cl.EXPECT().ToggleSafeSearch(true)
|
||||
cl.EXPECT().SafeBrowsing()
|
||||
err := w.syncGeneralSettings(o, rs, cl)
|
||||
ac.origin.safeSearch = &model.SafeSearchConfig{Enabled: utils.Ptr(true)}
|
||||
cl.EXPECT().SafeSearchConfig().Return(&model.SafeSearchConfig{}, nil)
|
||||
cl.EXPECT().SetSafeSearchConfig(ac.origin.safeSearch)
|
||||
err := actionSafeSearchConfig(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should have Duckduckgo safeSearch enabled changed", func() {
|
||||
ac.origin.safeSearch = &model.SafeSearchConfig{Duckduckgo: utils.Ptr(true)}
|
||||
cl.EXPECT().SafeSearchConfig().Return(&model.SafeSearchConfig{Google: utils.Ptr(true)}, nil)
|
||||
cl.EXPECT().SetSafeSearchConfig(ac.origin.safeSearch)
|
||||
err := actionSafeSearchConfig(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
Context("actionProfileInfo", func() {
|
||||
It("should have no changes", func() {
|
||||
cl.EXPECT().ProfileInfo().Return(ac.origin.profileInfo, nil)
|
||||
err := actionProfileInfo(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should have profileInfo language changed", func() {
|
||||
ac.origin.profileInfo.Language = "de"
|
||||
cl.EXPECT().ProfileInfo().Return(&model.ProfileInfo{Name: "replica", Language: "en"}, nil)
|
||||
cl.EXPECT().SetProfileInfo(&model.ProfileInfo{
|
||||
Language: "de",
|
||||
Name: "replica",
|
||||
Theme: "auto",
|
||||
})
|
||||
err := actionProfileInfo(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should not sync profileInfo if language is not set", func() {
|
||||
ac.origin.profileInfo.Language = ""
|
||||
cl.EXPECT().ProfileInfo().Return(&model.ProfileInfo{Name: "replica", Language: "en", Theme: "auto"}, nil)
|
||||
cl.EXPECT().SetProfileInfo(ac.origin.profileInfo).Times(0)
|
||||
err := actionProfileInfo(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should not sync profileInfo if theme is not set", func() {
|
||||
ac.origin.profileInfo.Theme = ""
|
||||
cl.EXPECT().ProfileInfo().Return(&model.ProfileInfo{Name: "replica", Language: "en", Theme: "auto"}, nil)
|
||||
cl.EXPECT().SetProfileInfo(ac.origin.profileInfo).Times(0)
|
||||
err := actionProfileInfo(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
Context("actionSafeBrowsing", func() {
|
||||
It("should have no changes", func() {
|
||||
cl.EXPECT().SafeBrowsing()
|
||||
err := actionSafeBrowsing(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
|
||||
It("should have safeBrowsing enabled changes", func() {
|
||||
o.safeBrowsing = true
|
||||
cl.EXPECT().Parental()
|
||||
cl.EXPECT().SafeSearch()
|
||||
ac.origin.safeBrowsing = true
|
||||
cl.EXPECT().SafeBrowsing()
|
||||
cl.EXPECT().ToggleSafeBrowsing(true)
|
||||
err := w.syncGeneralSettings(o, rs, cl)
|
||||
err := actionSafeBrowsing(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
Context("actionQueryLogConfig", func() {
|
||||
var qlc *model.QueryLogConfig
|
||||
BeforeEach(func() {
|
||||
qlc = &model.QueryLogConfig{}
|
||||
})
|
||||
It("should have no changes", func() {
|
||||
cl.EXPECT().QueryLogConfig().Return(qlc, nil)
|
||||
err := actionQueryLogConfig(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should have QueryLogConfig changes", func() {
|
||||
var interval model.QueryLogConfigInterval = 123
|
||||
ac.origin.queryLogConfig.Interval = &interval
|
||||
cl.EXPECT().QueryLogConfig().Return(qlc, nil)
|
||||
cl.EXPECT().SetQueryLogConfig(&model.QueryLogConfig{AnonymizeClientIp: nil, Interval: &interval, Enabled: nil})
|
||||
err := actionQueryLogConfig(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
Context("syncConfigs", func() {
|
||||
var (
|
||||
o *origin
|
||||
qlc *types.QueryLogConfig
|
||||
sc *types.IntervalConfig
|
||||
)
|
||||
var sc *model.StatsConfig
|
||||
BeforeEach(func() {
|
||||
o = &origin{
|
||||
queryLogConfig: &types.QueryLogConfig{},
|
||||
statsConfig: &types.IntervalConfig{},
|
||||
}
|
||||
qlc = &types.QueryLogConfig{}
|
||||
sc = &types.IntervalConfig{}
|
||||
sc = &model.StatsConfig{}
|
||||
})
|
||||
It("should have no changes", func() {
|
||||
cl.EXPECT().QueryLogConfig().Return(qlc, nil)
|
||||
cl.EXPECT().StatsConfig().Return(sc, nil)
|
||||
err := w.syncConfigs(o, cl)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should have QueryLogConfig changes", func() {
|
||||
o.queryLogConfig.Interval = 123
|
||||
cl.EXPECT().QueryLogConfig().Return(qlc, nil)
|
||||
cl.EXPECT().SetQueryLogConfig(false, 123.0, false)
|
||||
cl.EXPECT().StatsConfig().Return(sc, nil)
|
||||
err := w.syncConfigs(o, cl)
|
||||
err := actionStatsConfig(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should have StatsConfig changes", func() {
|
||||
o.statsConfig.Interval = 123
|
||||
cl.EXPECT().QueryLogConfig().Return(qlc, nil)
|
||||
var interval model.StatsConfigInterval = 123
|
||||
ac.origin.statsConfig.Interval = &interval
|
||||
cl.EXPECT().StatsConfig().Return(sc, nil)
|
||||
cl.EXPECT().SetStatsConfig(123.0)
|
||||
err := w.syncConfigs(o, cl)
|
||||
cl.EXPECT().SetStatsConfig(&model.StatsConfig{Interval: &interval})
|
||||
err := actionStatsConfig(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
Context("statusWithSetup", func() {
|
||||
var (
|
||||
status *types.Status
|
||||
status *model.ServerStatus
|
||||
inst types.AdGuardInstance
|
||||
)
|
||||
BeforeEach(func() {
|
||||
status = &types.Status{}
|
||||
status = &model.ServerStatus{}
|
||||
inst = types.AdGuardInstance{
|
||||
AutoSetup: true,
|
||||
}
|
||||
@@ -320,156 +359,155 @@ var _ = Describe("Sync", func() {
|
||||
Ω(st).Should(BeNil())
|
||||
})
|
||||
})
|
||||
Context("syncServices", func() {
|
||||
var (
|
||||
os types.Services
|
||||
rs types.Services
|
||||
)
|
||||
Context("actionBlockedServices", func() {
|
||||
var rbs *model.BlockedServicesArray
|
||||
BeforeEach(func() {
|
||||
os = []string{"foo"}
|
||||
rs = []string{"foo"}
|
||||
ac.origin.blockedServices = &model.BlockedServicesArray{"foo"}
|
||||
rbs = &model.BlockedServicesArray{"foo"}
|
||||
})
|
||||
It("should have no changes", func() {
|
||||
cl.EXPECT().Services().Return(rs, nil)
|
||||
err := w.syncServices(os, cl)
|
||||
cl.EXPECT().BlockedServices().Return(rbs, nil)
|
||||
err := actionBlockedServices(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should have services changes", func() {
|
||||
os = []string{"bar"}
|
||||
cl.EXPECT().Services().Return(rs, nil)
|
||||
cl.EXPECT().SetServices(os)
|
||||
err := w.syncServices(os, cl)
|
||||
It("should have blockedServices changes", func() {
|
||||
ac.origin.blockedServices = &model.BlockedServicesArray{"bar"}
|
||||
|
||||
cl.EXPECT().BlockedServices().Return(rbs, nil)
|
||||
cl.EXPECT().SetBlockedServices(ac.origin.blockedServices)
|
||||
err := actionBlockedServices(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
Context("actionBlockedServicesSchedule", func() {
|
||||
var rbss *model.BlockedServicesSchedule
|
||||
BeforeEach(func() {
|
||||
ac.origin.blockedServicesSchedule = &model.BlockedServicesSchedule{}
|
||||
rbss = &model.BlockedServicesSchedule{}
|
||||
})
|
||||
It("should have no changes", func() {
|
||||
cl.EXPECT().BlockedServicesSchedule().Return(ac.origin.blockedServicesSchedule, nil)
|
||||
err := actionBlockedServicesSchedule(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should have blockedServices schedule changes", func() {
|
||||
ac.origin.blockedServicesSchedule = &model.BlockedServicesSchedule{Ids: utils.Ptr([]string{"bar"})}
|
||||
|
||||
cl.EXPECT().BlockedServicesSchedule().Return(rbss, nil)
|
||||
cl.EXPECT().SetBlockedServicesSchedule(ac.origin.blockedServicesSchedule)
|
||||
err := actionBlockedServicesSchedule(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
Context("syncFilters", func() {
|
||||
var (
|
||||
of *types.FilteringStatus
|
||||
rf *types.FilteringStatus
|
||||
)
|
||||
var rf *model.FilterStatus
|
||||
BeforeEach(func() {
|
||||
of = &types.FilteringStatus{}
|
||||
rf = &types.FilteringStatus{}
|
||||
ac.origin.filters = &model.FilterStatus{}
|
||||
rf = &model.FilterStatus{}
|
||||
})
|
||||
It("should have no changes", func() {
|
||||
cl.EXPECT().Filtering().Return(rf, nil)
|
||||
cl.EXPECT().AddFilters(false)
|
||||
cl.EXPECT().UpdateFilters(false)
|
||||
cl.EXPECT().DeleteFilters(false)
|
||||
cl.EXPECT().AddFilters(true)
|
||||
cl.EXPECT().UpdateFilters(true)
|
||||
cl.EXPECT().DeleteFilters(true)
|
||||
err := w.syncFilters(of, cl)
|
||||
err := actionFilters(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should have changes user roles", func() {
|
||||
of.UserRules = []string{"foo"}
|
||||
ac.origin.filters.UserRules = utils.Ptr([]string{"foo"})
|
||||
cl.EXPECT().Filtering().Return(rf, nil)
|
||||
cl.EXPECT().AddFilters(false)
|
||||
cl.EXPECT().UpdateFilters(false)
|
||||
cl.EXPECT().DeleteFilters(false)
|
||||
cl.EXPECT().AddFilters(true)
|
||||
cl.EXPECT().UpdateFilters(true)
|
||||
cl.EXPECT().DeleteFilters(true)
|
||||
cl.EXPECT().SetCustomRules(of.UserRules)
|
||||
err := w.syncFilters(of, cl)
|
||||
cl.EXPECT().SetCustomRules(ac.origin.filters.UserRules)
|
||||
err := actionFilters(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should have changed filtering config", func() {
|
||||
of.Enabled = true
|
||||
of.Interval = 123
|
||||
ac.origin.filters.Enabled = utils.Ptr(true)
|
||||
ac.origin.filters.Interval = utils.Ptr(123)
|
||||
cl.EXPECT().Filtering().Return(rf, nil)
|
||||
cl.EXPECT().AddFilters(false)
|
||||
cl.EXPECT().UpdateFilters(false)
|
||||
cl.EXPECT().DeleteFilters(false)
|
||||
cl.EXPECT().AddFilters(true)
|
||||
cl.EXPECT().UpdateFilters(true)
|
||||
cl.EXPECT().DeleteFilters(true)
|
||||
cl.EXPECT().ToggleFiltering(of.Enabled, of.Interval)
|
||||
err := w.syncFilters(of, cl)
|
||||
cl.EXPECT().ToggleFiltering(*ac.origin.filters.Enabled, *ac.origin.filters.Interval)
|
||||
err := actionFilters(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
||||
Context("syncDNS", func() {
|
||||
var (
|
||||
oal *types.AccessList
|
||||
ral *types.AccessList
|
||||
odc *types.DNSConfig
|
||||
rdc *types.DNSConfig
|
||||
)
|
||||
Context("actionDNSAccessLists", func() {
|
||||
var ral *model.AccessList
|
||||
BeforeEach(func() {
|
||||
oal = &types.AccessList{}
|
||||
ral = &types.AccessList{}
|
||||
odc = &types.DNSConfig{}
|
||||
rdc = &types.DNSConfig{}
|
||||
ac.origin.accessList = &model.AccessList{}
|
||||
ral = &model.AccessList{}
|
||||
})
|
||||
It("should have no changes", func() {
|
||||
cl.EXPECT().AccessList().Return(ral, nil)
|
||||
cl.EXPECT().DNSConfig().Return(rdc, nil)
|
||||
err := w.syncDNS(oal, odc, cl)
|
||||
err := actionDNSAccessLists(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should have access list changes", func() {
|
||||
ral.BlockedHosts = []string{"foo"}
|
||||
ral.BlockedHosts = utils.Ptr([]string{"foo"})
|
||||
cl.EXPECT().AccessList().Return(ral, nil)
|
||||
cl.EXPECT().DNSConfig().Return(rdc, nil)
|
||||
cl.EXPECT().SetAccessList(oal)
|
||||
err := w.syncDNS(oal, odc, cl)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should have dns config changes", func() {
|
||||
rdc.Bootstraps = []string{"foo"}
|
||||
cl.EXPECT().AccessList().Return(ral, nil)
|
||||
cl.EXPECT().DNSConfig().Return(rdc, nil)
|
||||
cl.EXPECT().SetDNSConfig(odc)
|
||||
err := w.syncDNS(oal, odc, cl)
|
||||
cl.EXPECT().SetAccessList(ac.origin.accessList)
|
||||
err := actionDNSAccessLists(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
||||
Context("syncDHCPServer", func() {
|
||||
var (
|
||||
osc *types.DHCPServerConfig
|
||||
rsc *types.DHCPServerConfig
|
||||
)
|
||||
Context("actionDNSServerConfig", func() {
|
||||
var rdc *model.DNSConfig
|
||||
BeforeEach(func() {
|
||||
osc = &types.DHCPServerConfig{V4: &types.V4ServerConfJSON{
|
||||
GatewayIP: net.IPv4(1, 2, 3, 4),
|
||||
RangeStart: net.IPv4(1, 2, 3, 5),
|
||||
RangeEnd: net.IPv4(1, 2, 3, 6),
|
||||
SubnetMask: net.IPv4(255, 255, 255, 0),
|
||||
ac.origin.dnsConfig = &model.DNSConfig{}
|
||||
rdc = &model.DNSConfig{}
|
||||
})
|
||||
It("should have no changes", func() {
|
||||
cl.EXPECT().DNSConfig().Return(rdc, nil)
|
||||
err := actionDNSServerConfig(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should have dns config changes", func() {
|
||||
rdc.BootstrapDns = utils.Ptr([]string{"foo"})
|
||||
cl.EXPECT().DNSConfig().Return(rdc, nil)
|
||||
cl.EXPECT().SetDNSConfig(ac.origin.dnsConfig)
|
||||
err := actionDNSServerConfig(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
||||
Context("actionDHCPServerConfig", func() {
|
||||
var rsc *model.DhcpStatus
|
||||
BeforeEach(func() {
|
||||
ac.origin.dhcpServerConfig = &model.DhcpStatus{V4: &model.DhcpConfigV4{
|
||||
GatewayIp: utils.Ptr("1.2.3.4"),
|
||||
RangeStart: utils.Ptr("1.2.3.5"),
|
||||
RangeEnd: utils.Ptr("1.2.3.6"),
|
||||
SubnetMask: utils.Ptr("255.255.255.0"),
|
||||
}}
|
||||
rsc = &types.DHCPServerConfig{}
|
||||
rsc = &model.DhcpStatus{}
|
||||
w.cfg.Features.DHCP.StaticLeases = false
|
||||
})
|
||||
It("should have no changes", func() {
|
||||
rsc.V4 = osc.V4
|
||||
cl.EXPECT().DHCPServerConfig().Return(rsc, nil)
|
||||
err := w.syncDHCPServer(osc, cl, types.AdGuardInstance{})
|
||||
rsc.V4 = ac.origin.dhcpServerConfig.V4
|
||||
cl.EXPECT().DhcpConfig().Return(rsc, nil)
|
||||
err := actionDHCPServerConfig(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should have changes", func() {
|
||||
rsc.Enabled = true
|
||||
cl.EXPECT().DHCPServerConfig().Return(rsc, nil)
|
||||
cl.EXPECT().SetDHCPServerConfig(osc)
|
||||
err := w.syncDHCPServer(osc, cl, types.AdGuardInstance{})
|
||||
rsc.Enabled = utils.Ptr(true)
|
||||
cl.EXPECT().DhcpConfig().Return(rsc, nil)
|
||||
cl.EXPECT().SetDhcpConfig(ac.origin.dhcpServerConfig)
|
||||
err := actionDHCPServerConfig(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should use replica interface name", func() {
|
||||
cl.EXPECT().DHCPServerConfig().Return(rsc, nil)
|
||||
oscClone := osc.Clone()
|
||||
oscClone.InterfaceName = "foo"
|
||||
cl.EXPECT().SetDHCPServerConfig(oscClone)
|
||||
err := w.syncDHCPServer(osc, cl, types.AdGuardInstance{InterfaceName: "foo"})
|
||||
ac.replica.InterfaceName = "foo"
|
||||
cl.EXPECT().DhcpConfig().Return(rsc, nil)
|
||||
oscClone := ac.origin.dhcpServerConfig.Clone()
|
||||
oscClone.InterfaceName = utils.Ptr("foo")
|
||||
cl.EXPECT().SetDhcpConfig(oscClone)
|
||||
err := actionDHCPServerConfig(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("should enable the target dhcp server", func() {
|
||||
cl.EXPECT().DHCPServerConfig().Return(rsc, nil)
|
||||
oscClone := osc.Clone()
|
||||
oscClone.Enabled = true
|
||||
cl.EXPECT().SetDHCPServerConfig(oscClone)
|
||||
err := w.syncDHCPServer(osc, cl, types.AdGuardInstance{DHCPServerEnabled: &boolTrue})
|
||||
ac.replica.DHCPServerEnabled = utils.Ptr(true)
|
||||
cl.EXPECT().DhcpConfig().Return(rsc, nil)
|
||||
oscClone := ac.origin.dhcpServerConfig.Clone()
|
||||
oscClone.Enabled = utils.Ptr(true)
|
||||
cl.EXPECT().SetDhcpConfig(oscClone)
|
||||
err := actionDHCPServerConfig(ac)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
@@ -501,48 +539,41 @@ var _ = Describe("Sync", func() {
|
||||
It("should have no changes", func() {
|
||||
// origin
|
||||
cl.EXPECT().Host()
|
||||
cl.EXPECT().Status().Return(&types.Status{Version: versions.MinAgh}, nil)
|
||||
cl.EXPECT().Status().Return(&model.ServerStatus{Version: versions.MinAgh}, nil)
|
||||
cl.EXPECT().ProfileInfo().Return(&model.ProfileInfo{}, nil)
|
||||
cl.EXPECT().Parental()
|
||||
cl.EXPECT().SafeSearch()
|
||||
cl.EXPECT().SafeSearchConfig().Return(&model.SafeSearchConfig{}, nil)
|
||||
cl.EXPECT().SafeBrowsing()
|
||||
cl.EXPECT().RewriteList().Return(&types.RewriteEntries{}, nil)
|
||||
cl.EXPECT().Services()
|
||||
cl.EXPECT().Filtering().Return(&types.FilteringStatus{}, nil)
|
||||
cl.EXPECT().Clients().Return(&types.Clients{}, nil)
|
||||
cl.EXPECT().QueryLogConfig().Return(&types.QueryLogConfig{}, nil)
|
||||
cl.EXPECT().StatsConfig().Return(&types.IntervalConfig{}, nil)
|
||||
cl.EXPECT().AccessList().Return(&types.AccessList{}, nil)
|
||||
cl.EXPECT().DNSConfig().Return(&types.DNSConfig{}, nil)
|
||||
cl.EXPECT().DHCPServerConfig().Return(&types.DHCPServerConfig{}, nil)
|
||||
cl.EXPECT().RewriteList().Return(&model.RewriteEntries{}, nil)
|
||||
cl.EXPECT().BlockedServices()
|
||||
cl.EXPECT().BlockedServicesSchedule()
|
||||
cl.EXPECT().Filtering().Return(&model.FilterStatus{}, nil)
|
||||
cl.EXPECT().Clients().Return(&model.Clients{}, nil)
|
||||
cl.EXPECT().QueryLogConfig().Return(&model.QueryLogConfig{}, nil)
|
||||
cl.EXPECT().StatsConfig().Return(&model.StatsConfig{}, nil)
|
||||
cl.EXPECT().AccessList().Return(&model.AccessList{}, nil)
|
||||
cl.EXPECT().DNSConfig().Return(&model.DNSConfig{}, nil)
|
||||
cl.EXPECT().DhcpConfig().Return(&model.DhcpStatus{}, nil)
|
||||
|
||||
// replica
|
||||
cl.EXPECT().Host()
|
||||
cl.EXPECT().Status().Return(&types.Status{Version: versions.MinAgh}, nil)
|
||||
cl.EXPECT().Status().Return(&model.ServerStatus{Version: versions.MinAgh}, nil)
|
||||
cl.EXPECT().ProfileInfo().Return(&model.ProfileInfo{}, nil)
|
||||
cl.EXPECT().Parental()
|
||||
cl.EXPECT().SafeSearch()
|
||||
cl.EXPECT().SafeSearchConfig().Return(&model.SafeSearchConfig{}, nil)
|
||||
cl.EXPECT().SafeBrowsing()
|
||||
cl.EXPECT().QueryLogConfig().Return(&types.QueryLogConfig{}, nil)
|
||||
cl.EXPECT().StatsConfig().Return(&types.IntervalConfig{}, nil)
|
||||
cl.EXPECT().RewriteList().Return(&types.RewriteEntries{}, nil)
|
||||
cl.EXPECT().QueryLogConfig().Return(&model.QueryLogConfig{}, nil)
|
||||
cl.EXPECT().StatsConfig().Return(&model.StatsConfig{}, nil)
|
||||
cl.EXPECT().RewriteList().Return(&model.RewriteEntries{}, nil)
|
||||
cl.EXPECT().AddRewriteEntries()
|
||||
cl.EXPECT().DeleteRewriteEntries()
|
||||
cl.EXPECT().Filtering().Return(&types.FilteringStatus{}, nil)
|
||||
cl.EXPECT().AddFilters(false)
|
||||
cl.EXPECT().UpdateFilters(false)
|
||||
cl.EXPECT().DeleteFilters(false)
|
||||
cl.EXPECT().AddFilters(true)
|
||||
cl.EXPECT().UpdateFilters(true)
|
||||
cl.EXPECT().DeleteFilters(true)
|
||||
cl.EXPECT().Services()
|
||||
cl.EXPECT().Clients().Return(&types.Clients{}, nil)
|
||||
cl.EXPECT().AddClients()
|
||||
cl.EXPECT().UpdateClients()
|
||||
cl.EXPECT().DeleteClients()
|
||||
cl.EXPECT().AccessList().Return(&types.AccessList{}, nil)
|
||||
cl.EXPECT().DNSConfig().Return(&types.DNSConfig{}, nil)
|
||||
cl.EXPECT().DHCPServerConfig().Return(&types.DHCPServerConfig{}, nil)
|
||||
cl.EXPECT().AddDHCPStaticLeases().Return(nil)
|
||||
cl.EXPECT().DeleteDHCPStaticLeases().Return(nil)
|
||||
cl.EXPECT().Filtering().Return(&model.FilterStatus{}, nil)
|
||||
cl.EXPECT().BlockedServices()
|
||||
cl.EXPECT().BlockedServicesSchedule()
|
||||
cl.EXPECT().Clients().Return(&model.Clients{}, nil)
|
||||
cl.EXPECT().AccessList().Return(&model.AccessList{}, nil)
|
||||
cl.EXPECT().DNSConfig().Return(&model.DNSConfig{}, nil)
|
||||
cl.EXPECT().DhcpConfig().Return(&model.DhcpStatus{}, nil)
|
||||
w.sync()
|
||||
})
|
||||
It("should not sync DHCP", func() {
|
||||
@@ -550,94 +581,69 @@ var _ = Describe("Sync", func() {
|
||||
w.cfg.Features.DHCP.StaticLeases = false
|
||||
// origin
|
||||
cl.EXPECT().Host()
|
||||
cl.EXPECT().Status().Return(&types.Status{Version: versions.MinAgh}, nil)
|
||||
cl.EXPECT().Status().Return(&model.ServerStatus{Version: versions.MinAgh}, nil)
|
||||
cl.EXPECT().ProfileInfo().Return(&model.ProfileInfo{}, nil)
|
||||
cl.EXPECT().Parental()
|
||||
cl.EXPECT().SafeSearch()
|
||||
cl.EXPECT().SafeSearchConfig().Return(&model.SafeSearchConfig{}, nil)
|
||||
cl.EXPECT().SafeBrowsing()
|
||||
cl.EXPECT().RewriteList().Return(&types.RewriteEntries{}, nil)
|
||||
cl.EXPECT().Services()
|
||||
cl.EXPECT().Filtering().Return(&types.FilteringStatus{}, nil)
|
||||
cl.EXPECT().Clients().Return(&types.Clients{}, nil)
|
||||
cl.EXPECT().QueryLogConfig().Return(&types.QueryLogConfig{}, nil)
|
||||
cl.EXPECT().StatsConfig().Return(&types.IntervalConfig{}, nil)
|
||||
cl.EXPECT().AccessList().Return(&types.AccessList{}, nil)
|
||||
cl.EXPECT().DNSConfig().Return(&types.DNSConfig{}, nil)
|
||||
cl.EXPECT().RewriteList().Return(&model.RewriteEntries{}, nil)
|
||||
cl.EXPECT().BlockedServices()
|
||||
cl.EXPECT().BlockedServicesSchedule()
|
||||
cl.EXPECT().Filtering().Return(&model.FilterStatus{}, nil)
|
||||
cl.EXPECT().Clients().Return(&model.Clients{}, nil)
|
||||
cl.EXPECT().QueryLogConfig().Return(&model.QueryLogConfig{}, nil)
|
||||
cl.EXPECT().StatsConfig().Return(&model.StatsConfig{}, nil)
|
||||
cl.EXPECT().AccessList().Return(&model.AccessList{}, nil)
|
||||
cl.EXPECT().DNSConfig().Return(&model.DNSConfig{}, nil)
|
||||
|
||||
// replica
|
||||
cl.EXPECT().Host()
|
||||
cl.EXPECT().Status().Return(&types.Status{Version: versions.MinAgh}, nil)
|
||||
cl.EXPECT().Status().Return(&model.ServerStatus{Version: versions.MinAgh}, nil)
|
||||
cl.EXPECT().ProfileInfo().Return(&model.ProfileInfo{}, nil)
|
||||
cl.EXPECT().Parental()
|
||||
cl.EXPECT().SafeSearch()
|
||||
cl.EXPECT().SafeSearchConfig().Return(&model.SafeSearchConfig{}, nil)
|
||||
cl.EXPECT().SafeBrowsing()
|
||||
cl.EXPECT().QueryLogConfig().Return(&types.QueryLogConfig{}, nil)
|
||||
cl.EXPECT().StatsConfig().Return(&types.IntervalConfig{}, nil)
|
||||
cl.EXPECT().RewriteList().Return(&types.RewriteEntries{}, nil)
|
||||
cl.EXPECT().QueryLogConfig().Return(&model.QueryLogConfig{}, nil)
|
||||
cl.EXPECT().StatsConfig().Return(&model.StatsConfig{}, nil)
|
||||
cl.EXPECT().RewriteList().Return(&model.RewriteEntries{}, nil)
|
||||
cl.EXPECT().AddRewriteEntries()
|
||||
cl.EXPECT().DeleteRewriteEntries()
|
||||
cl.EXPECT().Filtering().Return(&types.FilteringStatus{}, nil)
|
||||
cl.EXPECT().AddFilters(false)
|
||||
cl.EXPECT().UpdateFilters(false)
|
||||
cl.EXPECT().DeleteFilters(false)
|
||||
cl.EXPECT().AddFilters(true)
|
||||
cl.EXPECT().UpdateFilters(true)
|
||||
cl.EXPECT().DeleteFilters(true)
|
||||
cl.EXPECT().Services()
|
||||
cl.EXPECT().Clients().Return(&types.Clients{}, nil)
|
||||
cl.EXPECT().AddClients()
|
||||
cl.EXPECT().UpdateClients()
|
||||
cl.EXPECT().DeleteClients()
|
||||
cl.EXPECT().AccessList().Return(&types.AccessList{}, nil)
|
||||
cl.EXPECT().DNSConfig().Return(&types.DNSConfig{}, nil)
|
||||
cl.EXPECT().Filtering().Return(&model.FilterStatus{}, nil)
|
||||
cl.EXPECT().BlockedServices()
|
||||
cl.EXPECT().BlockedServicesSchedule()
|
||||
cl.EXPECT().Clients().Return(&model.Clients{}, nil)
|
||||
cl.EXPECT().AccessList().Return(&model.AccessList{}, nil)
|
||||
cl.EXPECT().DNSConfig().Return(&model.DNSConfig{}, nil)
|
||||
w.sync()
|
||||
})
|
||||
It("origin version is too small", func() {
|
||||
// origin
|
||||
cl.EXPECT().Host()
|
||||
cl.EXPECT().Status().Return(&types.Status{Version: "v0.106.9"}, nil)
|
||||
cl.EXPECT().Status().Return(&model.ServerStatus{Version: "v0.106.9"}, nil)
|
||||
w.sync()
|
||||
})
|
||||
It("replica version is too small", func() {
|
||||
// origin
|
||||
cl.EXPECT().Host()
|
||||
cl.EXPECT().Status().Return(&types.Status{Version: versions.MinAgh}, nil)
|
||||
cl.EXPECT().Status().Return(&model.ServerStatus{Version: versions.MinAgh}, nil)
|
||||
cl.EXPECT().ProfileInfo().Return(&model.ProfileInfo{}, nil)
|
||||
cl.EXPECT().Parental()
|
||||
cl.EXPECT().SafeSearch()
|
||||
cl.EXPECT().SafeSearchConfig().Return(&model.SafeSearchConfig{}, nil)
|
||||
cl.EXPECT().SafeBrowsing()
|
||||
cl.EXPECT().RewriteList().Return(&types.RewriteEntries{}, nil)
|
||||
cl.EXPECT().Services()
|
||||
cl.EXPECT().Filtering().Return(&types.FilteringStatus{}, nil)
|
||||
cl.EXPECT().Clients().Return(&types.Clients{}, nil)
|
||||
cl.EXPECT().QueryLogConfig().Return(&types.QueryLogConfig{}, nil)
|
||||
cl.EXPECT().StatsConfig().Return(&types.IntervalConfig{}, nil)
|
||||
cl.EXPECT().AccessList().Return(&types.AccessList{}, nil)
|
||||
cl.EXPECT().DNSConfig().Return(&types.DNSConfig{}, nil)
|
||||
cl.EXPECT().DHCPServerConfig().Return(&types.DHCPServerConfig{}, nil)
|
||||
cl.EXPECT().RewriteList().Return(&model.RewriteEntries{}, nil)
|
||||
cl.EXPECT().BlockedServices()
|
||||
cl.EXPECT().BlockedServicesSchedule()
|
||||
cl.EXPECT().Filtering().Return(&model.FilterStatus{}, nil)
|
||||
cl.EXPECT().Clients().Return(&model.Clients{}, nil)
|
||||
cl.EXPECT().QueryLogConfig().Return(&model.QueryLogConfig{}, nil)
|
||||
cl.EXPECT().StatsConfig().Return(&model.StatsConfig{}, nil)
|
||||
cl.EXPECT().AccessList().Return(&model.AccessList{}, nil)
|
||||
cl.EXPECT().DNSConfig().Return(&model.DNSConfig{}, nil)
|
||||
cl.EXPECT().DhcpConfig().Return(&model.DhcpStatus{}, nil)
|
||||
|
||||
// replica
|
||||
cl.EXPECT().Host()
|
||||
cl.EXPECT().Status().Return(&types.Status{Version: "v0.106.9"}, nil)
|
||||
w.sync()
|
||||
})
|
||||
It("replica version is with incompatible API", func() {
|
||||
// origin
|
||||
cl.EXPECT().Host()
|
||||
cl.EXPECT().Status().Return(&types.Status{Version: versions.MinAgh}, nil)
|
||||
cl.EXPECT().Parental()
|
||||
cl.EXPECT().SafeSearch()
|
||||
cl.EXPECT().SafeBrowsing()
|
||||
cl.EXPECT().RewriteList().Return(&types.RewriteEntries{}, nil)
|
||||
cl.EXPECT().Services()
|
||||
cl.EXPECT().Filtering().Return(&types.FilteringStatus{}, nil)
|
||||
cl.EXPECT().Clients().Return(&types.Clients{}, nil)
|
||||
cl.EXPECT().QueryLogConfig().Return(&types.QueryLogConfig{}, nil)
|
||||
cl.EXPECT().StatsConfig().Return(&types.IntervalConfig{}, nil)
|
||||
cl.EXPECT().AccessList().Return(&types.AccessList{}, nil)
|
||||
cl.EXPECT().DNSConfig().Return(&types.DNSConfig{}, nil)
|
||||
cl.EXPECT().DHCPServerConfig().Return(&types.DHCPServerConfig{}, nil)
|
||||
|
||||
// replica
|
||||
cl.EXPECT().Host()
|
||||
cl.EXPECT().Status().Return(&types.Status{Version: versions.IncompatibleAPI}, nil)
|
||||
cl.EXPECT().Status().Return(&model.ServerStatus{Version: "v0.106.9"}, nil)
|
||||
w.sync()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -5,10 +5,6 @@
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
net "net"
|
||||
)
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *AdGuardInstance) DeepCopyInto(out *AdGuardInstance) {
|
||||
*out = *in
|
||||
@@ -60,44 +56,3 @@ func (in *Config) DeepCopy() *Config {
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
||||
func (in *DNSConfig) DeepCopyInto(out *DNSConfig) {
|
||||
*out = *in
|
||||
if in.Upstreams != nil {
|
||||
in, out := &in.Upstreams, &out.Upstreams
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.Bootstraps != nil {
|
||||
in, out := &in.Bootstraps, &out.Bootstraps
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.BlockingIPv4 != nil {
|
||||
in, out := &in.BlockingIPv4, &out.BlockingIPv4
|
||||
*out = make(net.IP, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.BlockingIPv6 != nil {
|
||||
in, out := &in.BlockingIPv6, &out.BlockingIPv6
|
||||
*out = make(net.IP, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
if in.LocalPTRUpstreams != nil {
|
||||
in, out := &in.LocalPTRUpstreams, &out.LocalPTRUpstreams
|
||||
*out = make([]string, len(*in))
|
||||
copy(*out, *in)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DNSConfig.
|
||||
func (in *DNSConfig) DeepCopy() *DNSConfig {
|
||||
if in == nil {
|
||||
return nil
|
||||
}
|
||||
out := new(DNSConfig)
|
||||
in.DeepCopyInto(out)
|
||||
return out
|
||||
}
|
||||
|
||||
@@ -1,101 +0,0 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net"
|
||||
"time"
|
||||
|
||||
"github.com/jinzhu/copier"
|
||||
)
|
||||
|
||||
// DHCPServerConfig dhcp server config
|
||||
type DHCPServerConfig struct {
|
||||
V4 *V4ServerConfJSON `json:"v4"`
|
||||
V6 *V6ServerConfJSON `json:"v6"`
|
||||
InterfaceName string `json:"interface_name"`
|
||||
Enabled bool `json:"enabled"`
|
||||
|
||||
Leases Leases `json:"leases,omitempty"`
|
||||
StaticLeases Leases `json:"static_leases,omitempty"`
|
||||
}
|
||||
|
||||
// Clone the config
|
||||
func (c *DHCPServerConfig) Clone() *DHCPServerConfig {
|
||||
clone := &DHCPServerConfig{}
|
||||
_ = copier.Copy(clone, c)
|
||||
return clone
|
||||
}
|
||||
|
||||
// Equals dhcp server config equal check
|
||||
func (c *DHCPServerConfig) Equals(o *DHCPServerConfig) bool {
|
||||
a, _ := json.Marshal(c)
|
||||
b, _ := json.Marshal(o)
|
||||
return string(a) == string(b)
|
||||
}
|
||||
|
||||
func (c *DHCPServerConfig) HasConfig() bool {
|
||||
return (c.V4 != nil && c.V4.isValid()) || (c.V6 != nil && c.V6.isValid())
|
||||
}
|
||||
|
||||
// V4ServerConfJSON v4 server conf
|
||||
type V4ServerConfJSON struct {
|
||||
GatewayIP net.IP `json:"gateway_ip"`
|
||||
SubnetMask net.IP `json:"subnet_mask"`
|
||||
RangeStart net.IP `json:"range_start"`
|
||||
RangeEnd net.IP `json:"range_end"`
|
||||
LeaseDuration uint32 `json:"lease_duration"`
|
||||
}
|
||||
|
||||
func (j V4ServerConfJSON) isValid() bool {
|
||||
return j.GatewayIP != nil && j.SubnetMask != nil && j.RangeStart != nil && j.RangeEnd != nil
|
||||
}
|
||||
|
||||
// V6ServerConfJSON v6 server conf
|
||||
type V6ServerConfJSON struct {
|
||||
RangeStart net.IP `json:"range_start"`
|
||||
RangeEnd net.IP `json:"range_end"`
|
||||
LeaseDuration uint32 `json:"lease_duration"`
|
||||
}
|
||||
|
||||
func (j V6ServerConfJSON) isValid() bool {
|
||||
return j.RangeStart != nil && j.RangeEnd != nil
|
||||
}
|
||||
|
||||
// Leases slice of leases type
|
||||
type Leases []Lease
|
||||
|
||||
// Merge the leases
|
||||
func (l Leases) Merge(other Leases) ([]Lease, []Lease) {
|
||||
current := make(map[string]Lease)
|
||||
|
||||
var adds Leases
|
||||
var removes Leases
|
||||
for _, le := range l {
|
||||
current[le.HWAddr] = le
|
||||
}
|
||||
|
||||
for _, le := range other {
|
||||
if _, ok := current[le.HWAddr]; ok {
|
||||
delete(current, le.HWAddr)
|
||||
} else {
|
||||
adds = append(adds, le)
|
||||
}
|
||||
}
|
||||
|
||||
for _, rr := range current {
|
||||
removes = append(removes, rr)
|
||||
}
|
||||
|
||||
return adds, removes
|
||||
}
|
||||
|
||||
// Lease contains the necessary information about a DHCP lease
|
||||
type Lease struct {
|
||||
HWAddr string `json:"mac"`
|
||||
IP net.IP `json:"ip"`
|
||||
Hostname string `json:"hostname"`
|
||||
|
||||
// Lease expiration time
|
||||
// 1: static lease
|
||||
Expiry time.Time `json:"expires"`
|
||||
}
|
||||
@@ -1,71 +0,0 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// DNSConfig dns config
|
||||
// +k8s:deepcopy-gen=true
|
||||
type DNSConfig struct {
|
||||
Upstreams []string `json:"upstream_dns,omitempty"`
|
||||
UpstreamsFile string `json:"upstream_dns_file"`
|
||||
Bootstraps []string `json:"bootstrap_dns,omitempty"`
|
||||
|
||||
ProtectionEnabled bool `json:"protection_enabled"`
|
||||
RateLimit uint32 `json:"ratelimit"`
|
||||
BlockingMode string `json:"blocking_mode,omitempty"`
|
||||
BlockingIPv4 net.IP `json:"blocking_ipv4,omitempty"`
|
||||
BlockingIPv6 net.IP `json:"blocking_ipv6"`
|
||||
EDNSCSEnabled bool `json:"edns_cs_enabled"`
|
||||
DNSSECEnabled bool `json:"dnssec_enabled"`
|
||||
DisableIPv6 bool `json:"disable_ipv6"`
|
||||
UpstreamMode string `json:"upstream_mode,omitempty"`
|
||||
CacheSize uint32 `json:"cache_size"`
|
||||
CacheMinTTL uint32 `json:"cache_ttl_min"`
|
||||
CacheMaxTTL uint32 `json:"cache_ttl_max"`
|
||||
CacheOptimistic bool `json:"cache_optimistic"`
|
||||
ResolveClients bool `json:"resolve_clients"`
|
||||
LocalPTRUpstreams []string `json:"local_ptr_upstreams,omitempty"`
|
||||
}
|
||||
|
||||
// Equals dns config equal check
|
||||
func (c *DNSConfig) Equals(o *DNSConfig) bool {
|
||||
cc := c.DeepCopy()
|
||||
oo := o.DeepCopy()
|
||||
cc.Sort()
|
||||
oo.Sort()
|
||||
|
||||
a, _ := json.Marshal(cc)
|
||||
b, _ := json.Marshal(oo)
|
||||
return string(a) == string(b)
|
||||
}
|
||||
|
||||
// Sort sort dns config
|
||||
func (c *DNSConfig) Sort() {
|
||||
sort.Strings(c.Upstreams)
|
||||
sort.Strings(c.Bootstraps)
|
||||
sort.Strings(c.LocalPTRUpstreams)
|
||||
}
|
||||
|
||||
// AccessList access list
|
||||
type AccessList struct {
|
||||
AllowedClients []string `json:"allowed_clients"`
|
||||
DisallowedClients []string `json:"disallowed_clients"`
|
||||
BlockedHosts []string `json:"blocked_hosts"`
|
||||
}
|
||||
|
||||
// Equals access list equal check
|
||||
func (al *AccessList) Equals(o *AccessList) bool {
|
||||
return equals(al.AllowedClients, o.AllowedClients) &&
|
||||
equals(al.DisallowedClients, o.DisallowedClients) &&
|
||||
equals(al.BlockedHosts, o.BlockedHosts)
|
||||
}
|
||||
|
||||
// Sort sort access list
|
||||
func (al *AccessList) Sort() {
|
||||
sort.Strings(al.AllowedClients)
|
||||
sort.Strings(al.DisallowedClients)
|
||||
sort.Strings(al.BlockedHosts)
|
||||
}
|
||||
@@ -60,7 +60,7 @@ func (f *Features) LogDisabled(l *zap.SugaredLogger) {
|
||||
features = append(features, "ClientSettings")
|
||||
}
|
||||
if !f.Services {
|
||||
features = append(features, "Services")
|
||||
features = append(features, "BlockedServices")
|
||||
}
|
||||
if !f.Filters {
|
||||
features = append(features, "Filters")
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
package types
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
"net/url"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/versions"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
@@ -18,13 +15,16 @@ const (
|
||||
// Config application configuration struct
|
||||
// +k8s:deepcopy-gen=true
|
||||
type Config struct {
|
||||
Origin AdGuardInstance `json:"origin" yaml:"origin"`
|
||||
Replica *AdGuardInstance `json:"replica,omitempty" yaml:"replica,omitempty"`
|
||||
Replicas []AdGuardInstance `json:"replicas,omitempty" yaml:"replicas,omitempty"`
|
||||
Cron string `json:"cron,omitempty" yaml:"cron,omitempty"`
|
||||
RunOnStart bool `json:"runOnStart,omitempty" yaml:"runOnStart,omitempty"`
|
||||
API API `json:"api,omitempty" yaml:"api,omitempty"`
|
||||
Features Features `json:"features,omitempty" yaml:"features,omitempty"`
|
||||
Origin AdGuardInstance `json:"origin" yaml:"origin"`
|
||||
Replica *AdGuardInstance `json:"replica,omitempty" yaml:"replica,omitempty"`
|
||||
Replicas []AdGuardInstance `json:"replicas,omitempty" yaml:"replicas,omitempty"`
|
||||
Cron string `json:"cron,omitempty" yaml:"cron,omitempty"`
|
||||
RunOnStart bool `json:"runOnStart,omitempty" yaml:"runOnStart,omitempty"`
|
||||
PrintConfigOnly bool `json:"printConfigOnly,omitempty" yaml:"printConfigOnly,omitempty" mapstructure:"PRINT_CONFIG_ONLY"`
|
||||
ContinueOnError bool `json:"continueOnError,omitempty" yaml:"continueOnError,omitempty" mapstructure:"CONTINUE_ON_ERROR"`
|
||||
API API `json:"api,omitempty" yaml:"api,omitempty"`
|
||||
Features Features `json:"features,omitempty" yaml:"features,omitempty"`
|
||||
LogLevel string `json:"logLevel,omitempty" yaml:"logLevel,omitempty" mapstructure:"LOG_LEVEL"`
|
||||
}
|
||||
|
||||
// API configuration
|
||||
@@ -74,17 +74,35 @@ func (cfg *Config) Log(l *zap.SugaredLogger) {
|
||||
l.With("config", c).Debug("Using config")
|
||||
}
|
||||
|
||||
func (cfg *Config) Init() error {
|
||||
if err := cfg.Origin.Init(); err != nil {
|
||||
return err
|
||||
}
|
||||
for i := range cfg.Replicas {
|
||||
replica := &cfg.Replicas[i]
|
||||
if err := replica.Init(); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AdGuardInstance AdguardHome config instance
|
||||
// +k8s:deepcopy-gen=true
|
||||
type AdGuardInstance struct {
|
||||
URL string `json:"url" yaml:"url"`
|
||||
WebURL string `json:"webURL" yaml:"webURL"`
|
||||
APIPath string `json:"apiPath,omitempty" yaml:"apiPath,omitempty"`
|
||||
Username string `json:"username,omitempty" yaml:"username,omitempty"`
|
||||
Password string `json:"password,omitempty" yaml:"password,omitempty"`
|
||||
Cookie string `json:"cookie,omitempty" yaml:"cookie,omitempty"`
|
||||
InsecureSkipVerify bool `json:"insecureSkipVerify" yaml:"insecureSkipVerify"`
|
||||
AutoSetup bool `json:"autoSetup" yaml:"autoSetup"`
|
||||
InterfaceName string `json:"interfaceName" yaml:"interfaceName"`
|
||||
InterfaceName string `json:"interfaceName,omitempty" yaml:"interfaceName,omitempty"`
|
||||
DHCPServerEnabled *bool `json:"dhcpServerEnabled,omitempty" yaml:"dhcpServerEnabled,omitempty"`
|
||||
|
||||
Host string `json:"-" yaml:"-"`
|
||||
WebHost string `json:"-" yaml:"-"`
|
||||
}
|
||||
|
||||
// Key AdGuardInstance key
|
||||
@@ -98,6 +116,26 @@ func (i *AdGuardInstance) Mask() {
|
||||
i.Password = mask(i.Password)
|
||||
}
|
||||
|
||||
func (i *AdGuardInstance) Init() error {
|
||||
u, err := url.Parse(i.URL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.Host = u.Host
|
||||
|
||||
if i.WebURL == "" {
|
||||
i.WebHost = i.Host
|
||||
i.WebURL = i.URL
|
||||
} else {
|
||||
u, err := url.Parse(i.WebURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
i.WebHost = u.Host
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func mask(s string) string {
|
||||
if s == "" {
|
||||
return "***"
|
||||
@@ -110,308 +148,6 @@ type Protection struct {
|
||||
ProtectionEnabled bool `json:"protection_enabled"`
|
||||
}
|
||||
|
||||
// Status API struct
|
||||
type Status struct {
|
||||
Protection
|
||||
DNSAddresses []string `json:"dns_addresses"`
|
||||
DNSPort int `json:"dns_port"`
|
||||
HTTPPort int `json:"http_port"`
|
||||
DhcpAvailable bool `json:"dhcp_available"`
|
||||
Running bool `json:"running"`
|
||||
Version string `json:"version"`
|
||||
Language string `json:"language"`
|
||||
}
|
||||
|
||||
// RewriteEntries list of RewriteEntry
|
||||
type RewriteEntries []RewriteEntry
|
||||
|
||||
// Merge RewriteEntries
|
||||
func (rwe *RewriteEntries) Merge(other *RewriteEntries) (RewriteEntries, RewriteEntries, RewriteEntries) {
|
||||
current := make(map[string]RewriteEntry)
|
||||
|
||||
var adds RewriteEntries
|
||||
var removes RewriteEntries
|
||||
var duplicates RewriteEntries
|
||||
processed := make(map[string]bool)
|
||||
for _, rr := range *rwe {
|
||||
if _, ok := processed[rr.Key()]; !ok {
|
||||
current[rr.Key()] = rr
|
||||
processed[rr.Key()] = true
|
||||
} else {
|
||||
// remove duplicate
|
||||
removes = append(removes, rr)
|
||||
}
|
||||
}
|
||||
|
||||
for _, rr := range *other {
|
||||
if _, ok := current[rr.Key()]; ok {
|
||||
delete(current, rr.Key())
|
||||
} else {
|
||||
if _, ok := processed[rr.Key()]; !ok {
|
||||
adds = append(adds, rr)
|
||||
processed[rr.Key()] = true
|
||||
} else {
|
||||
// skip duplicate
|
||||
duplicates = append(duplicates, rr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, rr := range current {
|
||||
removes = append(removes, rr)
|
||||
}
|
||||
|
||||
return adds, removes, duplicates
|
||||
}
|
||||
|
||||
// RewriteEntry API struct
|
||||
type RewriteEntry struct {
|
||||
Domain string `json:"domain"`
|
||||
Answer string `json:"answer"`
|
||||
}
|
||||
|
||||
// Key RewriteEntry key
|
||||
func (re *RewriteEntry) Key() string {
|
||||
return fmt.Sprintf("%s#%s", re.Domain, re.Answer)
|
||||
}
|
||||
|
||||
// Filters list of Filter
|
||||
type Filters []Filter
|
||||
|
||||
// Merge merge Filters
|
||||
func (f Filters) Merge(other Filters) (Filters, Filters, Filters) {
|
||||
current := make(map[string]Filter)
|
||||
|
||||
var adds Filters
|
||||
var updates Filters
|
||||
var removes Filters
|
||||
for _, f := range f {
|
||||
current[f.URL] = f
|
||||
}
|
||||
|
||||
for i := range other {
|
||||
rr := other[i]
|
||||
if c, ok := current[rr.URL]; ok {
|
||||
if !c.Equals(&rr) {
|
||||
updates = append(updates, rr)
|
||||
}
|
||||
delete(current, rr.URL)
|
||||
} else {
|
||||
adds = append(adds, rr)
|
||||
}
|
||||
}
|
||||
|
||||
for _, rr := range current {
|
||||
removes = append(removes, rr)
|
||||
}
|
||||
|
||||
return adds, updates, removes
|
||||
}
|
||||
|
||||
// Filter API struct
|
||||
type Filter struct {
|
||||
ID int `json:"id"`
|
||||
Enabled bool `json:"enabled"`
|
||||
URL string `json:"url"` // needed for add
|
||||
Name string `json:"name"` // needed for add
|
||||
RulesCount int `json:"rules_count"`
|
||||
Whitelist bool `json:"whitelist"` // needed for add
|
||||
}
|
||||
|
||||
// Equals Filter equal check
|
||||
func (f *Filter) Equals(o *Filter) bool {
|
||||
return f.Enabled == o.Enabled && f.URL == o.URL && f.Name == o.Name
|
||||
}
|
||||
|
||||
// FilterUpdate API struct
|
||||
type FilterUpdate struct {
|
||||
URL string `json:"url"`
|
||||
Data Filter `json:"data"`
|
||||
Whitelist bool `json:"whitelist"`
|
||||
}
|
||||
|
||||
// FilteringStatus API struct
|
||||
type FilteringStatus struct {
|
||||
FilteringConfig
|
||||
Filters Filters `json:"filters"`
|
||||
WhitelistFilters Filters `json:"whitelist_filters"`
|
||||
UserRules UserRules `json:"user_rules"`
|
||||
}
|
||||
|
||||
// UserRules API struct
|
||||
type UserRules []string
|
||||
|
||||
// String toString of Users
|
||||
func (ur UserRules) String() string {
|
||||
return strings.Join(ur, "\n")
|
||||
}
|
||||
|
||||
// ToPayload return the version specific payload for user rules
|
||||
func (ur UserRules) ToPayload(version string) interface{} {
|
||||
if versions.IsNewerThan(version, versions.LastStringCustomRules) {
|
||||
return &UserRulesRequest{Rules: ur}
|
||||
}
|
||||
return ur.String()
|
||||
}
|
||||
|
||||
// UserRulesRequest API struct
|
||||
type UserRulesRequest struct {
|
||||
Rules UserRules
|
||||
}
|
||||
|
||||
// String toString of Users
|
||||
func (ur UserRulesRequest) String() string {
|
||||
return ur.Rules.String()
|
||||
}
|
||||
|
||||
// EnableConfig API struct
|
||||
type EnableConfig struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
// IntervalConfig API struct
|
||||
type IntervalConfig struct {
|
||||
Interval float64 `json:"interval"`
|
||||
}
|
||||
|
||||
// FilteringConfig API struct
|
||||
type FilteringConfig struct {
|
||||
EnableConfig
|
||||
IntervalConfig
|
||||
}
|
||||
|
||||
// QueryLogConfig API struct
|
||||
type QueryLogConfig struct {
|
||||
EnableConfig
|
||||
IntervalConfig
|
||||
AnonymizeClientIP bool `json:"anonymize_client_ip"`
|
||||
}
|
||||
|
||||
// Equals QueryLogConfig equal check
|
||||
func (qlc *QueryLogConfig) Equals(o *QueryLogConfig) bool {
|
||||
return qlc.Enabled == o.Enabled && qlc.AnonymizeClientIP == o.AnonymizeClientIP && qlc.Interval == o.Interval
|
||||
}
|
||||
|
||||
// RefreshFilter API struct
|
||||
type RefreshFilter struct {
|
||||
Whitelist bool `json:"whitelist"`
|
||||
}
|
||||
|
||||
// Services API struct
|
||||
type Services []string
|
||||
|
||||
// Sort sort Services
|
||||
func (s Services) Sort() {
|
||||
sort.Strings(s)
|
||||
}
|
||||
|
||||
// Equals Services equal check
|
||||
func (s Services) Equals(o Services) bool {
|
||||
s.Sort()
|
||||
o.Sort()
|
||||
return equals(s, o)
|
||||
}
|
||||
|
||||
// Clients API struct
|
||||
type Clients struct {
|
||||
Clients []Client `json:"clients"`
|
||||
AutoClients []struct {
|
||||
IP string `json:"ip"`
|
||||
Name string `json:"name"`
|
||||
Source string `json:"source"`
|
||||
WhoisInfo struct{} `json:"whois_info"`
|
||||
} `json:"auto_clients"`
|
||||
SupportedTags []string `json:"supported_tags"`
|
||||
}
|
||||
|
||||
// Client API struct
|
||||
type Client struct {
|
||||
Ids []string `json:"ids,omitempty"`
|
||||
Tags []string `json:"tags,omitempty"`
|
||||
BlockedServices []string `json:"blocked_services,omitempty"`
|
||||
Upstreams []string `json:"upstreams,omitempty"`
|
||||
|
||||
UseGlobalSettings bool `json:"use_global_settings"`
|
||||
UseGlobalBlockedServices bool `json:"use_global_blocked_services"`
|
||||
Name string `json:"name"`
|
||||
FilteringEnabled bool `json:"filtering_enabled"`
|
||||
ParentalEnabled bool `json:"parental_enabled"`
|
||||
SafesearchEnabled bool `json:"safesearch_enabled"`
|
||||
SafebrowsingEnabled bool `json:"safebrowsing_enabled"`
|
||||
Disallowed bool `json:"disallowed"`
|
||||
DisallowedRule string `json:"disallowed_rule"`
|
||||
}
|
||||
|
||||
// Sort sort clients
|
||||
func (cl *Client) Sort() {
|
||||
sort.Strings(cl.Ids)
|
||||
sort.Strings(cl.Tags)
|
||||
sort.Strings(cl.BlockedServices)
|
||||
sort.Strings(cl.Upstreams)
|
||||
}
|
||||
|
||||
// Equals Clients equal check
|
||||
func (cl *Client) Equals(o *Client) bool {
|
||||
cl.Sort()
|
||||
o.Sort()
|
||||
|
||||
a, _ := json.Marshal(cl)
|
||||
b, _ := json.Marshal(o)
|
||||
return string(a) == string(b)
|
||||
}
|
||||
|
||||
// Merge merge Clients
|
||||
func (clients *Clients) Merge(other *Clients) ([]Client, []Client, []Client) {
|
||||
current := make(map[string]Client)
|
||||
for _, client := range clients.Clients {
|
||||
current[client.Name] = client
|
||||
}
|
||||
|
||||
expected := make(map[string]Client)
|
||||
for _, client := range other.Clients {
|
||||
expected[client.Name] = client
|
||||
}
|
||||
|
||||
var adds []Client
|
||||
var removes []Client
|
||||
var updates []Client
|
||||
|
||||
for _, cl := range expected {
|
||||
if oc, ok := current[cl.Name]; ok {
|
||||
if !cl.Equals(&oc) {
|
||||
updates = append(updates, cl)
|
||||
}
|
||||
delete(current, cl.Name)
|
||||
} else {
|
||||
adds = append(adds, cl)
|
||||
}
|
||||
}
|
||||
|
||||
for _, rr := range current {
|
||||
removes = append(removes, rr)
|
||||
}
|
||||
|
||||
return adds, updates, removes
|
||||
}
|
||||
|
||||
// ClientUpdate API struct
|
||||
type ClientUpdate struct {
|
||||
Name string `json:"name"`
|
||||
Data Client `json:"data"`
|
||||
}
|
||||
|
||||
func equals(a []string, b []string) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
for i, v := range a {
|
||||
if v != b[i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// InstallConfig AdguardHome install config
|
||||
type InstallConfig struct {
|
||||
Web InstallPort `json:"web"`
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
func TestTypes(t *testing.T) {
|
||||
func TestSync(t *testing.T) {
|
||||
RegisterFailHandler(Fail)
|
||||
RunSpecs(t, "Types Suite")
|
||||
}
|
||||
|
||||
@@ -1,455 +1,38 @@
|
||||
package types_test
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net"
|
||||
"os"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
"github.com/bakito/adguardhome-sync/pkg/versions"
|
||||
"github.com/google/uuid"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Types", func() {
|
||||
var (
|
||||
url string
|
||||
apiPath string
|
||||
)
|
||||
var _ = Describe("AdGuardInstance", func() {
|
||||
var inst types.AdGuardInstance
|
||||
|
||||
BeforeEach(func() {
|
||||
url = "https://" + uuid.NewString()
|
||||
apiPath = "/" + uuid.NewString()
|
||||
inst = types.AdGuardInstance{}
|
||||
})
|
||||
|
||||
Context("FilteringStatus", func() {
|
||||
It("should correctly parse json", func() {
|
||||
b, err := os.ReadFile("../..//testdata/filtering-status.json")
|
||||
fs := &types.FilteringStatus{}
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
err = json.Unmarshal(b, fs)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
|
||||
Context("Filters", func() {
|
||||
Context("Merge", func() {
|
||||
var (
|
||||
originFilters types.Filters
|
||||
replicaFilters types.Filters
|
||||
)
|
||||
BeforeEach(func() {
|
||||
originFilters = types.Filters{}
|
||||
replicaFilters = types.Filters{}
|
||||
})
|
||||
|
||||
It("should add a missing filter", func() {
|
||||
originFilters = append(originFilters, types.Filter{URL: url})
|
||||
a, u, d := replicaFilters.Merge(originFilters)
|
||||
Ω(a).Should(HaveLen(1))
|
||||
Ω(u).Should(BeEmpty())
|
||||
Ω(d).Should(BeEmpty())
|
||||
|
||||
Ω(a[0].URL).Should(Equal(url))
|
||||
})
|
||||
|
||||
It("should remove additional filter", func() {
|
||||
replicaFilters = append(replicaFilters, types.Filter{URL: url})
|
||||
a, u, d := replicaFilters.Merge(originFilters)
|
||||
Ω(a).Should(BeEmpty())
|
||||
Ω(u).Should(BeEmpty())
|
||||
Ω(d).Should(HaveLen(1))
|
||||
|
||||
Ω(d[0].URL).Should(Equal(url))
|
||||
})
|
||||
|
||||
It("should update existing filter when enabled differs", func() {
|
||||
enabled := true
|
||||
originFilters = append(originFilters, types.Filter{URL: url, Enabled: enabled})
|
||||
replicaFilters = append(replicaFilters, types.Filter{URL: url, Enabled: !enabled})
|
||||
a, u, d := replicaFilters.Merge(originFilters)
|
||||
Ω(a).Should(BeEmpty())
|
||||
Ω(u).Should(HaveLen(1))
|
||||
Ω(d).Should(BeEmpty())
|
||||
|
||||
Ω(u[0].Enabled).Should(Equal(enabled))
|
||||
})
|
||||
|
||||
It("should update existing filter when name differs", func() {
|
||||
name1 := uuid.NewString()
|
||||
name2 := uuid.NewString()
|
||||
originFilters = append(originFilters, types.Filter{URL: url, Name: name1})
|
||||
replicaFilters = append(replicaFilters, types.Filter{URL: url, Name: name2})
|
||||
a, u, d := replicaFilters.Merge(originFilters)
|
||||
Ω(a).Should(BeEmpty())
|
||||
Ω(u).Should(HaveLen(1))
|
||||
Ω(d).Should(BeEmpty())
|
||||
|
||||
Ω(u[0].Name).Should(Equal(name1))
|
||||
})
|
||||
|
||||
It("should have no changes", func() {
|
||||
originFilters = append(originFilters, types.Filter{URL: url})
|
||||
replicaFilters = append(replicaFilters, types.Filter{URL: url})
|
||||
a, u, d := replicaFilters.Merge(originFilters)
|
||||
Ω(a).Should(BeEmpty())
|
||||
Ω(u).Should(BeEmpty())
|
||||
Ω(d).Should(BeEmpty())
|
||||
})
|
||||
})
|
||||
})
|
||||
Context("AdGuardInstance", func() {
|
||||
It("should build a key with url and api apiPath", func() {
|
||||
i := &types.AdGuardInstance{URL: url, APIPath: apiPath}
|
||||
Ω(i.Key()).Should(Equal(url + "#" + apiPath))
|
||||
})
|
||||
})
|
||||
Context("RewriteEntry", func() {
|
||||
It("should build a key with url and api apiPath", func() {
|
||||
domain := uuid.NewString()
|
||||
answer := uuid.NewString()
|
||||
re := &types.RewriteEntry{Domain: domain, Answer: answer}
|
||||
Ω(re.Key()).Should(Equal(domain + "#" + answer))
|
||||
})
|
||||
})
|
||||
Context("QueryLogConfig", func() {
|
||||
Context("Equal", func() {
|
||||
var (
|
||||
a *types.QueryLogConfig
|
||||
b *types.QueryLogConfig
|
||||
)
|
||||
BeforeEach(func() {
|
||||
a = &types.QueryLogConfig{}
|
||||
b = &types.QueryLogConfig{}
|
||||
})
|
||||
It("should be equal", func() {
|
||||
a.Enabled = true
|
||||
a.Interval = 1
|
||||
a.AnonymizeClientIP = true
|
||||
b.Enabled = true
|
||||
b.Interval = 1
|
||||
b.AnonymizeClientIP = true
|
||||
Ω(a.Equals(b)).Should(BeTrue())
|
||||
})
|
||||
It("should not be equal when enabled differs", func() {
|
||||
a.Enabled = true
|
||||
b.Enabled = false
|
||||
Ω(a.Equals(b)).ShouldNot(BeTrue())
|
||||
})
|
||||
It("should not be equal when interval differs", func() {
|
||||
a.Interval = 1
|
||||
b.Interval = 2
|
||||
Ω(a.Equals(b)).ShouldNot(BeTrue())
|
||||
})
|
||||
It("should not be equal when anonymizeClientIP differs", func() {
|
||||
a.AnonymizeClientIP = true
|
||||
b.AnonymizeClientIP = false
|
||||
Ω(a.Equals(b)).ShouldNot(BeTrue())
|
||||
})
|
||||
})
|
||||
})
|
||||
Context("RewriteEntries", func() {
|
||||
Context("Merge", func() {
|
||||
var (
|
||||
originRE types.RewriteEntries
|
||||
replicaRE types.RewriteEntries
|
||||
domain string
|
||||
)
|
||||
BeforeEach(func() {
|
||||
originRE = types.RewriteEntries{}
|
||||
replicaRE = types.RewriteEntries{}
|
||||
domain = uuid.NewString()
|
||||
})
|
||||
|
||||
It("should add a missing rewrite entry", func() {
|
||||
originRE = append(originRE, types.RewriteEntry{Domain: domain})
|
||||
a, r, d := replicaRE.Merge(&originRE)
|
||||
Ω(a).Should(HaveLen(1))
|
||||
Ω(r).Should(BeEmpty())
|
||||
Ω(d).Should(BeEmpty())
|
||||
|
||||
Ω(a[0].Domain).Should(Equal(domain))
|
||||
})
|
||||
|
||||
It("should remove additional ewrite entry", func() {
|
||||
replicaRE = append(replicaRE, types.RewriteEntry{Domain: domain})
|
||||
a, r, d := replicaRE.Merge(&originRE)
|
||||
Ω(a).Should(BeEmpty())
|
||||
Ω(r).Should(HaveLen(1))
|
||||
Ω(d).Should(BeEmpty())
|
||||
|
||||
Ω(r[0].Domain).Should(Equal(domain))
|
||||
})
|
||||
|
||||
It("should have no changes", func() {
|
||||
originRE = append(originRE, types.RewriteEntry{Domain: domain})
|
||||
replicaRE = append(replicaRE, types.RewriteEntry{Domain: domain})
|
||||
a, r, d := replicaRE.Merge(&originRE)
|
||||
Ω(a).Should(BeEmpty())
|
||||
Ω(r).Should(BeEmpty())
|
||||
Ω(d).Should(BeEmpty())
|
||||
})
|
||||
|
||||
It("should remove target duplicate", func() {
|
||||
originRE = append(originRE, types.RewriteEntry{Domain: domain})
|
||||
replicaRE = append(replicaRE, types.RewriteEntry{Domain: domain})
|
||||
replicaRE = append(replicaRE, types.RewriteEntry{Domain: domain})
|
||||
a, r, d := replicaRE.Merge(&originRE)
|
||||
Ω(a).Should(BeEmpty())
|
||||
Ω(r).Should(HaveLen(1))
|
||||
Ω(d).Should(BeEmpty())
|
||||
})
|
||||
|
||||
It("should remove target duplicate", func() {
|
||||
originRE = append(originRE, types.RewriteEntry{Domain: domain})
|
||||
originRE = append(originRE, types.RewriteEntry{Domain: domain})
|
||||
replicaRE = append(replicaRE, types.RewriteEntry{Domain: domain})
|
||||
a, r, d := replicaRE.Merge(&originRE)
|
||||
Ω(a).Should(BeEmpty())
|
||||
Ω(r).Should(BeEmpty())
|
||||
Ω(d).Should(HaveLen(1))
|
||||
})
|
||||
})
|
||||
})
|
||||
Context("UserRules", func() {
|
||||
It("should join the rules correctly", func() {
|
||||
r1 := uuid.NewString()
|
||||
r2 := uuid.NewString()
|
||||
ur := types.UserRules([]string{r1, r2})
|
||||
Ω(ur.String()).Should(Equal(r1 + "\n" + r2))
|
||||
})
|
||||
It("should return a string for versions <= "+versions.LastStringCustomRules, func() {
|
||||
r1 := uuid.NewString()
|
||||
r2 := uuid.NewString()
|
||||
pl := types.UserRules([]string{r1, r2}).ToPayload(versions.LastStringCustomRules)
|
||||
Ω(pl).Should(BeAssignableToTypeOf(""))
|
||||
})
|
||||
It("should return a struct for versions > "+versions.IncompatibleAPI, func() {
|
||||
r1 := uuid.NewString()
|
||||
r2 := uuid.NewString()
|
||||
pl := types.UserRules([]string{r1, r2}).ToPayload(versions.FixedIncompatibleAPI)
|
||||
Ω(pl).Should(BeAssignableToTypeOf(&types.UserRulesRequest{}))
|
||||
})
|
||||
})
|
||||
Context("UserRulesRequest", func() {
|
||||
It("should join the rules correctly", func() {
|
||||
r1 := uuid.NewString()
|
||||
r2 := uuid.NewString()
|
||||
urr := types.UserRulesRequest{Rules: []string{r1, r2}}
|
||||
Ω(urr.String()).Should(Equal(r1 + "\n" + r2))
|
||||
})
|
||||
})
|
||||
Context("Config", func() {
|
||||
var cfg *types.Config
|
||||
Context("Init", func() {
|
||||
BeforeEach(func() {
|
||||
cfg = &types.Config{}
|
||||
inst.URL = "https://localhost:3000"
|
||||
})
|
||||
Context("UniqueReplicas", func() {
|
||||
It("should be empty if noting defined", func() {
|
||||
r := cfg.UniqueReplicas()
|
||||
Ω(r).Should(BeEmpty())
|
||||
})
|
||||
It("should be empty if replica url is not set", func() {
|
||||
cfg.Replica = &types.AdGuardInstance{URL: ""}
|
||||
r := cfg.UniqueReplicas()
|
||||
Ω(r).Should(BeEmpty())
|
||||
})
|
||||
It("should be empty if replicas url is not set", func() {
|
||||
cfg.Replicas = []types.AdGuardInstance{{URL: ""}}
|
||||
r := cfg.UniqueReplicas()
|
||||
Ω(r).Should(BeEmpty())
|
||||
})
|
||||
It("should return only one replica if same url and apiPath", func() {
|
||||
cfg.Replica = &types.AdGuardInstance{URL: url, APIPath: apiPath}
|
||||
cfg.Replicas = []types.AdGuardInstance{{URL: url, APIPath: apiPath}, {URL: url, APIPath: apiPath}}
|
||||
r := cfg.UniqueReplicas()
|
||||
Ω(r).Should(HaveLen(1))
|
||||
})
|
||||
It("should return 3 one replicas if urls are different", func() {
|
||||
cfg.Replica = &types.AdGuardInstance{URL: url, APIPath: apiPath}
|
||||
cfg.Replicas = []types.AdGuardInstance{{URL: url + "1", APIPath: apiPath}, {URL: url, APIPath: apiPath + "1"}}
|
||||
r := cfg.UniqueReplicas()
|
||||
Ω(r).Should(HaveLen(3))
|
||||
})
|
||||
It("should set default api apiPath if not set", func() {
|
||||
cfg.Replica = &types.AdGuardInstance{URL: url}
|
||||
cfg.Replicas = []types.AdGuardInstance{{URL: url + "1"}}
|
||||
r := cfg.UniqueReplicas()
|
||||
Ω(r).Should(HaveLen(2))
|
||||
Ω(r[0].APIPath).Should(Equal(types.DefaultAPIPath))
|
||||
Ω(r[1].APIPath).Should(Equal(types.DefaultAPIPath))
|
||||
})
|
||||
It("should correctly set Host and WebHost if only URL is set", func() {
|
||||
err := inst.Init()
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(inst.Host).Should(Equal("localhost:3000"))
|
||||
Ω(inst.WebHost).Should(Equal("localhost:3000"))
|
||||
Ω(inst.URL).Should(Equal("https://localhost:3000"))
|
||||
Ω(inst.WebURL).Should(Equal("https://localhost:3000"))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Clients", func() {
|
||||
Context("Merge", func() {
|
||||
var (
|
||||
originClients *types.Clients
|
||||
replicaClients types.Clients
|
||||
name string
|
||||
)
|
||||
BeforeEach(func() {
|
||||
originClients = &types.Clients{}
|
||||
replicaClients = types.Clients{}
|
||||
name = uuid.NewString()
|
||||
})
|
||||
|
||||
It("should add a missing client", func() {
|
||||
originClients.Clients = append(originClients.Clients, types.Client{Name: name})
|
||||
a, u, d := replicaClients.Merge(originClients)
|
||||
Ω(a).Should(HaveLen(1))
|
||||
Ω(u).Should(BeEmpty())
|
||||
Ω(d).Should(BeEmpty())
|
||||
|
||||
Ω(a[0].Name).Should(Equal(name))
|
||||
})
|
||||
|
||||
It("should remove additional client", func() {
|
||||
replicaClients.Clients = append(replicaClients.Clients, types.Client{Name: name})
|
||||
a, u, d := replicaClients.Merge(originClients)
|
||||
Ω(a).Should(BeEmpty())
|
||||
Ω(u).Should(BeEmpty())
|
||||
Ω(d).Should(HaveLen(1))
|
||||
|
||||
Ω(d[0].Name).Should(Equal(name))
|
||||
})
|
||||
|
||||
It("should update existing client when name differs", func() {
|
||||
disallowed := true
|
||||
originClients.Clients = append(originClients.Clients, types.Client{Name: name, Disallowed: disallowed})
|
||||
replicaClients.Clients = append(replicaClients.Clients, types.Client{Name: name, Disallowed: !disallowed})
|
||||
a, u, d := replicaClients.Merge(originClients)
|
||||
Ω(a).Should(BeEmpty())
|
||||
Ω(u).Should(HaveLen(1))
|
||||
Ω(d).Should(BeEmpty())
|
||||
|
||||
Ω(u[0].Disallowed).Should(Equal(disallowed))
|
||||
})
|
||||
})
|
||||
})
|
||||
Context("Services", func() {
|
||||
Context("Equals", func() {
|
||||
It("should be equal", func() {
|
||||
s1 := types.Services([]string{"a", "b"})
|
||||
s2 := types.Services([]string{"b", "a"})
|
||||
Ω(s1.Equals(s2)).Should(BeTrue())
|
||||
})
|
||||
It("should not be equal different values", func() {
|
||||
s1 := types.Services([]string{"a", "b"})
|
||||
s2 := types.Services([]string{"B", "a"})
|
||||
Ω(s1.Equals(s2)).ShouldNot(BeTrue())
|
||||
})
|
||||
It("should not be equal different length", func() {
|
||||
s1 := types.Services([]string{"a", "b"})
|
||||
s2 := types.Services([]string{"b", "a", "c"})
|
||||
Ω(s1.Equals(s2)).ShouldNot(BeTrue())
|
||||
})
|
||||
})
|
||||
})
|
||||
Context("DNSConfig", func() {
|
||||
Context("Equals", func() {
|
||||
It("should be equal", func() {
|
||||
dc1 := &types.DNSConfig{Upstreams: []string{"a"}}
|
||||
dc2 := &types.DNSConfig{Upstreams: []string{"a"}}
|
||||
Ω(dc1.Equals(dc2)).Should(BeTrue())
|
||||
})
|
||||
It("should not be equal", func() {
|
||||
dc1 := &types.DNSConfig{Upstreams: []string{"a"}}
|
||||
dc2 := &types.DNSConfig{Upstreams: []string{"b"}}
|
||||
Ω(dc1.Equals(dc2)).ShouldNot(BeTrue())
|
||||
})
|
||||
})
|
||||
})
|
||||
Context("DHCPServerConfig", func() {
|
||||
Context("Equals", func() {
|
||||
It("should be equal", func() {
|
||||
dc1 := &types.DHCPServerConfig{
|
||||
V4: &types.V4ServerConfJSON{
|
||||
GatewayIP: net.IPv4(1, 2, 3, 4),
|
||||
LeaseDuration: 123,
|
||||
RangeStart: net.IPv4(1, 2, 3, 5),
|
||||
RangeEnd: net.IPv4(1, 2, 3, 6),
|
||||
SubnetMask: net.IPv4(255, 255, 255, 0),
|
||||
},
|
||||
}
|
||||
dc2 := &types.DHCPServerConfig{
|
||||
V4: &types.V4ServerConfJSON{
|
||||
GatewayIP: net.IPv4(1, 2, 3, 4),
|
||||
LeaseDuration: 123,
|
||||
RangeStart: net.IPv4(1, 2, 3, 5),
|
||||
RangeEnd: net.IPv4(1, 2, 3, 6),
|
||||
SubnetMask: net.IPv4(255, 255, 255, 0),
|
||||
},
|
||||
}
|
||||
Ω(dc1.Equals(dc2)).Should(BeTrue())
|
||||
})
|
||||
It("should not be equal", func() {
|
||||
dc1 := &types.DHCPServerConfig{
|
||||
V4: &types.V4ServerConfJSON{
|
||||
GatewayIP: net.IPv4(1, 2, 3, 3),
|
||||
LeaseDuration: 123,
|
||||
RangeStart: net.IPv4(1, 2, 3, 5),
|
||||
RangeEnd: net.IPv4(1, 2, 3, 6),
|
||||
SubnetMask: net.IPv4(255, 255, 255, 0),
|
||||
},
|
||||
}
|
||||
dc2 := &types.DHCPServerConfig{
|
||||
V4: &types.V4ServerConfJSON{
|
||||
GatewayIP: net.IPv4(1, 2, 3, 4),
|
||||
LeaseDuration: 123,
|
||||
RangeStart: net.IPv4(1, 2, 3, 5),
|
||||
RangeEnd: net.IPv4(1, 2, 3, 6),
|
||||
SubnetMask: net.IPv4(255, 255, 255, 0),
|
||||
},
|
||||
}
|
||||
Ω(dc1.Equals(dc2)).ShouldNot(BeTrue())
|
||||
})
|
||||
})
|
||||
Context("Clone", func() {
|
||||
It("clone should be equal", func() {
|
||||
dc1 := &types.DHCPServerConfig{
|
||||
V4: &types.V4ServerConfJSON{
|
||||
GatewayIP: net.IPv4(1, 2, 3, 4),
|
||||
LeaseDuration: 123,
|
||||
RangeStart: net.IPv4(1, 2, 3, 5),
|
||||
RangeEnd: net.IPv4(1, 2, 3, 6),
|
||||
SubnetMask: net.IPv4(255, 255, 255, 0),
|
||||
},
|
||||
}
|
||||
Ω(dc1.Clone().Equals(dc1)).Should(BeTrue())
|
||||
})
|
||||
})
|
||||
Context("HasConfig", func() {
|
||||
It("should not have a config", func() {
|
||||
dc1 := &types.DHCPServerConfig{
|
||||
V4: &types.V4ServerConfJSON{},
|
||||
V6: &types.V6ServerConfJSON{},
|
||||
}
|
||||
Ω(dc1.HasConfig()).Should(BeFalse())
|
||||
})
|
||||
It("should not have a v4 config", func() {
|
||||
dc1 := &types.DHCPServerConfig{
|
||||
V4: &types.V4ServerConfJSON{
|
||||
GatewayIP: net.IPv4(1, 2, 3, 4),
|
||||
RangeStart: net.IPv4(1, 2, 3, 5),
|
||||
RangeEnd: net.IPv4(1, 2, 3, 6),
|
||||
SubnetMask: net.IPv4(255, 255, 255, 0),
|
||||
},
|
||||
V6: &types.V6ServerConfJSON{},
|
||||
}
|
||||
Ω(dc1.HasConfig()).Should(BeTrue())
|
||||
})
|
||||
It("should not have a v6 config", func() {
|
||||
dc1 := &types.DHCPServerConfig{
|
||||
V4: &types.V4ServerConfJSON{},
|
||||
V6: &types.V6ServerConfJSON{
|
||||
RangeStart: net.IPv4(1, 2, 3, 5),
|
||||
RangeEnd: net.IPv4(1, 2, 3, 6),
|
||||
},
|
||||
}
|
||||
Ω(dc1.HasConfig()).Should(BeTrue())
|
||||
})
|
||||
It("should correctly set Host and WebHost if URL and WebURL are set", func() {
|
||||
inst.WebURL = "https://127.0.0.1:4000"
|
||||
err := inst.Init()
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(inst.Host).Should(Equal("localhost:3000"))
|
||||
Ω(inst.WebHost).Should(Equal("127.0.0.1:4000"))
|
||||
Ω(inst.WebURL).Should(Equal(inst.WebURL))
|
||||
Ω(inst.URL).Should(Equal("https://localhost:3000"))
|
||||
Ω(inst.WebURL).Should(Equal("https://127.0.0.1:4000"))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
15
pkg/utils/clone.go
Normal file
15
pkg/utils/clone.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package utils
|
||||
|
||||
import "encoding/json"
|
||||
|
||||
func Clone[I interface{}](in I, out I) I {
|
||||
b, _ := json.Marshal(in)
|
||||
_ = json.Unmarshal(b, out)
|
||||
return out
|
||||
}
|
||||
|
||||
func JsonEquals(a interface{}, b interface{}) bool {
|
||||
ja, _ := json.Marshal(a)
|
||||
jb, _ := json.Marshal(b)
|
||||
return string(ja) == string(jb)
|
||||
}
|
||||
14
pkg/utils/ptr.go
Normal file
14
pkg/utils/ptr.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package utils
|
||||
|
||||
import "fmt"
|
||||
|
||||
func Ptr[I interface{}](i I) *I {
|
||||
return &i
|
||||
}
|
||||
|
||||
func PtrToString[I interface{}](i *I) string {
|
||||
if i == nil {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("%v", i)
|
||||
}
|
||||
@@ -4,16 +4,7 @@ import "golang.org/x/mod/semver"
|
||||
|
||||
const (
|
||||
// MinAgh minimal adguardhome version
|
||||
MinAgh = "v0.107.0"
|
||||
// LastStringCustomRules last adguardhome version with string payload custom rules
|
||||
// https://github.com/bakito/adguardhome-sync/issues/99
|
||||
LastStringCustomRules = "v0.107.13"
|
||||
// IncompatibleAPI adguardhome version with incompatible API
|
||||
// https://github.com/bakito/adguardhome-sync/issues/99
|
||||
IncompatibleAPI = "v0.107.14"
|
||||
// FixedIncompatibleAPI adguardhome version with fixed API
|
||||
// https://github.com/bakito/adguardhome-sync/issues/99
|
||||
FixedIncompatibleAPI = "v0.107.15"
|
||||
MinAgh = "v0.107.40"
|
||||
)
|
||||
|
||||
func IsNewerThan(v1 string, v2 string) bool {
|
||||
|
||||
1
testdata/.gitignore
vendored
Normal file
1
testdata/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
docker-compose.yaml
|
||||
22
testdata/blockedservicesschedule-get.json
vendored
Normal file
22
testdata/blockedservicesschedule-get.json
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"schedule": {
|
||||
"time_zone": "Europe/Zurich",
|
||||
"tue": {
|
||||
"start": 0,
|
||||
"end": 86340000
|
||||
},
|
||||
"thu": {
|
||||
"start": 0,
|
||||
"end": 86340000
|
||||
},
|
||||
"sat": {
|
||||
"start": 0,
|
||||
"end": 35940000
|
||||
}
|
||||
},
|
||||
"ids": [
|
||||
"9gag",
|
||||
"dailymotion",
|
||||
"disneyplus"
|
||||
]
|
||||
}
|
||||
6
testdata/e2e/bin/read-latest-replica-config.sh
vendored
Executable file
6
testdata/e2e/bin/read-latest-replica-config.sh
vendored
Executable file
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
echo "## AdGuardHome.yaml of latest replica" >> $GITHUB_STEP_SUMMARY
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
kubectl exec adguardhome-replica-latest -- cat /opt/adguardhome/conf/AdGuardHome.yaml >> $GITHUB_STEP_SUMMARY
|
||||
echo '```' >> $GITHUB_STEP_SUMMARY
|
||||
206
testdata/e2e/resources/AdGuardHome.yaml
vendored
Normal file
206
testdata/e2e/resources/AdGuardHome.yaml
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
http:
|
||||
pprof:
|
||||
port: 6060
|
||||
enabled: false
|
||||
address: 0.0.0.0:3000
|
||||
session_ttl: 720h
|
||||
users:
|
||||
- name: username
|
||||
password: $2a$10$yrrX.EvDpUUnZxr74u6euOMeF6dPFd/mEyohDq1LkpH76JyeObPBm
|
||||
auth_attempts: 5
|
||||
block_auth_min: 15
|
||||
http_proxy: ""
|
||||
language: en
|
||||
theme: auto
|
||||
dns:
|
||||
bind_hosts:
|
||||
- 0.0.0.0
|
||||
port: 53
|
||||
anonymize_client_ip: false
|
||||
ratelimit: 20
|
||||
ratelimit_whitelist: [ ]
|
||||
refuse_any: true
|
||||
upstream_dns:
|
||||
- https://dns10.quad9.net/dns-query
|
||||
upstream_dns_file: ""
|
||||
bootstrap_dns:
|
||||
- 1.1.1.1:53
|
||||
fallback_dns: [ ]
|
||||
all_servers: false
|
||||
fastest_addr: false
|
||||
fastest_timeout: 1s
|
||||
allowed_clients: [ ]
|
||||
disallowed_clients: [ ]
|
||||
blocked_hosts:
|
||||
- version.bind
|
||||
- id.server
|
||||
- hostname.bind
|
||||
trusted_proxies:
|
||||
- 127.0.0.0/8
|
||||
- ::1/128
|
||||
cache_size: 4194304
|
||||
cache_ttl_min: 0
|
||||
cache_ttl_max: 0
|
||||
cache_optimistic: true
|
||||
bogus_nxdomain: [ ]
|
||||
aaaa_disabled: false
|
||||
enable_dnssec: false
|
||||
edns_client_subnet:
|
||||
custom_ip: ""
|
||||
enabled: false
|
||||
use_custom: false
|
||||
max_goroutines: 300
|
||||
handle_ddr: true
|
||||
ipset: [ ]
|
||||
ipset_file: ""
|
||||
bootstrap_prefer_ipv6: false
|
||||
upstream_timeout: 10s
|
||||
private_networks: [ ]
|
||||
use_private_ptr_resolvers: true
|
||||
local_ptr_upstreams: [ ]
|
||||
use_dns64: false
|
||||
dns64_prefixes: [ ]
|
||||
serve_http3: false
|
||||
use_http3_upstreams: false
|
||||
tls:
|
||||
enabled: false
|
||||
server_name: ""
|
||||
force_https: false
|
||||
port_https: 443
|
||||
port_dns_over_tls: 853
|
||||
port_dns_over_quic: 853
|
||||
port_dnscrypt: 0
|
||||
dnscrypt_config_file: ""
|
||||
allow_unencrypted_doh: false
|
||||
certificate_chain: ""
|
||||
private_key: ""
|
||||
certificate_path: ""
|
||||
private_key_path: ""
|
||||
strict_sni_check: false
|
||||
querylog:
|
||||
ignored: [ ]
|
||||
interval: 6h
|
||||
size_memory: 1000
|
||||
enabled: true
|
||||
file_enabled: true
|
||||
statistics:
|
||||
ignored: [ ]
|
||||
interval: 24h
|
||||
enabled: true
|
||||
filters:
|
||||
- enabled: true
|
||||
url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
|
||||
name: AdGuard DNS filter
|
||||
id: 1
|
||||
- enabled: true
|
||||
url: https://adaway.org/hosts.txt
|
||||
name: AdAway Default Blocklist
|
||||
id: 2
|
||||
whitelist_filters: [ ]
|
||||
user_rules:
|
||||
- '||metrics2.data.hicloud.com^$important'
|
||||
- '||www.curiouscorrespondence.com^$important'
|
||||
- '||bluewizard.com^$important'
|
||||
- '||facebook.com^$important'
|
||||
dhcp:
|
||||
enabled: false
|
||||
interface_name: eth0
|
||||
local_domain_name: lan
|
||||
dhcpv4:
|
||||
gateway_ip: 1.2.3.4
|
||||
subnet_mask: 255.255.0.0
|
||||
range_start: 1.2.3.5
|
||||
range_end: 1.2.3.56
|
||||
lease_duration: 86400
|
||||
icmp_timeout_msec: 1000
|
||||
options: [ ]
|
||||
dhcpv6:
|
||||
range_start: ""
|
||||
lease_duration: 86400
|
||||
ra_slaac_only: false
|
||||
ra_allow_slaac: false
|
||||
filtering:
|
||||
blocking_ipv4: ""
|
||||
blocking_ipv6: ""
|
||||
blocked_services:
|
||||
schedule:
|
||||
time_zone: Europe/Zurich
|
||||
tue:
|
||||
start: 0s
|
||||
end: 23h59m
|
||||
thu:
|
||||
start: 0s
|
||||
end: 23h59m
|
||||
sat:
|
||||
start: 0s
|
||||
end: 9h59m
|
||||
ids:
|
||||
- 9gag
|
||||
- dailymotion
|
||||
- disneyplus
|
||||
protection_disabled_until: null
|
||||
safe_search:
|
||||
enabled: true
|
||||
bing: true
|
||||
duckduckgo: true
|
||||
google: true
|
||||
pixabay: true
|
||||
yandex: true
|
||||
youtube: true
|
||||
blocking_mode: default
|
||||
parental_block_host: family-block.dns.adguard.com
|
||||
safebrowsing_block_host: standard-block.dns.adguard.com
|
||||
rewrites: [ ]
|
||||
safebrowsing_cache_size: 1048576
|
||||
safesearch_cache_size: 1048576
|
||||
parental_cache_size: 1048576
|
||||
cache_time: 30
|
||||
filters_update_interval: 24
|
||||
blocked_response_ttl: 10
|
||||
filtering_enabled: true
|
||||
parental_enabled: true
|
||||
safebrowsing_enabled: true
|
||||
protection_enabled: true
|
||||
clients:
|
||||
runtime_sources:
|
||||
whois: true
|
||||
arp: true
|
||||
rdns: true
|
||||
dhcp: true
|
||||
hosts: true
|
||||
persistent:
|
||||
- name: Device 1
|
||||
tags:
|
||||
- device_1
|
||||
ids:
|
||||
- 2.2.2.2
|
||||
blocked_services:
|
||||
schedule:
|
||||
time_zone: Europe/Zurich
|
||||
ids:
|
||||
- facebook
|
||||
- mail_ru
|
||||
- qq
|
||||
- vk
|
||||
- ok
|
||||
upstreams: [ ]
|
||||
use_global_settings: true
|
||||
filtering_enabled: false
|
||||
parental_enabled: false
|
||||
safebrowsing_enabled: false
|
||||
use_global_blocked_services: false
|
||||
ignore_querylog: false
|
||||
ignore_statistics: false
|
||||
log:
|
||||
file: ""
|
||||
max_backups: 0
|
||||
max_size: 100
|
||||
max_age: 3
|
||||
compress: false
|
||||
local_time: false
|
||||
verbose: false
|
||||
os:
|
||||
group: ""
|
||||
user: ""
|
||||
rlimit_nofile: 0
|
||||
schema_version: 27
|
||||
4
testdata/e2e/templates/NOTES.txt
vendored
Normal file
4
testdata/e2e/templates/NOTES.txt
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
Installed adguardhome-sync end-2-end test with {{ len .Values.replica.versions }} replica instances.
|
||||
{{- range $_, $version := .Values.replica.versions }}
|
||||
- {{ $version }}
|
||||
{{- end }}
|
||||
168
testdata/e2e/templates/configmap-origin.yaml
vendored
168
testdata/e2e/templates/configmap-origin.yaml
vendored
@@ -5,170 +5,4 @@ metadata:
|
||||
namespace: {{ .Release.Namespace }}
|
||||
data:
|
||||
AdGuardHome.yaml: |
|
||||
bind_host: 0.0.0.0
|
||||
bind_port: 3000
|
||||
beta_bind_port: 0
|
||||
users:
|
||||
- name: username
|
||||
password: $2a$10$yrrX.EvDpUUnZxr74u6euOMeF6dPFd/mEyohDq1LkpH76JyeObPBm
|
||||
auth_attempts: 5
|
||||
block_auth_min: 15
|
||||
http_proxy: ""
|
||||
language: en
|
||||
debug_pprof: false
|
||||
web_session_ttl: 720
|
||||
dns:
|
||||
bind_hosts:
|
||||
- 0.0.0.0
|
||||
port: 53
|
||||
statistics_interval: 1
|
||||
querylog_enabled: true
|
||||
querylog_file_enabled: true
|
||||
querylog_interval: 6h
|
||||
querylog_size_memory: 1000
|
||||
anonymize_client_ip: false
|
||||
protection_enabled: true
|
||||
blocking_mode: default
|
||||
blocking_ipv4: ""
|
||||
blocking_ipv6: ""
|
||||
blocked_response_ttl: 10
|
||||
parental_block_host: family-block.dns.adguard.com
|
||||
safebrowsing_block_host: standard-block.dns.adguard.com
|
||||
ratelimit: 20
|
||||
ratelimit_whitelist: []
|
||||
refuse_any: true
|
||||
upstream_dns:
|
||||
- https://dns10.quad9.net/dns-query
|
||||
upstream_dns_file: ""
|
||||
bootstrap_dns:
|
||||
- 1.1.1.1:53
|
||||
all_servers: false
|
||||
fastest_addr: false
|
||||
fastest_timeout: 1s
|
||||
allowed_clients: []
|
||||
disallowed_clients: []
|
||||
blocked_hosts:
|
||||
- version.bind
|
||||
- id.server
|
||||
- hostname.bind
|
||||
trusted_proxies:
|
||||
- 127.0.0.0/8
|
||||
- ::1/128
|
||||
cache_size: 4194304
|
||||
cache_ttl_min: 0
|
||||
cache_ttl_max: 0
|
||||
cache_optimistic: true
|
||||
bogus_nxdomain: []
|
||||
aaaa_disabled: false
|
||||
enable_dnssec: false
|
||||
edns_client_subnet: false
|
||||
max_goroutines: 300
|
||||
handle_ddr: true
|
||||
ipset: []
|
||||
ipset_file: ""
|
||||
filtering_enabled: true
|
||||
filters_update_interval: 12
|
||||
parental_enabled: true
|
||||
safesearch_enabled: true
|
||||
safebrowsing_enabled: true
|
||||
safebrowsing_cache_size: 1048576
|
||||
safesearch_cache_size: 1048576
|
||||
parental_cache_size: 1048576
|
||||
cache_time: 30
|
||||
rewrites:
|
||||
- domain: foo.bar.com
|
||||
answer: 1.2.3.4
|
||||
blocked_services:
|
||||
- 9gag
|
||||
- dailymotion
|
||||
upstream_timeout: 10s
|
||||
private_networks: []
|
||||
use_private_ptr_resolvers: true
|
||||
local_ptr_upstreams: []
|
||||
serve_http3: false
|
||||
use_http3_upstreams: false
|
||||
tls:
|
||||
enabled: false
|
||||
server_name: ""
|
||||
force_https: false
|
||||
port_https: 443
|
||||
port_dns_over_tls: 853
|
||||
port_dns_over_quic: 853
|
||||
port_dnscrypt: 0
|
||||
dnscrypt_config_file: ""
|
||||
allow_unencrypted_doh: false
|
||||
strict_sni_check: false
|
||||
certificate_chain: ""
|
||||
private_key: ""
|
||||
certificate_path: ""
|
||||
private_key_path: ""
|
||||
filters:
|
||||
- enabled: true
|
||||
url: https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt
|
||||
name: AdGuard DNS filter
|
||||
id: 1
|
||||
- enabled: true
|
||||
url: https://adaway.org/hosts.txt
|
||||
name: AdAway Default Blocklist
|
||||
id: 2
|
||||
whitelist_filters: []
|
||||
user_rules:
|
||||
- '||metrics2.data.hicloud.com^$important'
|
||||
- '||www.curiouscorrespondence.com^$important'
|
||||
- '||bluewizard.com^$important'
|
||||
- '||facebook.com^$important'
|
||||
dhcp:
|
||||
enabled: false
|
||||
interface_name: eth0
|
||||
local_domain_name: lan
|
||||
dhcpv4:
|
||||
gateway_ip: 1.2.3.4
|
||||
subnet_mask: 255.255.0.0
|
||||
range_start: 1.2.3.5
|
||||
range_end: 1.2.3.56
|
||||
lease_duration: 86400
|
||||
icmp_timeout_msec: 1000
|
||||
options: []
|
||||
dhcpv6:
|
||||
range_start: ""
|
||||
lease_duration: 86400
|
||||
ra_slaac_only: false
|
||||
ra_allow_slaac: false
|
||||
clients:
|
||||
runtime_sources:
|
||||
whois: true
|
||||
arp: true
|
||||
rdns: true
|
||||
dhcp: true
|
||||
hosts: true
|
||||
persistent:
|
||||
- name: Device 1
|
||||
tags:
|
||||
- device_1
|
||||
ids:
|
||||
- 2.2.2.2
|
||||
blocked_services:
|
||||
- facebook
|
||||
- ok
|
||||
- vk
|
||||
- mail_ru
|
||||
- qq
|
||||
upstreams: []
|
||||
use_global_settings: true
|
||||
filtering_enabled: false
|
||||
parental_enabled: false
|
||||
safesearch_enabled: false
|
||||
safebrowsing_enabled: false
|
||||
use_global_blocked_services: false
|
||||
log_file: ""
|
||||
log_max_backups: 0
|
||||
log_max_size: 100
|
||||
log_max_age: 3
|
||||
log_compress: false
|
||||
log_localtime: false
|
||||
verbose: false
|
||||
os:
|
||||
group: ""
|
||||
user: ""
|
||||
rlimit_nofile: 0
|
||||
schema_version: 14
|
||||
{{- .Files.Get "resources/AdGuardHome.yaml" | nindent 4 }}
|
||||
20
testdata/e2e/templates/configmap-sync.yaml
vendored
20
testdata/e2e/templates/configmap-sync.yaml
vendored
@@ -2,16 +2,16 @@ apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: sync-conf
|
||||
namespace: {{ .Release.Namespace }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
data:
|
||||
API_PORT: "0"
|
||||
LOG_LEVEL: info
|
||||
ORIGIN_URL: http://service-origin.{{ $.Release.Namespace }}.svc.cluster.local:3000
|
||||
ORIGIN_PASSWORD: password
|
||||
ORIGIN_USERNAME: username
|
||||
API_PORT: '0'
|
||||
LOG_LEVEL: 'debug'
|
||||
ORIGIN_URL: 'http://service-origin.{{ $.Release.Namespace }}.svc.cluster.local:3000'
|
||||
ORIGIN_PASSWORD: 'password'
|
||||
ORIGIN_USERNAME: 'username'
|
||||
{{ range $i,$version := .Values.replica.versions }}
|
||||
REPLICA{{ $i }}_AUTOSETUP: "true"
|
||||
REPLICA{{ $i }}_URL: http://service-replica-{{ $version | toString | replace "." "-" }}.{{ $.Release.Namespace }}.svc.cluster.local:3000
|
||||
REPLICA{{ $i }}_PASSWORD: password
|
||||
REPLICA{{ $i }}_USERNAME: username
|
||||
REPLICA{{ $i }}_AUTOSETUP: 'true'
|
||||
REPLICA{{ $i }}_URL: 'http://service-replica-{{ $version | toString | replace "." "-" }}.{{ $.Release.Namespace }}.svc.cluster.local:3000'
|
||||
REPLICA{{ $i }}_PASSWORD: 'password'
|
||||
REPLICA{{ $i }}_USERNAME: 'username'
|
||||
{{- end }}
|
||||
|
||||
2
testdata/e2e/templates/rbac.yaml
vendored
2
testdata/e2e/templates/rbac.yaml
vendored
@@ -3,7 +3,6 @@ kind: ServiceAccount
|
||||
metadata:
|
||||
name: agh-e2e
|
||||
namespace: {{ .Release.Namespace }}
|
||||
|
||||
---
|
||||
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
@@ -15,7 +14,6 @@ rules:
|
||||
- apiGroups: [ "" ]
|
||||
resources: [ "pods" ]
|
||||
verbs: [ "get", "watch", "list" ]
|
||||
|
||||
---
|
||||
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
|
||||
4
testdata/e2e/values.yaml
vendored
4
testdata/e2e/values.yaml
vendored
@@ -1,5 +1,5 @@
|
||||
replica:
|
||||
versions:
|
||||
- v0.107.40
|
||||
- v0.107.43
|
||||
- latest
|
||||
- v0.107.13
|
||||
- v0.107.15
|
||||
|
||||
5
testdata/filtering-status.json
vendored
5
testdata/filtering-status.json
vendored
@@ -7,8 +7,7 @@
|
||||
"enabled": true,
|
||||
"url": "https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt",
|
||||
"name": "AdGuard DNS filter",
|
||||
"rules_count": 37330,
|
||||
"last_updated": ""
|
||||
"rules_count": 37330
|
||||
},
|
||||
{
|
||||
"id": 1616956421,
|
||||
@@ -24,4 +23,4 @@
|
||||
"||metrics2.data.hicloud.com^$important",
|
||||
""
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user