Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb1f2d02c5 | ||
|
|
3bd093ceb9 | ||
|
|
05c0eab4a8 | ||
|
|
57745f2953 | ||
|
|
9f5ac14aa1 | ||
|
|
8f2aa58fe8 | ||
|
|
01e23d3b69 | ||
|
|
c2da171c85 | ||
|
|
b44dd16ad8 | ||
|
|
ba00016be8 | ||
|
|
e301f483c6 | ||
|
|
ebf25a8ddf | ||
|
|
56d6644194 | ||
|
|
51401dac81 | ||
|
|
18b07898ea | ||
|
|
223739f4a7 | ||
|
|
02ff6a11f0 | ||
|
|
2bff464f65 | ||
|
|
8fe0fe27ea | ||
|
|
5c00caa296 | ||
|
|
344337a3d5 | ||
|
|
e1287564c3 | ||
|
|
8f61de83bf | ||
|
|
f3810cf241 | ||
|
|
3d385f409e | ||
|
|
19bdd47b3c |
2
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
2
.github/ISSUE_TEMPLATE/bug_report.yaml
vendored
@@ -58,7 +58,7 @@ body:
|
||||
- type: textarea
|
||||
id: logs
|
||||
attributes:
|
||||
label: Relevant log output
|
||||
label: Relevant DEBUG 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`.
|
||||
|
||||
6
.github/workflows/go.yml
vendored
6
.github/workflows/go.yml
vendored
@@ -22,10 +22,8 @@ jobs:
|
||||
with:
|
||||
go-version-file: "go.mod"
|
||||
|
||||
- name: golangci-lint
|
||||
uses: golangci/golangci-lint-action@v6
|
||||
with:
|
||||
skip-cache: true
|
||||
- name: Lint
|
||||
run: make lint
|
||||
|
||||
test:
|
||||
name: test
|
||||
|
||||
209
.golangci.yaml
Normal file
209
.golangci.yaml
Normal file
@@ -0,0 +1,209 @@
|
||||
version: '2'
|
||||
linters:
|
||||
enable:
|
||||
- asciicheck
|
||||
- bidichk
|
||||
- bodyclose
|
||||
- canonicalheader
|
||||
- containedctx
|
||||
- copyloopvar
|
||||
- decorder
|
||||
- dogsled
|
||||
- dupword
|
||||
- durationcheck
|
||||
- err113
|
||||
- errname
|
||||
- errorlint
|
||||
- exptostd
|
||||
- fatcontext
|
||||
- forcetypeassert
|
||||
- gocheckcompilerdirectives
|
||||
- gochecksumtype
|
||||
- gocritic
|
||||
- godot
|
||||
- gomodguard
|
||||
- goprintffuncname
|
||||
- gosmopolitan
|
||||
- grouper
|
||||
- iface
|
||||
- importas
|
||||
- inamedparam
|
||||
- interfacebloat
|
||||
- intrange
|
||||
- loggercheck
|
||||
- makezero
|
||||
- mirror
|
||||
- misspell
|
||||
- nilerr
|
||||
- nilnesserr
|
||||
- noctx
|
||||
- nolintlint
|
||||
- nosprintfhostport
|
||||
- perfsprint
|
||||
- predeclared
|
||||
- promlinter
|
||||
- protogetter
|
||||
- reassign
|
||||
- revive
|
||||
- rowserrcheck
|
||||
- sloglint
|
||||
- spancheck
|
||||
- sqlclosecheck
|
||||
- staticcheck
|
||||
- tagalign
|
||||
- testableexamples
|
||||
- testifylint
|
||||
- thelper
|
||||
- unconvert
|
||||
- unparam
|
||||
- usestdlibvars
|
||||
- usetesting
|
||||
- wastedassign
|
||||
- whitespace
|
||||
- zerologlint
|
||||
disable:
|
||||
- asasalint
|
||||
- contextcheck
|
||||
- cyclop
|
||||
- depguard
|
||||
- dupl
|
||||
- errchkjson
|
||||
- exhaustive
|
||||
- exhaustruct
|
||||
- forbidigo
|
||||
- funlen
|
||||
- ginkgolinter
|
||||
- gochecknoglobals
|
||||
- gochecknoinits
|
||||
- gocognit
|
||||
- goconst
|
||||
- gocyclo
|
||||
- godox
|
||||
- goheader
|
||||
- gomoddirectives
|
||||
- gosec
|
||||
- ireturn
|
||||
- lll
|
||||
- maintidx
|
||||
- musttag
|
||||
- nakedret
|
||||
- nestif
|
||||
- nilnil
|
||||
- nlreturn
|
||||
- nonamedreturns
|
||||
- paralleltest
|
||||
- prealloc
|
||||
- recvcheck
|
||||
- tagliatelle
|
||||
- testpackage
|
||||
- tparallel
|
||||
- varnamelen
|
||||
- wrapcheck
|
||||
- wsl
|
||||
settings:
|
||||
gocritic:
|
||||
enable-all: true
|
||||
disabled-checks:
|
||||
- emptyFallthrough
|
||||
- hugeParam
|
||||
- rangeValCopy
|
||||
- unnamedResult
|
||||
- whyNoLint
|
||||
govet:
|
||||
disable:
|
||||
- fieldalignment
|
||||
- shadow
|
||||
enable-all: true
|
||||
misspell:
|
||||
locale: US
|
||||
revive:
|
||||
enable-all-rules: true
|
||||
rules:
|
||||
- name: add-constant
|
||||
disabled: true
|
||||
- name: cognitive-complexity
|
||||
disabled: true
|
||||
- name: cyclomatic
|
||||
disabled: true
|
||||
- name: deep-exit
|
||||
disabled: true
|
||||
- name: dot-imports
|
||||
severity: warning
|
||||
disabled: false
|
||||
exclude: [""]
|
||||
arguments:
|
||||
- allowedPackages: ["github.com/onsi/ginkgo/v2", "github.com/onsi/gomega"]
|
||||
- name: empty-block
|
||||
disabled: true
|
||||
- name: exported
|
||||
disabled: true
|
||||
- name: filename-format
|
||||
arguments:
|
||||
- ^[a-z][-0-9_a-z]*(?:\.gen)?\.go$
|
||||
- name: flag-parameter
|
||||
disabled: true
|
||||
- name: function-length
|
||||
disabled: true
|
||||
- name: function-result-limit
|
||||
disabled: true
|
||||
- name: import-shadowing
|
||||
disabled: true
|
||||
- name: line-length-limit
|
||||
disabled: true
|
||||
- name: max-control-nesting
|
||||
disabled: true
|
||||
- name: max-public-structs
|
||||
disabled: true
|
||||
- name: nested-structs
|
||||
disabled: true
|
||||
- name: package-comments
|
||||
disabled: true
|
||||
- name: unused-parameter
|
||||
disabled: true
|
||||
- name: unused-receiver
|
||||
disabled: true
|
||||
staticcheck:
|
||||
checks:
|
||||
- 'all'
|
||||
- '-ST1000'
|
||||
exclusions:
|
||||
generated: lax
|
||||
presets:
|
||||
- common-false-positives
|
||||
- legacy
|
||||
- std-error-handling
|
||||
rules:
|
||||
- linters:
|
||||
- err113
|
||||
text: do not define dynamic errors, use wrapped static errors instead
|
||||
- linters:
|
||||
- forbidigo
|
||||
path: ^internal/cmds/
|
||||
- linters:
|
||||
- forcetypeassert
|
||||
path: _test\.go$
|
||||
- linters:
|
||||
- forbidigo
|
||||
path: assets/scripts/generate-commit.go
|
||||
formatters:
|
||||
enable:
|
||||
- gci
|
||||
- gofmt
|
||||
- gofumpt
|
||||
- goimports
|
||||
- golines
|
||||
settings:
|
||||
gci:
|
||||
sections:
|
||||
- standard
|
||||
- default
|
||||
- prefix(github.com/bakito/adguardhome-sync)
|
||||
gofumpt:
|
||||
module-path: github.com/bakito/adguardhome-sync
|
||||
extra-rules: true
|
||||
goimports:
|
||||
local-prefixes:
|
||||
- github.com/bakito/adguardhome-sync
|
||||
golines:
|
||||
max-len: 128
|
||||
tab-len: 4
|
||||
@@ -1,37 +0,0 @@
|
||||
run:
|
||||
timeout: 5m
|
||||
|
||||
linters:
|
||||
enable:
|
||||
- asciicheck
|
||||
- bodyclose
|
||||
- dogsled
|
||||
- durationcheck
|
||||
- errcheck
|
||||
- errorlint
|
||||
- gci
|
||||
- gofmt
|
||||
- gofumpt
|
||||
- goimports
|
||||
- gosec
|
||||
- gosimple
|
||||
- govet
|
||||
- importas
|
||||
- ineffassign
|
||||
- misspell
|
||||
- nakedret
|
||||
- nolintlint
|
||||
- staticcheck
|
||||
- unconvert
|
||||
- unparam
|
||||
- unused
|
||||
linters-settings:
|
||||
gosec:
|
||||
# Exclude generated files
|
||||
exclude-generated: true
|
||||
excludes:
|
||||
- G601 # not applicable in go 1.22 anymore
|
||||
gofmt:
|
||||
# simplify code: gofmt with `-s` option, true by default
|
||||
simplify: true
|
||||
|
||||
14
.toolbox.mk
14
.toolbox.mk
@@ -23,15 +23,15 @@ TB_SEMVER ?= $(TB_LOCALBIN)/semver
|
||||
# renovate: packageName=k8s.io/code-generator/cmd/deepcopy-gen
|
||||
TB_DEEPCOPY_GEN_VERSION ?= v0.32.3
|
||||
# renovate: packageName=mvdan.cc/gofumpt
|
||||
TB_GOFUMPT_VERSION ?= v0.7.0
|
||||
# renovate: packageName=github.com/golangci/golangci-lint/cmd/golangci-lint
|
||||
TB_GOLANGCI_LINT_VERSION ?= v1.64.7
|
||||
TB_GOFUMPT_VERSION ?= v0.8.0
|
||||
# renovate: packageName=github.com/golangci/golangci-lint/v2/cmd/golangci-lint
|
||||
TB_GOLANGCI_LINT_VERSION ?= v2.1.2
|
||||
# renovate: packageName=github.com/segmentio/golines
|
||||
TB_GOLINES_VERSION ?= v0.12.2
|
||||
# renovate: packageName=github.com/goreleaser/goreleaser/v2
|
||||
TB_GORELEASER_VERSION ?= v2.8.0
|
||||
TB_GORELEASER_VERSION ?= v2.8.2
|
||||
# renovate: packageName=go.uber.org/mock/mockgen
|
||||
TB_MOCKGEN_VERSION ?= v0.5.0
|
||||
TB_MOCKGEN_VERSION ?= v0.5.1
|
||||
# renovate: packageName=github.com/oapi-codegen/oapi-codegen/v2/cmd/oapi-codegen
|
||||
TB_OAPI_CODEGEN_VERSION ?= v2.4.1
|
||||
# renovate: packageName=github.com/bakito/semver
|
||||
@@ -53,7 +53,7 @@ $(TB_GOFUMPT): $(TB_LOCALBIN)
|
||||
.PHONY: tb.golangci-lint
|
||||
tb.golangci-lint: $(TB_GOLANGCI_LINT) ## Download golangci-lint locally if necessary.
|
||||
$(TB_GOLANGCI_LINT): $(TB_LOCALBIN)
|
||||
test -s $(TB_LOCALBIN)/golangci-lint || GOBIN=$(TB_LOCALBIN) go install github.com/golangci/golangci-lint/cmd/golangci-lint@$(TB_GOLANGCI_LINT_VERSION)
|
||||
test -s $(TB_LOCALBIN)/golangci-lint || GOBIN=$(TB_LOCALBIN) go install github.com/golangci/golangci-lint/v2/cmd/golangci-lint@$(TB_GOLANGCI_LINT_VERSION)
|
||||
.PHONY: tb.golines
|
||||
tb.golines: $(TB_GOLINES) ## Download golines locally if necessary.
|
||||
$(TB_GOLINES): $(TB_LOCALBIN)
|
||||
@@ -95,7 +95,7 @@ tb.update: tb.reset
|
||||
toolbox makefile --renovate -f $(TB_LOCALDIR)/Makefile \
|
||||
k8s.io/code-generator/cmd/deepcopy-gen@github.com/kubernetes/code-generator \
|
||||
mvdan.cc/gofumpt@github.com/mvdan/gofumpt \
|
||||
github.com/golangci/golangci-lint/cmd/golangci-lint \
|
||||
github.com/golangci/golangci-lint/v2/cmd/golangci-lint \
|
||||
github.com/segmentio/golines \
|
||||
github.com/goreleaser/goreleaser/v2 \
|
||||
go.uber.org/mock/mockgen@github.com/uber-go/mock \
|
||||
|
||||
7
Makefile
7
Makefile
@@ -42,6 +42,7 @@ test-release: tb.goreleaser
|
||||
$(TB_GORELEASER) --skip=publish --snapshot --clean
|
||||
|
||||
start-replica:
|
||||
docker rm -f adguardhome-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
|
||||
|
||||
@@ -49,6 +50,7 @@ copy-replica-config:
|
||||
docker cp adguardhome-replica:/opt/adguardhome/conf/AdGuardHome.yaml tmp/AdGuardHome.yaml
|
||||
|
||||
start-replica2:
|
||||
docker rm -f adguardhome-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
|
||||
|
||||
@@ -71,7 +73,7 @@ kind-test:
|
||||
@./testdata/e2e/bin/install-chart.sh
|
||||
|
||||
# renovate: packageName=AdguardTeam/AdGuardHome
|
||||
ADGUARD_HOME_VERSION ?= v0.107.57
|
||||
ADGUARD_HOME_VERSION ?= v0.107.60
|
||||
|
||||
model: tb.oapi-codegen
|
||||
@mkdir -p tmp
|
||||
@@ -82,3 +84,6 @@ model-diff:
|
||||
go run openapi/main.go $(ADGUARD_HOME_VERSION)
|
||||
go run openapi/main.go
|
||||
diff tmp/schema.yaml tmp/schema-master.yaml
|
||||
|
||||
zellij:
|
||||
zellij -l ./testdata/test-layout.kdl
|
||||
|
||||
124
README.md
124
README.md
@@ -141,9 +141,8 @@ set REPLICA1_USERNAME=username
|
||||
set REPLICA1_PASSWORD=password
|
||||
# set REPLICA1_COOKIE=Replica-Cookie-Name=CCCOOOKKKIIIEEE
|
||||
|
||||
set FEATURES_DHCP=false
|
||||
set FEATURES_DHCP_SERVERCONFIG=false
|
||||
set FEATURES_DHCP_STATICLEASES=false
|
||||
set FEATURES_DHCP_SERVER_CONFIG=false
|
||||
set FEATURES_DHCP_STATIC_LEASES=false
|
||||
|
||||
# run once
|
||||
adguardhome-sync run
|
||||
@@ -182,71 +181,64 @@ services:
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
### env
|
||||
## Config via environment variables
|
||||
|
||||
```yaml
|
||||
---
|
||||
version: "2.1"
|
||||
services:
|
||||
adguardhome-sync:
|
||||
image: ghcr.io/bakito/adguardhome-sync
|
||||
container_name: adguardhome-sync
|
||||
command: run
|
||||
environment:
|
||||
LOG_LEVEL: "info"
|
||||
ORIGIN_URL: "https://192.168.1.2:3000"
|
||||
# ORIGIN_WEB_URL: "https://some-other.url" # used in the web interface (default: <origin-url>
|
||||
For Replicas replace `#` with the index number for the replica. E.g: `REPLICA#_URL` -> `REPLICA1_URL`
|
||||
|
||||
ORIGIN_USERNAME: "username"
|
||||
ORIGIN_PASSWORD: "password"
|
||||
REPLICA1_URL: "http://192.168.1.3"
|
||||
REPLICA1_USERNAME: "username"
|
||||
REPLICA1_PASSWORD: "password"
|
||||
REPLICA2_URL: "http://192.168.1.4"
|
||||
REPLICA2_USERNAME: "username"
|
||||
REPLICA2_PASSWORD: "password"
|
||||
REPLICA2_API_PATH: "/some/path/control"
|
||||
# REPLICA2_WEB_URL: "https://some-other.url" # used in the web interface (default: <replica-url>
|
||||
# REPLICA2_AUTO_SETUP: true # if true, AdGuardHome is automatically initialized.
|
||||
# REPLICA2_INTERFACE_NAME: 'ens18' # use custom dhcp interface name
|
||||
# REPLICA2_DHCP_SERVER_ENABLED: true/false (optional) enables/disables the dhcp server on the replica
|
||||
CRON: "0 */2 * * *" # run every 2 hours
|
||||
RUN_ON_START: "true"
|
||||
# CONTINUE_ON_ERROR: false # If enabled, the synchronisation task will not fail on single errors, but will log the errors and continue
|
||||
|
||||
# Configure the sync API server, disabled if api port is 0
|
||||
API_PORT: 8080
|
||||
# API_DARK_MODE: "true"
|
||||
# API_USERNAME: admin
|
||||
# API_PASSWORD: secret
|
||||
# the directory of the provided tls certs
|
||||
# API_TLS_CERT_DIR: /path/to/certs
|
||||
# the name of the cert file (default: tls.crt)
|
||||
# API_TLS_CERT_NAME: foo.crt
|
||||
# the name of the key file (default: tls.key)
|
||||
# API_TLS_KEY_NAME: bar.key
|
||||
# API_METRICS_ENABLED: "true"
|
||||
|
||||
# Configure sync features; by default all features are enabled.
|
||||
# FEATURES_GENERAL_SETTINGS: "true"
|
||||
# FEATURES_QUERY_LOG_CONFIG: "true"
|
||||
# FEATURES_STATS_CONFIG: "true"
|
||||
# FEATURES_CLIENT_SETTINGS: "true"
|
||||
# FEATURES_SERVICES: "true"
|
||||
# FEATURES_FILTERS: "true"
|
||||
# FEATURES_DHCP_SERVER_CONFIG: "true"
|
||||
# FEATURES_DHCP_STATIC_LEASES: "true"
|
||||
# FEATURES_DNS_SERVER_CONFIG: "true"
|
||||
# FEATURES_DNS_ACCESS_LISTS: "true"
|
||||
# FEATURES_DNS_REWRITES: "true"
|
||||
# FEATURES_THEME: "true" # if false the UI theme is not synced
|
||||
ports:
|
||||
- 8080:8080
|
||||
restart: unless-stopped
|
||||
```
|
||||
| Name | Type | Description |
|
||||
|:-------------------------------------|--------|:----------------------------------------------------------|
|
||||
| ORIGIN_URL (string) | string | URL of adguardhome instance |
|
||||
| ORIGIN_WEB_URL (string) | string | Web URL of adguardhome instance |
|
||||
| ORIGIN_API_PATH (string) | string | API Path |
|
||||
| ORIGIN_USERNAME (string) | string | Adguardhome username |
|
||||
| ORIGIN_PASSWORD (string) | string | Adguardhome password |
|
||||
| ORIGIN_COOKIE (string) | string | Adguardhome cookie |
|
||||
| ORIGIN_INSECURE_SKIP_VERIFY (bool) | bool | Skip TLS verification |
|
||||
| ORIGIN_AUTO_SETUP (bool) | bool | Automatically setup the instance if it is not initialized |
|
||||
| ORIGIN_INTERFACE_NAME (string) | string | Network interface name |
|
||||
| ORIGIN_DHCP_SERVER_ENABLED (bool) | bool | Enable DHCP server |
|
||||
| REPLICA#_URL (string) | string | URL of adguardhome instance |
|
||||
| REPLICA#_WEB_URL (string) | string | Web URL of adguardhome instance |
|
||||
| REPLICA#_API_PATH (string) | string | API Path |
|
||||
| REPLICA#_USERNAME (string) | string | Adguardhome username |
|
||||
| REPLICA#_PASSWORD (string) | string | Adguardhome password |
|
||||
| REPLICA#_COOKIE (string) | string | Adguardhome cookie |
|
||||
| REPLICA#_INSECURE_SKIP_VERIFY (bool) | bool | Skip TLS verification |
|
||||
| REPLICA#_AUTO_SETUP (bool) | bool | Automatically setup the instance if it is not initialized |
|
||||
| REPLICA#_INTERFACE_NAME (string) | string | Network interface name |
|
||||
| REPLICA#_DHCP_SERVER_ENABLED (bool) | bool | Enable DHCP server |
|
||||
| CRON (string) | string | Cron expression for the sync interval |
|
||||
| RUN_ON_START (bool) | bool | Run the sung on startup |
|
||||
| PRINT_CONFIG_ONLY (bool) | bool | Print current config only and stop the application |
|
||||
| CONTINUE_ON_ERROR (bool) | bool | Continue sync on errors |
|
||||
| API_PORT (int) | int | API port |
|
||||
| API_USERNAME (string) | string | API username |
|
||||
| API_PASSWORD (string) | string | API password |
|
||||
| API_DARK_MODE (bool) | bool | API dark mode |
|
||||
| API_METRICS_ENABLED (bool) | bool | Enable metrics |
|
||||
| API_METRICS_SCRAPE_INTERVAL (int64) | int64 | Interval for metrics scraping |
|
||||
| API_METRICS_QUERY_LOG_LIMIT (int) | int | Metrics log query limit |
|
||||
| API_TLS_CERT_DIR (string) | string | API TLS certificate directory |
|
||||
| API_TLS_CERT_NAME (string) | string | API TLS certificate file name |
|
||||
| API_TLS_KEY_NAME (string) | string | API TLS key file name |
|
||||
| FEATURES_DNS_ACCESS_LISTS (bool) | bool | Sync DNS access lists |
|
||||
| FEATURES_DNS_SERVER_CONFIG (bool) | bool | Sync DNS server config |
|
||||
| FEATURES_DNS_REWRITES (bool) | bool | Sync DNS rewrites |
|
||||
| FEATURES_DHCP_SERVER_CONFIG (bool) | bool | Sync DHCP server config |
|
||||
| FEATURES_DHCP_STATIC_LEASES (bool) | bool | Sync DHCP static leases |
|
||||
| FEATURES_GENERAL_SETTINGS (bool) | bool | Sync general settings |
|
||||
| FEATURES_QUERY_LOG_CONFIG (bool) | bool | Sync query log config |
|
||||
| FEATURES_STATS_CONFIG (bool) | bool | Sync stats config |
|
||||
| FEATURES_CLIENT_SETTINGS (bool) | bool | Sync client settings |
|
||||
| FEATURES_SERVICES (bool) | bool | Sync services |
|
||||
| FEATURES_FILTERS (bool) | bool | Sync filters |
|
||||
| FEATURES_THEME (bool) | bool | Sync the weg UI theme |
|
||||
|
||||
### Unraid
|
||||
|
||||
⚠️ Disclaimer: Tere exists an unraid tepmlate for this application. This template is not managed by this project.
|
||||
Also, as unraid is not known to me, I can not give any support on unraind templates.
|
||||
|
||||
Note when running the Docker container in Unraid please remove unneeded env variables if don't needed.
|
||||
If replica2 isn't used this can cause sync errors.
|
||||
|
||||
@@ -299,9 +291,9 @@ api:
|
||||
|
||||
# enable metrics on path '/metrics' (api port must be != 0)
|
||||
# metrics:
|
||||
# enabled: true
|
||||
# scrapeInterval: 30s
|
||||
# queryLogLimit: 10000
|
||||
# enabled: true
|
||||
# scrapeInterval: 30s
|
||||
# queryLogLimit: 10000
|
||||
|
||||
# enable tls for the api server
|
||||
# tls:
|
||||
|
||||
@@ -4,9 +4,10 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/log"
|
||||
"github.com/bakito/adguardhome-sync/version"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -14,7 +15,7 @@ var (
|
||||
logger = log.GetLogger("root")
|
||||
)
|
||||
|
||||
// rootCmd represents the base command when called without any subcommands
|
||||
// rootCmd represents the base command when called without any subcommands.
|
||||
var rootCmd = &cobra.Command{
|
||||
Use: "adguardhome-sync",
|
||||
Short: "Synchronize config from one AdGuardHome instance to another",
|
||||
@@ -25,7 +26,7 @@ var rootCmd = &cobra.Command{
|
||||
// This is called by main.main(). It only needs to happen once to the rootCmd.
|
||||
func Execute() {
|
||||
if err := rootCmd.Execute(); err != nil {
|
||||
fmt.Println(err)
|
||||
_, _ = fmt.Println(err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
27
cmd/run.go
27
cmd/run.go
@@ -1,16 +1,17 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/config"
|
||||
"github.com/bakito/adguardhome-sync/pkg/log"
|
||||
"github.com/bakito/adguardhome-sync/pkg/sync"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
// runCmd represents the run command
|
||||
// runCmd represents the run command.
|
||||
var doCmd = &cobra.Command{
|
||||
Use: "run",
|
||||
Short: "Start a synchronisation from origin to replica",
|
||||
Short: "Start a synchronization from origin to replica",
|
||||
Long: `Synchronizes the configuration form an origin instance to a replica`,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
logger = log.GetLogger("run")
|
||||
@@ -44,21 +45,21 @@ func init() {
|
||||
doCmd.PersistentFlags().Bool(config.FlagRunOnStart, true, "Run the sync job on start.")
|
||||
doCmd.PersistentFlags().Bool(config.FlagPrintConfigOnly, false, "Prints the configuration only and exists. "+
|
||||
"Can be used to debug the config E.g: when having authentication issues.")
|
||||
doCmd.PersistentFlags().Bool(config.FlagContinueOnError, false, "If enabled, the synchronisation task "+
|
||||
doCmd.PersistentFlags().Bool(config.FlagContinueOnError, false, "If enabled, the synchronization task "+
|
||||
"will not fail on single errors, but will log the errors and continue.")
|
||||
|
||||
doCmd.PersistentFlags().
|
||||
Int(config.FlagApiPort, 8080, "Sync API Port, the API endpoint will be started to enable remote triggering; if 0 port API is disabled.")
|
||||
doCmd.PersistentFlags().String(config.FlagApiUsername, "", "Sync API username")
|
||||
doCmd.PersistentFlags().String(config.FlagApiPassword, "", "Sync API password")
|
||||
doCmd.PersistentFlags().String(config.FlagApiDarkMode, "", "API UI in dark mode")
|
||||
Int(config.FlagAPIPort, 8080, "Sync API Port, the API endpoint will be started to enable remote triggering; if 0 port API is disabled.")
|
||||
doCmd.PersistentFlags().String(config.FlagAPIUsername, "", "Sync API username")
|
||||
doCmd.PersistentFlags().String(config.FlagAPIPassword, "", "Sync API password")
|
||||
doCmd.PersistentFlags().String(config.FlagAPIDarkMode, "", "API UI in dark mode")
|
||||
|
||||
doCmd.PersistentFlags().Bool(config.FlagFeatureDhcpServerConfig, true, "Enable DHCP server config feature")
|
||||
doCmd.PersistentFlags().Bool(config.FlagFeatureDhcpStaticLeases, true, "Enable DHCP server static leases feature")
|
||||
|
||||
doCmd.PersistentFlags().Bool(config.FlagFeatureDnsServerConfig, true, "Enable DNS server config feature")
|
||||
doCmd.PersistentFlags().Bool(config.FlagFeatureDnsAccessLists, true, "Enable DNS server access lists feature")
|
||||
doCmd.PersistentFlags().Bool(config.FlagFeatureDnsRewrites, true, "Enable DNS rewrites feature")
|
||||
doCmd.PersistentFlags().Bool(config.FlagFeatureDNSServerConfig, true, "Enable DNS server config feature")
|
||||
doCmd.PersistentFlags().Bool(config.FlagFeatureDNSAccessLists, true, "Enable DNS server access lists feature")
|
||||
doCmd.PersistentFlags().Bool(config.FlagFeatureDNSRewrites, true, "Enable DNS rewrites feature")
|
||||
|
||||
doCmd.PersistentFlags().Bool(config.FlagFeatureGeneral, true, "Enable general settings feature")
|
||||
doCmd.PersistentFlags().Bool(config.FlagFeatureQueryLog, true, "Enable query log config feature")
|
||||
@@ -70,7 +71,7 @@ func init() {
|
||||
doCmd.PersistentFlags().String(config.FlagOriginURL, "", "Origin instance url")
|
||||
doCmd.PersistentFlags().
|
||||
String(config.FlagOriginWebURL, "", "Origin instance web url used in the web interface (default: <origin-url>)")
|
||||
doCmd.PersistentFlags().String(config.FlagOriginApiPath, "/control", "Origin instance API path")
|
||||
doCmd.PersistentFlags().String(config.FlagOriginAPIPath, "/control", "Origin instance API path")
|
||||
doCmd.PersistentFlags().String(config.FlagOriginUsername, "", "Origin instance username")
|
||||
doCmd.PersistentFlags().String(config.FlagOriginPassword, "", "Origin instance password")
|
||||
doCmd.PersistentFlags().String(config.FlagOriginCookie, "", "If Set, uses a cookie for authentication")
|
||||
@@ -79,7 +80,7 @@ func init() {
|
||||
doCmd.PersistentFlags().String(config.FlagReplicaURL, "", "Replica instance url")
|
||||
doCmd.PersistentFlags().
|
||||
String(config.FlagReplicaWebURL, "", "Replica instance web url used in the web interface (default: <replica-url>)")
|
||||
doCmd.PersistentFlags().String(config.FlagReplicaApiPath, "/control", "Replica instance API path")
|
||||
doCmd.PersistentFlags().String(config.FlagReplicaAPIPath, "/control", "Replica instance API path")
|
||||
doCmd.PersistentFlags().String(config.FlagReplicaUsername, "", "Replica instance username")
|
||||
doCmd.PersistentFlags().String(config.FlagReplicaPassword, "", "Replica instance password")
|
||||
doCmd.PersistentFlags().String(config.FlagReplicaCookie, "", "If Set, uses a cookie for authentication")
|
||||
|
||||
57
docs/main.go
Normal file
57
docs/main.go
Normal file
@@ -0,0 +1,57 @@
|
||||
// Print the available environment variables
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
)
|
||||
|
||||
func main() {
|
||||
_, _ = fmt.Println("| Name | Type | Description |")
|
||||
_, _ = fmt.Println("| :--- | ---- |:----------- |")
|
||||
printEnvTags(reflect.TypeOf(types.Config{}), "")
|
||||
}
|
||||
|
||||
// printEnvTags recursively prints all fields with `env` tags.
|
||||
func printEnvTags(t reflect.Type, prefix string) {
|
||||
if t.Kind() == reflect.Ptr {
|
||||
t = t.Elem()
|
||||
}
|
||||
if t.Kind() != reflect.Struct {
|
||||
return
|
||||
}
|
||||
|
||||
for _, field := range reflect.VisibleFields(t) {
|
||||
if field.PkgPath != "" { // unexported field
|
||||
continue
|
||||
}
|
||||
|
||||
envTag := field.Tag.Get("env")
|
||||
if envTag == "REPLICA" {
|
||||
envTag = "REPLICA#"
|
||||
}
|
||||
combinedTag := envTag
|
||||
if prefix != "" && envTag != "" {
|
||||
combinedTag = prefix + "_" + envTag
|
||||
} else if prefix != "" {
|
||||
combinedTag = prefix
|
||||
}
|
||||
|
||||
ft := field.Type
|
||||
if ft.Kind() == reflect.Ptr {
|
||||
ft = ft.Elem()
|
||||
}
|
||||
|
||||
if ft.Kind() == reflect.Struct && ft.Name() != "Time" { // skip time.Time
|
||||
printEnvTags(ft, strings.TrimSuffix(combinedTag, "_"))
|
||||
} else if envTag != "" {
|
||||
envVar := strings.Trim(combinedTag, "_") + " (" + ft.Kind().String() + ")"
|
||||
docs := field.Tag.Get("documentation")
|
||||
|
||||
_, _ = fmt.Printf("| %s | %s | %s |\n", envVar, ft.Kind().String(), docs)
|
||||
}
|
||||
}
|
||||
}
|
||||
63
go.mod
63
go.mod
@@ -1,6 +1,6 @@
|
||||
module github.com/bakito/adguardhome-sync
|
||||
|
||||
go 1.24.0
|
||||
go 1.24.1
|
||||
|
||||
require (
|
||||
github.com/caarlos0/env/v11 v11.3.1
|
||||
@@ -10,69 +10,68 @@ require (
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/jinzhu/copier v0.4.0
|
||||
github.com/oapi-codegen/runtime v1.1.1
|
||||
github.com/onsi/ginkgo/v2 v2.23.0
|
||||
github.com/onsi/gomega v1.36.2
|
||||
github.com/prometheus/client_golang v1.21.1
|
||||
github.com/onsi/ginkgo/v2 v2.23.4
|
||||
github.com/onsi/gomega v1.37.0
|
||||
github.com/prometheus/client_golang v1.22.0
|
||||
github.com/robfig/cron/v3 v3.0.1
|
||||
github.com/santhosh-tekuri/jsonschema/v6 v6.0.1
|
||||
github.com/spf13/cobra v1.9.1
|
||||
go.uber.org/mock v0.5.0
|
||||
go.uber.org/mock v0.5.1
|
||||
go.uber.org/zap v1.27.0
|
||||
golang.org/x/mod v0.24.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
k8s.io/apimachinery v0.32.3
|
||||
k8s.io/utils v0.0.0-20241210054802-24370beab758
|
||||
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/apapsch/go-jsonmerge/v2 v2.0.0 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/bytedance/sonic v1.11.6 // indirect
|
||||
github.com/bytedance/sonic/loader v0.1.1 // indirect
|
||||
github.com/bytedance/sonic v1.13.2 // indirect
|
||||
github.com/bytedance/sonic/loader v0.2.4 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/cloudwego/base64x v0.1.5 // indirect
|
||||
github.com/fxamacker/cbor/v2 v2.8.0 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||
github.com/gin-contrib/sse v1.1.0 // indirect
|
||||
github.com/go-logr/logr v1.4.2 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.20.0 // indirect
|
||||
github.com/go-playground/validator/v10 v10.26.0 // indirect
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/google/go-cmp v0.6.0 // indirect
|
||||
github.com/google/go-cmp v0.7.0 // indirect
|
||||
github.com/google/gofuzz v1.2.0 // indirect
|
||||
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad // indirect
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.1.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.17.11 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
github.com/prometheus/client_model v0.6.1 // indirect
|
||||
github.com/prometheus/common v0.62.0 // indirect
|
||||
github.com/prometheus/procfs v0.15.1 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/prometheus/client_model v0.6.2 // indirect
|
||||
github.com/prometheus/common v0.63.0 // indirect
|
||||
github.com/prometheus/procfs v0.16.0 // indirect
|
||||
github.com/spf13/pflag v1.0.6 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
github.com/x448/float16 v0.8.4 // indirect
|
||||
go.uber.org/automaxprocs v1.6.0 // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/arch v0.8.0 // indirect
|
||||
golang.org/x/crypto v0.35.0 // indirect
|
||||
golang.org/x/net v0.36.0 // indirect
|
||||
golang.org/x/sys v0.30.0 // indirect
|
||||
golang.org/x/text v0.22.0 // indirect
|
||||
golang.org/x/tools v0.30.0 // indirect
|
||||
google.golang.org/protobuf v1.36.1 // indirect
|
||||
golang.org/x/arch v0.16.0 // indirect
|
||||
golang.org/x/crypto v0.37.0 // indirect
|
||||
golang.org/x/net v0.39.0 // indirect
|
||||
golang.org/x/sys v0.32.0 // indirect
|
||||
golang.org/x/text v0.24.0 // indirect
|
||||
golang.org/x/tools v0.32.0 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||
k8s.io/klog/v2 v2.130.1 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 // indirect
|
||||
sigs.k8s.io/yaml v1.4.0 // indirect
|
||||
)
|
||||
|
||||
131
go.sum
131
go.sum
@@ -4,17 +4,17 @@ github.com/apapsch/go-jsonmerge/v2 v2.0.0/go.mod h1:lvDnEdqiQrp0O42VQGgmlKpxL1AP
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bmatcuk/doublestar v1.1.1/go.mod h1:UD6OnuiIn0yFxxA2le/rnRU1G4RaI4UvFv1sNto9p6w=
|
||||
github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0=
|
||||
github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4=
|
||||
github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM=
|
||||
github.com/bytedance/sonic v1.13.2 h1:8/H1FempDZqC4VqjptGo14QQlJx8VdZJegxs6wwfqpQ=
|
||||
github.com/bytedance/sonic v1.13.2/go.mod h1:o68xyaF9u2gvVBuGHPlUVCy+ZfmNNO5ETf1+KgkJhz4=
|
||||
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||
github.com/bytedance/sonic/loader v0.2.4 h1:ZWCw4stuXUsn1/+zQDqeE7JKP+QO47tz7QCNan80NzY=
|
||||
github.com/bytedance/sonic/loader v0.2.4/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
|
||||
github.com/caarlos0/env/v11 v11.3.1 h1:cArPWC15hWmEt+gWk7YBi7lEXTXCvpaSdCiZE2X5mCA=
|
||||
github.com/caarlos0/env/v11 v11.3.1/go.mod h1:qupehSf/Y0TUTsxKywqRt/vJjN5nz6vauiYEUUr8P4U=
|
||||
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
||||
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||
github.com/cloudwego/iasm v0.2.0 h1:1KNIy1I1H9hNNFEEH3DVnI4UujN+1zjpuk6gwHLTssg=
|
||||
github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4=
|
||||
github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||
github.com/cloudwego/iasm v0.2.0/go.mod h1:8rXZaNYT2n95jn+zTI1sDr+IgcD2GVs0nlbbQPiEFhY=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -23,12 +23,12 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1
|
||||
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dlclark/regexp2 v1.11.0 h1:G/nrcoOa7ZXlpoa/91N3X7mM3r8eIlMBBJZvsz/mxKI=
|
||||
github.com/dlclark/regexp2 v1.11.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
|
||||
github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
|
||||
github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0=
|
||||
github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU=
|
||||
github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
||||
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
||||
github.com/gin-contrib/sse v1.1.0 h1:n0w2GMuUpWDVp7qSpvze6fAu9iRxJY4Hmj6AmBOU05w=
|
||||
github.com/gin-contrib/sse v1.1.0/go.mod h1:hxRZ5gVpWMT7Z0B0gSNYqqsSCNIJMjzvm6fqCz9vjwM=
|
||||
github.com/gin-gonic/gin v1.10.0 h1:nTuyha1TYqgedzytsKYqna+DfLos46nTv2ygFy86HFU=
|
||||
github.com/gin-gonic/gin v1.10.0/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y=
|
||||
github.com/go-faker/faker/v4 v4.6.0 h1:6aOPzNptRiDwD14HuAnEtlTa+D1IfFuEHO8+vEFwjTs=
|
||||
@@ -41,24 +41,24 @@ github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/o
|
||||
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.20.0 h1:K9ISHbSaI0lyB2eWMPJo+kOS/FBExVwjEviJTixqxL8=
|
||||
github.com/go-playground/validator/v10 v10.20.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||
github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k=
|
||||
github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo=
|
||||
github.com/go-resty/resty/v2 v2.16.5 h1:hBKqmWrr7uRc3euHVqmh1HTHcKn99Smr7o5spptdhTM=
|
||||
github.com/go-resty/resty/v2 v2.16.5/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
|
||||
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4=
|
||||
github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
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/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad h1:a6HEuzUHeKH6hwfN/ZoQgRgVIWFJljSWa/zetS2WTvg=
|
||||
github.com/google/pprof v0.0.0-20241210010833-40e02aabc2ad/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6 h1:BHT72Gu3keYf3ZEu2J0b1vyeLSOYI8bm5wbJM/8yDe8=
|
||||
github.com/google/pprof v0.0.0-20250403155104-27863c87afa6/go.mod h1:boTsfXsheKC2y+lKOCMpSfarhxDeIzfZG1jqGcPl3cA=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
|
||||
@@ -70,11 +70,11 @@ github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHm
|
||||
github.com/juju/gnuflag v0.0.0-20171113085948-2ce1bb71843d/go.mod h1:2PavIy+JPciBPrBUjwbNvtwB6RQlve+hkpll6QSNmOE=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc=
|
||||
github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0=
|
||||
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
|
||||
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
|
||||
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 h1:ZWSB3igEs+d0qvnxR/ZBzXVmxkgt8DdzP6m9pfuVLDM=
|
||||
github.com/klauspost/cpuid/v2 v2.2.7/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE=
|
||||
github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0=
|
||||
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=
|
||||
@@ -95,23 +95,25 @@ github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/oapi-codegen/runtime v1.1.1 h1:EXLHh0DXIJnWhdRPN2w4MXAzFyE4CskzhNLUmtpMYro=
|
||||
github.com/oapi-codegen/runtime v1.1.1/go.mod h1:SK9X900oXmPWilYR5/WKPzt3Kqxn/uS/+lbpREv+eCg=
|
||||
github.com/onsi/ginkgo/v2 v2.23.0 h1:FA1xjp8ieYDzlgS5ABTpdUDB7wtngggONc8a7ku2NqQ=
|
||||
github.com/onsi/ginkgo/v2 v2.23.0/go.mod h1:zXTP6xIp3U8aVuXN8ENK9IXRaTjFnpVB9mGmaSRvxnM=
|
||||
github.com/onsi/gomega v1.36.2 h1:koNYke6TVk6ZmnyHrCXba/T/MoLBXFjeC1PtvYgw0A8=
|
||||
github.com/onsi/gomega v1.36.2/go.mod h1:DdwyADRjrc825LhMEkD76cHR5+pUnjhUN8GlHlRPHzY=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM=
|
||||
github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs=
|
||||
github.com/onsi/ginkgo/v2 v2.23.4 h1:ktYTpKJAVZnDT4VjxSbiBenUjmlL/5QkBEocaWXiQus=
|
||||
github.com/onsi/ginkgo/v2 v2.23.4/go.mod h1:Bt66ApGPBFzHyR+JO10Zbt0Gsp4uWxu5mIOTusL46e8=
|
||||
github.com/onsi/gomega v1.37.0 h1:CdEG8g0S133B4OswTDC/5XPSzE1OeP29QOioj2PID2Y=
|
||||
github.com/onsi/gomega v1.37.0/go.mod h1:8D9+Txp43QWKhM24yyOBEdpkzN8FvJyAwecBgsU4KU0=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/prometheus/client_golang v1.21.1 h1:DOvXXTqVzvkIewV/CDPFdejpMCGeMcbGCQ8YOmu+Ibk=
|
||||
github.com/prometheus/client_golang v1.21.1/go.mod h1:U9NM32ykUErtVBxdvD3zfi+EuFkkaBvMb09mIfe0Zgg=
|
||||
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
|
||||
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
|
||||
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
|
||||
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
|
||||
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
|
||||
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
|
||||
github.com/prashantv/gostub v1.1.0 h1:BTyx3RfQjRHnUWaGF9oQos79AlQ5k8WNktv7VGvVH4g=
|
||||
github.com/prashantv/gostub v1.1.0/go.mod h1:A5zLQHz7ieHGG7is6LLXLz7I8+3LZzsrV0P1IAHhP5U=
|
||||
github.com/prometheus/client_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
|
||||
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
|
||||
github.com/prometheus/client_model v0.6.2 h1:oBsgwpGs7iVziMvrGhE53c/GrLUsZdHnqNwqPLxwZyk=
|
||||
github.com/prometheus/client_model v0.6.2/go.mod h1:y3m2F6Gdpfy6Ut/GBsUqTWZqCUvMVzSfMLjcu6wAwpE=
|
||||
github.com/prometheus/common v0.63.0 h1:YR/EIY1o3mEFP/kZCD7iDMnLPlGyuU2Gb3HIcXnA98k=
|
||||
github.com/prometheus/common v0.63.0/go.mod h1:VVFF/fBIoToEnWRVkYoXEkq3R3paCoxG9PXP74SnV18=
|
||||
github.com/prometheus/procfs v0.16.0 h1:xh6oHhKwnOJKMYiYBDWmkHqQPyiY40sny36Cmx2bbsM=
|
||||
github.com/prometheus/procfs v0.16.0/go.mod h1:8veyXUu3nGP7oaCxhX6yeaM5u4stL2FeMXnCqhDthZg=
|
||||
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.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
|
||||
@@ -127,14 +129,11 @@ github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKk
|
||||
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/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
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/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
|
||||
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
@@ -145,22 +144,23 @@ github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
|
||||
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
go.uber.org/automaxprocs v1.6.0 h1:O3y2/QNTOdbF+e/dpXNNW7Rx2hZ4sTIPyybbxyNqTUs=
|
||||
go.uber.org/automaxprocs v1.6.0/go.mod h1:ifeIMSnPZuznNm6jmdzmU3/bfk01Fe2fotchwEFJ8r8=
|
||||
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||
go.uber.org/mock v0.5.0 h1:KAMbZvZPyBPWgD14IrIQ38QCyjwpvVVV6K/bHl1IwQU=
|
||||
go.uber.org/mock v0.5.0/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
||||
go.uber.org/mock v0.5.1 h1:ASgazW/qBmR+A32MYFDB6E2POoTgOwT509VP0CT/fjs=
|
||||
go.uber.org/mock v0.5.1/go.mod h1:ge71pBPLYDk7QIi1LupWxdAykm7KIEFchiOqd6z7qMM=
|
||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
|
||||
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
|
||||
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/arch v0.16.0 h1:foMtLTdyOmIniqWCHjY6+JxuC54XP1fDwx4N0ASyW+U=
|
||||
golang.org/x/arch v0.16.0/go.mod h1:JmwW7aLIoRUKgaTzhkiEFxvcEiQGyOg9BMonBJUS7EE=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.35.0 h1:b15kiHdrGCHrP6LvwaQ3c03kgNhhiMgvlhxHQhmg2Xs=
|
||||
golang.org/x/crypto v0.35.0/go.mod h1:dy7dXNW32cAb/6/PRuTNsix8T+vJAqvuIy5Bli/x0YQ=
|
||||
golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
|
||||
golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
|
||||
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.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
|
||||
@@ -169,36 +169,35 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.36.0 h1:vWF2fRbw4qslQsQzgFqZff+BItCvGFQqKzKIzx1rmoA=
|
||||
golang.org/x/net v0.36.0/go.mod h1:bFmbeoIPfrw4sMHNhb4J9f6+tPziuGjq7Jk/38fxi1I=
|
||||
golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY=
|
||||
golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20=
|
||||
golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0=
|
||||
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
|
||||
golang.org/x/time v0.7.0 h1:ntUhktv3OPE6TgYxXWv9vKvUSJyIFJlyohwbkEwPrKQ=
|
||||
golang.org/x/time v0.7.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.30.0 h1:BgcpHewrV5AUp2G9MebG4XPFI1E2W41zU1SaqVA9vJY=
|
||||
golang.org/x/tools v0.30.0/go.mod h1:c347cR/OJfw5TI+GfX7RUPNMdDRRbjvYTS0jPyvsVtY=
|
||||
golang.org/x/tools v0.32.0 h1:Q7N1vhpkQv7ybVzLFtTjvQya2ewbwNDZzUgfXGqtMWU=
|
||||
golang.org/x/tools v0.32.0/go.mod h1:ZxrU41P/wAbZD8EDa6dDCa6XfpkhJ7HFMjHJXfBDu8s=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v1.36.1 h1:yBPeRvTftaleIgM3PZ/WBIZ7XM/eEYAaEyCwvyjq/gk=
|
||||
google.golang.org/protobuf v1.36.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY=
|
||||
google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
@@ -211,13 +210,13 @@ k8s.io/apimachinery v0.32.3 h1:JmDuDarhDmA/Li7j3aPrwhpNBA94Nvk5zLeOge9HH1U=
|
||||
k8s.io/apimachinery v0.32.3/go.mod h1:GpHVgxoKlTxClKcteaeuF1Ul/lDVb74KpZcxcmLDElE=
|
||||
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
|
||||
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
|
||||
k8s.io/utils v0.0.0-20241210054802-24370beab758 h1:sdbE21q2nlQtFh65saZY+rRM6x6aJJI8IUa1AmH/qa0=
|
||||
k8s.io/utils v0.0.0-20241210054802-24370beab758/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e h1:KqK5c/ghOm8xkHYhlodbp6i6+r+ChV2vuAuVRdFbLro=
|
||||
k8s.io/utils v0.0.0-20250321185631-1f6e0b77f77e/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
|
||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 h1:/Rv+M11QRah1itp8VhT6HoVx1Ray9eB4DBr+K+/sCJ8=
|
||||
sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3/go.mod h1:18nIHnGi6636UCz6m8i4DhaJ65T6EruyzmoQqI2BVDo=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.2 h1:MdmvkGuXi/8io6ixD5wud3vOLwc1rj0aNqRlpuvjmwA=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.4.2/go.mod h1:N8f93tFZh9U6vpxwRArLiikrE5/2tiu1w1AGfACIGE4=
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
|
||||
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
|
||||
sigs.k8s.io/randfill v0.0.0-20250304075658-069ef1bbf016/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.7.0 h1:qPeWmscJcXP0snki5IYF79Z8xrl8ETFxgMd7wez1XkI=
|
||||
sigs.k8s.io/structured-merge-diff/v4 v4.7.0/go.mod h1:dDy58f92j70zLsuZVuUX5Wp9vtxXpaZnkPGWeqDfCps=
|
||||
sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E=
|
||||
sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY=
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
@@ -20,21 +21,33 @@ func main() {
|
||||
}
|
||||
log.Printf("Patching schema version %s\n", version)
|
||||
|
||||
resp, err := http.Get(
|
||||
ctx := context.Background() // Or use context.WithTimeout
|
||||
req, err := http.NewRequestWithContext(
|
||||
ctx,
|
||||
http.MethodGet,
|
||||
fmt.Sprintf("https://raw.githubusercontent.com/AdguardTeam/AdGuardHome/%s/openapi/openapi.yaml", version),
|
||||
http.NoBody,
|
||||
)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
client := &http.Client{}
|
||||
resp, err := client.Do(req)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
defer func() { _ = resp.Body.Close() }()
|
||||
data, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
schema := make(map[string]interface{})
|
||||
schema := make(map[string]any)
|
||||
err = yaml.Unmarshal(data, &schema)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
|
||||
if requestBodies, ok, _ := unstructured.NestedMap(schema, "components", "requestBodies"); ok {
|
||||
@@ -47,9 +60,11 @@ func main() {
|
||||
"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{}),
|
||||
//nolint:forcetypeassert
|
||||
if err := unstructured.SetNestedMap(schema, allOf[0].(map[string]any),
|
||||
"paths", "/dns_info", "get", "responses", "200", "content", "application/json", "schema"); err != nil {
|
||||
log.Fatalln(err)
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,24 +75,26 @@ func main() {
|
||||
|
||||
b, err := yaml.Marshal(&schema)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
log.Printf("Writing schema file tmp/%s", fileName)
|
||||
err = os.WriteFile("tmp/"+fileName, b, 0o600)
|
||||
if err != nil {
|
||||
log.Fatalln(err)
|
||||
log.Println(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func correctEntries(schema map[string]interface{}) {
|
||||
func correctEntries(schema map[string]any) {
|
||||
// https://github.com/AdguardTeam/AdGuardHome/pull/7678
|
||||
if err := unstructured.SetNestedField(schema, "string", "components", "schemas", "QueryLogItem", "properties", "client_proto", "type"); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
}
|
||||
|
||||
func addFakeTags(schema map[string]interface{}) {
|
||||
fake := map[string]interface{}{"faker": `slice_len=24`}
|
||||
func addFakeTags(schema map[string]any) {
|
||||
fake := map[string]any{"faker": `slice_len=24`}
|
||||
if err := unstructured.SetNestedMap(schema, fake, "components", "schemas", "Stats", "properties", "blocked_filtering", "x-oapi-codegen-extra-tags"); err != nil {
|
||||
log.Fatalln(err)
|
||||
}
|
||||
|
||||
@@ -17,14 +17,18 @@ func (cl *client) doGet(req *resty.Request, url string) error {
|
||||
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
|
||||
l := rl
|
||||
if resp != nil {
|
||||
if resp.StatusCode() == http.StatusFound {
|
||||
loc := resp.Header().Get("Location")
|
||||
if loc == "/install.html" || loc == "/control/install.html" {
|
||||
return ErrSetupNeeded
|
||||
}
|
||||
}
|
||||
l = l.With("status", resp.StatusCode(), "body", string(resp.Body()), "error", err)
|
||||
}
|
||||
|
||||
rl.With("status", resp.StatusCode(), "body", string(resp.Body()), "error", err).Debug("error in do get")
|
||||
l.Debug("error in do get")
|
||||
return detailedError(resp, err)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,19 +11,20 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/go-resty/resty/v2"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
const envRedirectPolicyNoOfRedirects = "REDIRECT_POLICY_NO_OF_REDIRECTS"
|
||||
|
||||
var (
|
||||
l = log.GetLogger("client")
|
||||
// ErrSetupNeeded custom error
|
||||
// ErrSetupNeeded custom error.
|
||||
ErrSetupNeeded = errors.New("setup needed")
|
||||
)
|
||||
|
||||
@@ -33,16 +34,16 @@ func detailedError(resp *resty.Response, err error) error {
|
||||
e += fmt.Sprintf("(%s)", string(resp.Body()))
|
||||
}
|
||||
if err != nil {
|
||||
e += fmt.Sprintf(": %s", err.Error())
|
||||
e += ": " + err.Error()
|
||||
}
|
||||
return errors.New(e)
|
||||
}
|
||||
|
||||
// New create a new client
|
||||
// New create a new client.
|
||||
func New(config types.AdGuardInstance) (Client, error) {
|
||||
var apiURL string
|
||||
if config.APIPath == "" {
|
||||
apiURL = fmt.Sprintf("%s/control", config.URL)
|
||||
apiURL = config.URL + "/control"
|
||||
} else {
|
||||
apiURL = fmt.Sprintf("%s/%s", config.URL, config.APIPath)
|
||||
}
|
||||
@@ -84,7 +85,9 @@ func New(config types.AdGuardInstance) (Client, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
// Client AdguardHome API client interface
|
||||
// Client AdguardHome API client interface.
|
||||
//
|
||||
//nolint:interfacebloat
|
||||
type Client interface {
|
||||
Host() string
|
||||
Status() (*model.ServerStatus, error)
|
||||
@@ -116,16 +119,16 @@ type Client interface {
|
||||
UpdateClient(client *model.Client) error
|
||||
DeleteClient(client *model.Client) error
|
||||
QueryLogConfig() (*model.QueryLogConfigWithIgnored, error)
|
||||
SetQueryLogConfig(*model.QueryLogConfigWithIgnored) error
|
||||
SetQueryLogConfig(ql *model.QueryLogConfigWithIgnored) error
|
||||
StatsConfig() (*model.GetStatsConfigResponse, error)
|
||||
SetStatsConfig(sc *model.PutStatsConfigUpdateRequest) error
|
||||
Setup() error
|
||||
AccessList() (*model.AccessList, error)
|
||||
SetAccessList(*model.AccessList) error
|
||||
SetAccessList(accessList *model.AccessList) error
|
||||
DNSConfig() (*model.DNSConfig, error)
|
||||
SetDNSConfig(*model.DNSConfig) error
|
||||
SetDNSConfig(config *model.DNSConfig) error
|
||||
DhcpConfig() (*model.DhcpStatus, error)
|
||||
SetDhcpConfig(*model.DhcpStatus) error
|
||||
SetDhcpConfig(status *model.DhcpStatus) error
|
||||
AddDHCPStaticLease(lease model.DhcpStaticLease) error
|
||||
DeleteDHCPStaticLease(lease model.DhcpStaticLease) error
|
||||
}
|
||||
@@ -224,7 +227,7 @@ func (cl *client) toggleStatus(mode string) (bool, error) {
|
||||
}
|
||||
|
||||
func (cl *client) toggleBool(mode string, enable bool) error {
|
||||
cl.log.With("enable", enable).Info(fmt.Sprintf("Toggle %s", mode))
|
||||
cl.log.With("enable", enable).Info("Toggle " + mode)
|
||||
var target string
|
||||
if enable {
|
||||
target = "enable"
|
||||
|
||||
@@ -8,13 +8,14 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/google/uuid"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"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"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -140,7 +141,7 @@ var _ = Describe("Client", func() {
|
||||
ts, cl = ClientPost(
|
||||
"/install/configure",
|
||||
fmt.Sprintf(
|
||||
`{"web":{"ip":"0.0.0.0","port":3000,"status":"","can_autofix":false},"dns":{"ip":"0.0.0.0","port":53,"status":"","can_autofix":false},"username":"%s","password":"%s"}`,
|
||||
`{"web":{"ip":"0.0.0.0","port":3000,"status":"","can_autofix":false},"dns":{"ip":"0.0.0.0","port":53,"status":"","can_autofix":false},"username":%q,"password":%q}`,
|
||||
username,
|
||||
password,
|
||||
),
|
||||
@@ -373,10 +374,10 @@ var _ = Describe("Client", func() {
|
||||
})
|
||||
})
|
||||
|
||||
func ClientGet(file string, path string) (*httptest.Server, client.Client) {
|
||||
func ClientGet(file, path string) (*httptest.Server, client.Client) {
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
Ω(r.URL.Path).Should(Equal(types.DefaultAPIPath + path))
|
||||
b, err := os.ReadFile(filepath.Join("../../testdata", file))
|
||||
b, err := os.ReadFile(filepath.Join("..", "..", "testdata", file))
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
_, err = w.Write(b)
|
||||
|
||||
@@ -11,19 +11,20 @@ import (
|
||||
"net/url"
|
||||
"path"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"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
|
||||
// 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)
|
||||
apiURL = config.URL + "/control"
|
||||
} else {
|
||||
apiURL = fmt.Sprintf("%s/%s", config.URL, config.APIPath)
|
||||
}
|
||||
@@ -96,7 +97,7 @@ func (a apiClient) SetFilteringConfig(ctx context.Context, config model.FilterCo
|
||||
return write(ctx, config, a.client.FilteringConfig)
|
||||
}
|
||||
|
||||
func write[B interface{}](
|
||||
func write[B any](
|
||||
ctx context.Context,
|
||||
body B,
|
||||
req func(ctx context.Context, body B, reqEditors ...model.RequestEditorFn) (*http.Response, error),
|
||||
@@ -112,7 +113,7 @@ func write[B interface{}](
|
||||
return nil
|
||||
}
|
||||
|
||||
func read[I interface{}](
|
||||
func read[I any](
|
||||
ctx context.Context,
|
||||
req func(ctx context.Context, reqEditors ...model.RequestEditorFn) (*http.Response, error),
|
||||
parse func(rsp *http.Response) (*I, error),
|
||||
|
||||
@@ -3,8 +3,9 @@ package client
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/client/model"
|
||||
"github.com/go-resty/resty/v2"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/client/model"
|
||||
)
|
||||
|
||||
var _ model.HttpRequestDoer = &adapter{}
|
||||
|
||||
@@ -5,13 +5,14 @@ import (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/utils"
|
||||
"github.com/jinzhu/copier"
|
||||
"go.uber.org/zap"
|
||||
"k8s.io/utils/ptr"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/utils"
|
||||
)
|
||||
|
||||
// Clone the config
|
||||
// Clone the config.
|
||||
func (c *DhcpStatus) Clone() *DhcpStatus {
|
||||
clone := &DhcpStatus{}
|
||||
_ = copier.Copy(clone, c)
|
||||
@@ -27,16 +28,16 @@ func (c *DhcpStatus) cleanV4V6() {
|
||||
}
|
||||
}
|
||||
|
||||
// CleanAndEquals dhcp server config equal check where V4 and V6 are cleaned in advance
|
||||
// CleanAndEquals dhcp server config equal check where V4 and V6 are cleaned in advance.
|
||||
func (c *DhcpStatus) CleanAndEquals(o *DhcpStatus) bool {
|
||||
c.cleanV4V6()
|
||||
o.cleanV4V6()
|
||||
return c.Equals(o)
|
||||
}
|
||||
|
||||
// Equals dhcp server config equal check
|
||||
// Equals dhcp server config equal check.
|
||||
func (c *DhcpStatus) Equals(o *DhcpStatus) bool {
|
||||
return utils.JsonEquals(c, o)
|
||||
return utils.JSONEquals(c, o)
|
||||
}
|
||||
|
||||
func (c *DhcpStatus) HasConfig() bool {
|
||||
@@ -56,8 +57,8 @@ func (j DhcpConfigV6) isValid() bool {
|
||||
|
||||
type DhcpStaticLeases []DhcpStaticLease
|
||||
|
||||
// MergeDhcpStaticLeases the leases
|
||||
func MergeDhcpStaticLeases(l *[]DhcpStaticLease, other *[]DhcpStaticLease) (DhcpStaticLeases, DhcpStaticLeases) {
|
||||
// MergeDhcpStaticLeases the leases.
|
||||
func MergeDhcpStaticLeases(l, other *[]DhcpStaticLease) (adds, removes DhcpStaticLeases) {
|
||||
var thisLeases []DhcpStaticLease
|
||||
var otherLeases []DhcpStaticLease
|
||||
|
||||
@@ -69,8 +70,6 @@ func MergeDhcpStaticLeases(l *[]DhcpStaticLease, other *[]DhcpStaticLease) (Dhcp
|
||||
}
|
||||
current := make(map[string]DhcpStaticLease)
|
||||
|
||||
var adds DhcpStaticLeases
|
||||
var removes DhcpStaticLeases
|
||||
for _, le := range thisLeases {
|
||||
current[le.Mac] = le
|
||||
}
|
||||
@@ -90,21 +89,21 @@ func MergeDhcpStaticLeases(l *[]DhcpStaticLease, other *[]DhcpStaticLease) (Dhcp
|
||||
return adds, removes
|
||||
}
|
||||
|
||||
// Equals dns config equal check
|
||||
// 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)
|
||||
return utils.JSONEquals(cc, oo)
|
||||
}
|
||||
|
||||
func (c *DNSConfig) Clone() *DNSConfig {
|
||||
return utils.Clone(c, &DNSConfig{})
|
||||
}
|
||||
|
||||
// Sort sort dns config
|
||||
// Sort dns config.
|
||||
func (c *DNSConfig) Sort() {
|
||||
if c.UpstreamDns != nil {
|
||||
sort.Strings(*c.UpstreamDns)
|
||||
@@ -119,14 +118,14 @@ func (c *DNSConfig) Sort() {
|
||||
}
|
||||
}
|
||||
|
||||
// Equals access list equal check
|
||||
// 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 {
|
||||
func EqualsStringSlice(a, b *[]string, sortIt bool) bool {
|
||||
if a == nil && b == nil {
|
||||
return true
|
||||
}
|
||||
@@ -152,7 +151,7 @@ func EqualsStringSlice(a *[]string, b *[]string, sortIt bool) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// Sort clients
|
||||
// Sort clients.
|
||||
func (cl *Client) Sort() {
|
||||
if cl.Ids != nil {
|
||||
sort.Strings(*cl.Ids)
|
||||
@@ -168,28 +167,26 @@ func (cl *Client) Sort() {
|
||||
}
|
||||
}
|
||||
|
||||
// PrepareDiff timezone BlockedServicesSchedule might differ if all other fields are empty,
|
||||
// so we skip it in diff
|
||||
// PrepareDiff so we skip it in diff.
|
||||
func (cl *Client) PrepareDiff() *string {
|
||||
var tz *string
|
||||
bss := cl.BlockedServicesSchedule
|
||||
if bss != nil && bss.Mon == nil && bss.Tue == nil && bss.Wed == nil &&
|
||||
bss.Thu == nil && bss.Fri == nil && bss.Sat == nil && bss.Sun == nil {
|
||||
|
||||
tz = cl.BlockedServicesSchedule.TimeZone
|
||||
cl.BlockedServicesSchedule.TimeZone = nil
|
||||
}
|
||||
return tz
|
||||
}
|
||||
|
||||
// AfterDiff reset after diff
|
||||
// AfterDiff reset after diff.
|
||||
func (cl *Client) AfterDiff(tz *string) {
|
||||
if cl.BlockedServicesSchedule != nil {
|
||||
cl.BlockedServicesSchedule.TimeZone = tz
|
||||
}
|
||||
}
|
||||
|
||||
// Equals Clients equal check
|
||||
// Equals Clients equal check.
|
||||
func (cl *Client) Equals(o *Client) bool {
|
||||
cl.Sort()
|
||||
o.Sort()
|
||||
@@ -202,10 +199,10 @@ func (cl *Client) Equals(o *Client) bool {
|
||||
o.AfterDiff(bssO)
|
||||
}()
|
||||
|
||||
return utils.JsonEquals(cl, o)
|
||||
return utils.JSONEquals(cl, o)
|
||||
}
|
||||
|
||||
// Add ac client
|
||||
// Add ac client.
|
||||
func (clients *Clients) Add(cl Client) {
|
||||
if clients.Clients == nil {
|
||||
clients.Clients = &ClientsArray{cl}
|
||||
@@ -215,8 +212,8 @@ func (clients *Clients) Add(cl Client) {
|
||||
}
|
||||
}
|
||||
|
||||
// Merge merge Clients
|
||||
func (clients *Clients) Merge(other *Clients) ([]*Client, []*Client, []*Client) {
|
||||
// Merge merge Clients.
|
||||
func (clients *Clients) Merge(other *Clients) (adds, removes, updates []*Client) {
|
||||
current := make(map[string]*Client)
|
||||
if clients.Clients != nil {
|
||||
cc := *clients.Clients
|
||||
@@ -233,10 +230,6 @@ func (clients *Clients) Merge(other *Clients) ([]*Client, []*Client, []*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) {
|
||||
@@ -255,7 +248,7 @@ func (clients *Clients) Merge(other *Clients) ([]*Client, []*Client, []*Client)
|
||||
return adds, updates, removes
|
||||
}
|
||||
|
||||
// Key RewriteEntry key
|
||||
// Key RewriteEntry key.
|
||||
func (re *RewriteEntry) Key() string {
|
||||
var d string
|
||||
var a string
|
||||
@@ -268,16 +261,13 @@ func (re *RewriteEntry) Key() string {
|
||||
return fmt.Sprintf("%s#%s", d, a)
|
||||
}
|
||||
|
||||
// RewriteEntries list of RewriteEntry
|
||||
// RewriteEntries list of RewriteEntry.
|
||||
type RewriteEntries []RewriteEntry
|
||||
|
||||
// Merge RewriteEntries
|
||||
func (rwe *RewriteEntries) Merge(other *RewriteEntries) (RewriteEntries, RewriteEntries, RewriteEntries) {
|
||||
// Merge RewriteEntries.
|
||||
func (rwe *RewriteEntries) Merge(other *RewriteEntries) (adds, removes, duplicates 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 {
|
||||
@@ -310,16 +300,13 @@ func (rwe *RewriteEntries) Merge(other *RewriteEntries) (RewriteEntries, Rewrite
|
||||
return adds, removes, duplicates
|
||||
}
|
||||
|
||||
func MergeFilters(this *[]Filter, other *[]Filter) ([]Filter, []Filter, []Filter) {
|
||||
func MergeFilters(this, other *[]Filter) (adds, updates, removes []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 _, fi := range *this {
|
||||
current[fi.Url] = &fi
|
||||
@@ -346,7 +333,7 @@ func MergeFilters(this *[]Filter, other *[]Filter) ([]Filter, []Filter, []Filter
|
||||
return adds, updates, removes
|
||||
}
|
||||
|
||||
// Equals Filter equal check
|
||||
// Equals Filter equal check.
|
||||
func (f *Filter) Equals(o *Filter) bool {
|
||||
return f.Enabled == o.Enabled && f.Url == o.Url && f.Name == o.Name
|
||||
}
|
||||
@@ -358,17 +345,17 @@ type QueryLogConfigWithIgnored struct {
|
||||
Ignored []string `json:"ignored,omitempty"`
|
||||
}
|
||||
|
||||
// Equals QueryLogConfig equal check
|
||||
// Equals QueryLogConfig equal check.
|
||||
func (qlc *QueryLogConfigWithIgnored) Equals(o *QueryLogConfigWithIgnored) bool {
|
||||
return utils.JsonEquals(qlc, o)
|
||||
return utils.JSONEquals(qlc, o)
|
||||
}
|
||||
|
||||
// Equals QueryLogConfigInterval equal check
|
||||
// Equals QueryLogConfigInterval equal check.
|
||||
func (qlc *QueryLogConfigInterval) Equals(o *QueryLogConfigInterval) bool {
|
||||
return ptrEquals(qlc, o)
|
||||
}
|
||||
|
||||
func ptrEquals[T comparable](a *T, b *T) bool {
|
||||
func ptrEquals[T comparable](a, b *T) bool {
|
||||
if a == nil && b == nil {
|
||||
return true
|
||||
}
|
||||
@@ -384,7 +371,7 @@ func ptrEquals[T comparable](a *T, b *T) bool {
|
||||
return aa == bb
|
||||
}
|
||||
|
||||
// EnableConfig API struct
|
||||
// EnableConfig API struct.
|
||||
type EnableConfig struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
@@ -421,7 +408,7 @@ func (pi *ProfileInfo) ShouldSyncFor(o *ProfileInfo, withTheme bool) *ProfileInf
|
||||
}
|
||||
|
||||
func (bss *BlockedServicesSchedule) Equals(o *BlockedServicesSchedule) bool {
|
||||
return utils.JsonEquals(bss, o)
|
||||
return utils.JSONEquals(bss, o)
|
||||
}
|
||||
|
||||
func (bss *BlockedServicesSchedule) ServicesString() string {
|
||||
@@ -449,9 +436,9 @@ func (c *DNSConfig) Sanitize(l *zap.SugaredLogger) {
|
||||
}
|
||||
}
|
||||
|
||||
// Equals GetStatsConfigResponse equal check
|
||||
// Equals GetStatsConfigResponse equal check.
|
||||
func (sc *GetStatsConfigResponse) Equals(o *GetStatsConfigResponse) bool {
|
||||
return utils.JsonEquals(sc, o)
|
||||
return utils.JSONEquals(sc, o)
|
||||
}
|
||||
|
||||
func NewStats() *Stats {
|
||||
@@ -482,19 +469,19 @@ func (s *Stats) Add(other *Stats) {
|
||||
s.ReplacedSafebrowsing = sumUp(s.ReplacedSafebrowsing, other.ReplacedSafebrowsing)
|
||||
}
|
||||
|
||||
func addInt(t *int, add *int) *int {
|
||||
func addInt(t, add *int) *int {
|
||||
if add != nil {
|
||||
return ptr.To(*t + *add)
|
||||
}
|
||||
return t
|
||||
}
|
||||
|
||||
func sumUp(t *[]int, o *[]int) *[]int {
|
||||
func sumUp(t, o *[]int) *[]int {
|
||||
if o != nil {
|
||||
tt := *t
|
||||
oo := *o
|
||||
var sum []int
|
||||
for i := 0; i < len(tt); i++ {
|
||||
for i := range tt {
|
||||
if len(oo) >= i {
|
||||
sum = append(sum, tt[i]+oo[i])
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/bakito/adguardhome-sync/pkg/log"
|
||||
"github.com/bakito/adguardhome-sync/pkg/utils"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
"github.com/onsi/gomega"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/log"
|
||||
"github.com/bakito/adguardhome-sync/pkg/utils"
|
||||
)
|
||||
|
||||
var _ = Describe("Types", func() {
|
||||
|
||||
@@ -4,12 +4,13 @@ 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"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/client/model"
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
"github.com/bakito/adguardhome-sync/pkg/utils"
|
||||
)
|
||||
|
||||
var _ = Describe("Types", func() {
|
||||
|
||||
@@ -4,9 +4,10 @@ import (
|
||||
"errors"
|
||||
"regexp"
|
||||
|
||||
"github.com/caarlos0/env/v11"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/log"
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
"github.com/caarlos0/env/v11"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -38,7 +39,7 @@ func Get(configFile string, flags Flags) (*AppConfig, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = validateSchema(path); err != nil {
|
||||
if err := validateSchema(path); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -67,10 +68,10 @@ func Get(configFile string, flags Flags) (*AppConfig, error) {
|
||||
cfg.Replicas = nil
|
||||
|
||||
// overwrite from env vars
|
||||
if err = env.Parse(cfg); err != nil {
|
||||
if err := env.Parse(cfg); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err = env.ParseWithOptions(cfg.Replica, env.Options{Prefix: "REPLICA_"}); err != nil {
|
||||
if err := env.ParseWithOptions(cfg.Replica, env.Options{Prefix: "REPLICA_"}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// restore the replica
|
||||
@@ -81,7 +82,7 @@ func Get(configFile string, flags Flags) (*AppConfig, error) {
|
||||
cfg.Replica.DHCPServerEnabled = replicaDhcpServer
|
||||
}
|
||||
|
||||
if err = env.ParseWithOptions(&cfg.Origin, env.Options{Prefix: "ORIGIN_"}); err != nil {
|
||||
if err := env.ParseWithOptions(&cfg.Origin, env.Options{Prefix: "ORIGIN_"}); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
|
||||
@@ -3,11 +3,12 @@ package config_test
|
||||
import (
|
||||
"os"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/config"
|
||||
flagsmock "github.com/bakito/adguardhome-sync/pkg/mocks/flags"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
gm "go.uber.org/mock/gomock"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/config"
|
||||
flagsmock "github.com/bakito/adguardhome-sync/pkg/mocks/flags"
|
||||
)
|
||||
|
||||
var _ = Describe("Config", func() {
|
||||
@@ -16,7 +17,7 @@ var _ = Describe("Config", func() {
|
||||
flags *flagsmock.MockFlags
|
||||
mockCtrl *gm.Controller
|
||||
changedEnvVars []string
|
||||
setEnv = func(name string, value string) {
|
||||
setEnv = func(name, value string) {
|
||||
_ = os.Setenv(name, value)
|
||||
changedEnvVars = append(changedEnvVars, name)
|
||||
}
|
||||
@@ -125,9 +126,9 @@ var _ = Describe("Config", func() {
|
||||
Ω(cfg.Get().API.Port).Should(Equal(9090))
|
||||
})
|
||||
It("should have the api port from the config flags", func() {
|
||||
flags.EXPECT().Changed(config.FlagApiPort).Return(true).AnyTimes()
|
||||
flags.EXPECT().Changed(config.FlagAPIPort).Return(true).AnyTimes()
|
||||
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
||||
flags.EXPECT().GetInt(config.FlagApiPort).Return(9990, nil).AnyTimes()
|
||||
flags.EXPECT().GetInt(config.FlagAPIPort).Return(9990, nil).AnyTimes()
|
||||
|
||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
@@ -135,9 +136,9 @@ var _ = Describe("Config", func() {
|
||||
})
|
||||
It("should have the api port from the config env var", func() {
|
||||
setEnv("API_PORT", "9999")
|
||||
flags.EXPECT().Changed(config.FlagApiPort).Return(true).AnyTimes()
|
||||
flags.EXPECT().Changed(config.FlagAPIPort).Return(true).AnyTimes()
|
||||
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
||||
flags.EXPECT().GetInt(config.FlagApiPort).Return(9990, nil).AnyTimes()
|
||||
flags.EXPECT().GetInt(config.FlagAPIPort).Return(9990, nil).AnyTimes()
|
||||
|
||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
@@ -174,9 +175,9 @@ var _ = Describe("Config", func() {
|
||||
Ω(cfg.Get().API.Port).Should(Equal(9090))
|
||||
})
|
||||
It("should have the api port from the config flags", func() {
|
||||
flags.EXPECT().Changed(config.FlagApiPort).Return(true).AnyTimes()
|
||||
flags.EXPECT().Changed(config.FlagAPIPort).Return(true).AnyTimes()
|
||||
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
||||
flags.EXPECT().GetInt(config.FlagApiPort).Return(9990, nil).AnyTimes()
|
||||
flags.EXPECT().GetInt(config.FlagAPIPort).Return(9990, nil).AnyTimes()
|
||||
|
||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
@@ -184,9 +185,9 @@ var _ = Describe("Config", func() {
|
||||
})
|
||||
It("should have the api port from the config env var", func() {
|
||||
setEnv("API_PORT", "9999")
|
||||
flags.EXPECT().Changed(config.FlagApiPort).Return(true).AnyTimes()
|
||||
flags.EXPECT().Changed(config.FlagAPIPort).Return(true).AnyTimes()
|
||||
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
||||
flags.EXPECT().GetInt(config.FlagApiPort).Return(9990, nil).AnyTimes()
|
||||
flags.EXPECT().GetInt(config.FlagAPIPort).Return(9990, nil).AnyTimes()
|
||||
|
||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
@@ -202,9 +203,9 @@ var _ = Describe("Config", func() {
|
||||
Ω(cfg.Get().Features.DNS.ServerConfig).Should(BeFalse())
|
||||
})
|
||||
It("should have the feature dns server config from the config flags", func() {
|
||||
flags.EXPECT().Changed(config.FlagFeatureDnsServerConfig).Return(true).AnyTimes()
|
||||
flags.EXPECT().Changed(config.FlagFeatureDNSServerConfig).Return(true).AnyTimes()
|
||||
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
||||
flags.EXPECT().GetBool(config.FlagFeatureDnsServerConfig).Return(true, nil).AnyTimes()
|
||||
flags.EXPECT().GetBool(config.FlagFeatureDNSServerConfig).Return(true, nil).AnyTimes()
|
||||
|
||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
@@ -212,9 +213,9 @@ var _ = Describe("Config", func() {
|
||||
})
|
||||
It("should have the feature dns server config from the config env var", func() {
|
||||
setEnv("FEATURES_DNS_SERVER_CONFIG", "false")
|
||||
flags.EXPECT().Changed(config.FlagFeatureDnsServerConfig).Return(true).AnyTimes()
|
||||
flags.EXPECT().Changed(config.FlagFeatureDNSServerConfig).Return(true).AnyTimes()
|
||||
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
||||
flags.EXPECT().GetBool(config.FlagFeatureDnsServerConfig).Return(true, nil).AnyTimes()
|
||||
flags.EXPECT().GetBool(config.FlagFeatureDNSServerConfig).Return(true, nil).AnyTimes()
|
||||
|
||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
@@ -222,9 +223,9 @@ var _ = Describe("Config", func() {
|
||||
})
|
||||
It("should have the feature dns server config from the config DEPRECATED env var", func() {
|
||||
setEnv("FEATURES_DNS_SERVERCONFIG", "false")
|
||||
flags.EXPECT().Changed(config.FlagFeatureDnsServerConfig).Return(true).AnyTimes()
|
||||
flags.EXPECT().Changed(config.FlagFeatureDNSServerConfig).Return(true).AnyTimes()
|
||||
flags.EXPECT().Changed(gm.Any()).Return(false).AnyTimes()
|
||||
flags.EXPECT().GetBool(config.FlagFeatureDnsServerConfig).Return(true, nil).AnyTimes()
|
||||
flags.EXPECT().GetBool(config.FlagFeatureDNSServerConfig).Return(true, nil).AnyTimes()
|
||||
|
||||
cfg, err := config.Get("../../testdata/config_test_replicas.yaml", flags)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
|
||||
@@ -4,9 +4,10 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/config"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/config"
|
||||
)
|
||||
|
||||
var envVars = []string{
|
||||
|
||||
@@ -6,9 +6,10 @@ import (
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/caarlos0/env/v11"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
"github.com/bakito/adguardhome-sync/pkg/utils"
|
||||
"github.com/caarlos0/env/v11"
|
||||
)
|
||||
|
||||
func handleDeprecatedEnvVars(cfg *types.Config) {
|
||||
@@ -61,20 +62,20 @@ func handleDeprecatedEnvVars(cfg *types.Config) {
|
||||
}
|
||||
}
|
||||
|
||||
func checkDeprecatedEnvVar(oldName string, newName string) (string, bool) {
|
||||
func checkDeprecatedEnvVar(oldName, newName string) (string, bool) {
|
||||
old, oldOK := os.LookupEnv(oldName)
|
||||
if oldOK {
|
||||
logger.With("deprecated", oldName, "replacement", newName).
|
||||
Warn("Deprecated env variable is used, please use the correct one")
|
||||
}
|
||||
new, newOK := os.LookupEnv(newName)
|
||||
newVal, newOK := os.LookupEnv(newName)
|
||||
if newOK {
|
||||
return new, true
|
||||
return newVal, true
|
||||
}
|
||||
return old, oldOK
|
||||
}
|
||||
|
||||
func checkDeprecatedReplicaEnvVar(oldPattern string, newPattern string, replicaID int) (string, bool) {
|
||||
func checkDeprecatedReplicaEnvVar(oldPattern, newPattern string, replicaID int) (string, bool) {
|
||||
return checkDeprecatedEnvVar(fmt.Sprintf(oldPattern, replicaID), fmt.Sprintf(newPattern, replicaID))
|
||||
}
|
||||
|
||||
|
||||
@@ -4,8 +4,9 @@ import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
)
|
||||
|
||||
func readFile(cfg *types.Config, path string) (string, error) {
|
||||
|
||||
@@ -10,9 +10,6 @@ import (
|
||||
)
|
||||
|
||||
var _ = Describe("Config", func() {
|
||||
var ()
|
||||
BeforeEach(func() {
|
||||
})
|
||||
Context("configFilePath", func() {
|
||||
It("should return the same value", func() {
|
||||
path := uuid.NewString()
|
||||
@@ -26,7 +23,7 @@ var _ = Describe("Config", func() {
|
||||
result, err := configFilePath("")
|
||||
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(result).Should(Equal(filepath.Join(home, "/.adguardhome-sync.yaml")))
|
||||
Ω(result).Should(Equal(filepath.Join(home, ".adguardhome-sync.yaml")))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -6,16 +6,16 @@ const (
|
||||
FlagPrintConfigOnly = "printConfigOnly"
|
||||
FlagContinueOnError = "continueOnError"
|
||||
|
||||
FlagApiPort = "api-port"
|
||||
FlagApiUsername = "api-username"
|
||||
FlagApiPassword = "api-password"
|
||||
FlagApiDarkMode = "api-dark-mode"
|
||||
FlagAPIPort = "api-port"
|
||||
FlagAPIUsername = "api-username"
|
||||
FlagAPIPassword = "api-password"
|
||||
FlagAPIDarkMode = "api-dark-mode"
|
||||
|
||||
FlagFeatureDhcpServerConfig = "feature-dhcp-server-config"
|
||||
FlagFeatureDhcpStaticLeases = "feature-dhcp-static-leases"
|
||||
FlagFeatureDnsServerConfig = "feature-dns-server-config"
|
||||
FlagFeatureDnsAccessLists = "feature-dns-access-lists"
|
||||
FlagFeatureDnsRewrites = "feature-dns-rewrites"
|
||||
FlagFeatureDNSServerConfig = "feature-dns-server-config"
|
||||
FlagFeatureDNSAccessLists = "feature-dns-access-lists"
|
||||
FlagFeatureDNSRewrites = "feature-dns-rewrites"
|
||||
FlagFeatureGeneral = "feature-general-settings"
|
||||
FlagFeatureQueryLog = "feature-query-log-config"
|
||||
FlagFeatureStats = "feature-stats-config"
|
||||
@@ -25,7 +25,7 @@ const (
|
||||
|
||||
FlagOriginURL = "origin-url"
|
||||
FlagOriginWebURL = "origin-web-url"
|
||||
FlagOriginApiPath = "origin-api-path"
|
||||
FlagOriginAPIPath = "origin-api-path"
|
||||
FlagOriginUsername = "origin-username"
|
||||
|
||||
FlagOriginPassword = "origin-password"
|
||||
@@ -34,7 +34,7 @@ const (
|
||||
|
||||
FlagReplicaURL = "replica-url"
|
||||
FlagReplicaWebURL = "replica-web-url"
|
||||
FlagReplicaApiPath = "replica-api-path"
|
||||
FlagReplicaAPIPath = "replica-api-path"
|
||||
FlagReplicaUsername = "replica-username"
|
||||
FlagReplicaPassword = "replica-password"
|
||||
FlagReplicaCookie = "replica-cookie"
|
||||
|
||||
@@ -18,7 +18,7 @@ func readFlags(cfg *types.Config, flags Flags) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := fr.readApiFlags(); err != nil {
|
||||
if err := fr.readAPIFlags(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -30,11 +30,7 @@ func readFlags(cfg *types.Config, flags Flags) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := fr.readReplicaFlags(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return fr.readReplicaFlags()
|
||||
}
|
||||
|
||||
type flagReader struct {
|
||||
@@ -53,7 +49,7 @@ func (fr *flagReader) readReplicaFlags() error {
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fr.setStringFlag(FlagReplicaApiPath, func(cgf *types.Config, value string) {
|
||||
if err := fr.setStringFlag(FlagReplicaAPIPath, func(cgf *types.Config, value string) {
|
||||
fr.cfg.Replica.APIPath = value
|
||||
}); err != nil {
|
||||
return err
|
||||
@@ -83,12 +79,9 @@ func (fr *flagReader) readReplicaFlags() error {
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fr.setStringFlag(FlagReplicaInterfaceName, func(cgf *types.Config, value string) {
|
||||
return fr.setStringFlag(FlagReplicaInterfaceName, func(cgf *types.Config, value string) {
|
||||
fr.cfg.Replica.InterfaceName = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (fr *flagReader) readOriginFlags() error {
|
||||
@@ -102,7 +95,7 @@ func (fr *flagReader) readOriginFlags() error {
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fr.setStringFlag(FlagOriginApiPath, func(cgf *types.Config, value string) {
|
||||
if err := fr.setStringFlag(FlagOriginAPIPath, func(cgf *types.Config, value string) {
|
||||
fr.cfg.Origin.APIPath = value
|
||||
}); err != nil {
|
||||
return err
|
||||
@@ -122,12 +115,9 @@ func (fr *flagReader) readOriginFlags() error {
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fr.setBoolFlag(FlagOriginISV, func(cgf *types.Config, value bool) {
|
||||
return fr.setBoolFlag(FlagOriginISV, func(cgf *types.Config, value bool) {
|
||||
fr.cfg.Origin.InsecureSkipVerify = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (fr *flagReader) readFeatureFlags() error {
|
||||
@@ -142,17 +132,17 @@ func (fr *flagReader) readFeatureFlags() error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := fr.setBoolFlag(FlagFeatureDnsServerConfig, func(cgf *types.Config, value bool) {
|
||||
if err := fr.setBoolFlag(FlagFeatureDNSServerConfig, func(cgf *types.Config, value bool) {
|
||||
fr.cfg.Features.DNS.ServerConfig = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fr.setBoolFlag(FlagFeatureDnsAccessLists, func(cgf *types.Config, value bool) {
|
||||
if err := fr.setBoolFlag(FlagFeatureDNSAccessLists, func(cgf *types.Config, value bool) {
|
||||
fr.cfg.Features.DNS.AccessLists = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fr.setBoolFlag(FlagFeatureDnsRewrites, func(cgf *types.Config, value bool) {
|
||||
if err := fr.setBoolFlag(FlagFeatureDNSRewrites, func(cgf *types.Config, value bool) {
|
||||
fr.cfg.Features.DNS.Rewrites = value
|
||||
}); err != nil {
|
||||
return err
|
||||
@@ -183,61 +173,51 @@ func (fr *flagReader) readFeatureFlags() error {
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := fr.setBoolFlag(FlagFeatureFilters, func(cgf *types.Config, value bool) {
|
||||
return fr.setBoolFlag(FlagFeatureFilters, func(cgf *types.Config, value bool) {
|
||||
fr.cfg.Features.Filters = value
|
||||
})
|
||||
}
|
||||
|
||||
func (fr *flagReader) readAPIFlags() error {
|
||||
if err := fr.setIntFlag(FlagAPIPort, func(cgf *types.Config, value int) {
|
||||
fr.cfg.API.Port = value
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fr *flagReader) readApiFlags() (err error) {
|
||||
if err = fr.setIntFlag(FlagApiPort, func(cgf *types.Config, value int) {
|
||||
fr.cfg.API.Port = value
|
||||
}); err != nil {
|
||||
return
|
||||
}
|
||||
if err = fr.setStringFlag(FlagApiUsername, func(cgf *types.Config, value string) {
|
||||
if err := fr.setStringFlag(FlagAPIUsername, func(cgf *types.Config, value string) {
|
||||
fr.cfg.API.Username = value
|
||||
}); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
if err = fr.setStringFlag(FlagApiPassword, func(cgf *types.Config, value string) {
|
||||
if err := fr.setStringFlag(FlagAPIPassword, func(cgf *types.Config, value string) {
|
||||
fr.cfg.API.Password = value
|
||||
}); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
if err = fr.setBoolFlag(FlagApiDarkMode, func(cgf *types.Config, value bool) {
|
||||
return fr.setBoolFlag(FlagAPIDarkMode, func(cgf *types.Config, value bool) {
|
||||
fr.cfg.API.DarkMode = value
|
||||
}); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
func (fr *flagReader) readRootFlags() (err error) {
|
||||
if err = fr.setStringFlag(FlagCron, func(cgf *types.Config, value string) {
|
||||
func (fr *flagReader) readRootFlags() error {
|
||||
if err := fr.setStringFlag(FlagCron, func(cgf *types.Config, value string) {
|
||||
fr.cfg.Cron = value
|
||||
}); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
if err = fr.setBoolFlag(FlagRunOnStart, func(cgf *types.Config, value bool) {
|
||||
if err := fr.setBoolFlag(FlagRunOnStart, func(cgf *types.Config, value bool) {
|
||||
fr.cfg.RunOnStart = value
|
||||
}); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
if err = fr.setBoolFlag(FlagPrintConfigOnly, func(cgf *types.Config, value bool) {
|
||||
if err := fr.setBoolFlag(FlagPrintConfigOnly, func(cgf *types.Config, value bool) {
|
||||
fr.cfg.PrintConfigOnly = value
|
||||
}); err != nil {
|
||||
return
|
||||
return err
|
||||
}
|
||||
if err = fr.setBoolFlag(FlagContinueOnError, func(cgf *types.Config, value bool) {
|
||||
return fr.setBoolFlag(FlagContinueOnError, func(cgf *types.Config, value bool) {
|
||||
fr.cfg.ContinueOnError = value
|
||||
}); err != nil {
|
||||
return
|
||||
}
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
type Flags interface {
|
||||
@@ -249,33 +229,33 @@ type Flags interface {
|
||||
|
||||
func (fr *flagReader) setStringFlag(name string, cb callback[string]) (err error) {
|
||||
if fr.flags.Changed(name) {
|
||||
if value, err := fr.flags.GetString(name); err != nil {
|
||||
var value string
|
||||
if value, err = fr.flags.GetString(name); err != nil {
|
||||
return err
|
||||
} else {
|
||||
cb(fr.cfg, value)
|
||||
}
|
||||
cb(fr.cfg, value)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fr *flagReader) setBoolFlag(name string, cb callback[bool]) (err error) {
|
||||
if fr.flags.Changed(name) {
|
||||
if value, err := fr.flags.GetBool(name); err != nil {
|
||||
var value bool
|
||||
if value, err = fr.flags.GetBool(name); err != nil {
|
||||
return err
|
||||
} else {
|
||||
cb(fr.cfg, value)
|
||||
}
|
||||
cb(fr.cfg, value)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (fr *flagReader) setIntFlag(name string, cb callback[int]) (err error) {
|
||||
if fr.flags.Changed(name) {
|
||||
if value, err := fr.flags.GetInt(name); err != nil {
|
||||
var value int
|
||||
if value, err = fr.flags.GetInt(name); err != nil {
|
||||
return err
|
||||
} else {
|
||||
cb(fr.cfg, value)
|
||||
}
|
||||
cb(fr.cfg, value)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -3,11 +3,12 @@ package config
|
||||
import (
|
||||
"strings"
|
||||
|
||||
flagsmock "github.com/bakito/adguardhome-sync/pkg/mocks/flags"
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
gm "go.uber.org/mock/gomock"
|
||||
|
||||
flagsmock "github.com/bakito/adguardhome-sync/pkg/mocks/flags"
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
)
|
||||
|
||||
var _ = Describe("Config", func() {
|
||||
@@ -88,7 +89,7 @@ var _ = Describe("Config", func() {
|
||||
}))
|
||||
})
|
||||
})
|
||||
Context("readApiFlags", func() {
|
||||
Context("readAPIFlags", func() {
|
||||
It("should change all values", func() {
|
||||
cfg.API = types.API{
|
||||
Port: 1111,
|
||||
@@ -99,10 +100,10 @@ var _ = Describe("Config", func() {
|
||||
flags.EXPECT().Changed(gm.Any()).DoAndReturn(func(name string) bool {
|
||||
return strings.HasPrefix(name, "api")
|
||||
}).AnyTimes()
|
||||
flags.EXPECT().GetInt(FlagApiPort).Return(9999, nil)
|
||||
flags.EXPECT().GetString(FlagApiUsername).Return("aaaa", nil)
|
||||
flags.EXPECT().GetString(FlagApiPassword).Return("bbbb", nil)
|
||||
flags.EXPECT().GetBool(FlagApiDarkMode).Return(true, nil)
|
||||
flags.EXPECT().GetInt(FlagAPIPort).Return(9999, nil)
|
||||
flags.EXPECT().GetString(FlagAPIUsername).Return("aaaa", nil)
|
||||
flags.EXPECT().GetString(FlagAPIPassword).Return("bbbb", nil)
|
||||
flags.EXPECT().GetBool(FlagAPIDarkMode).Return(true, nil)
|
||||
err := readFlags(cfg, flags)
|
||||
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
@@ -154,7 +155,7 @@ var _ = Describe("Config", func() {
|
||||
|
||||
flags.EXPECT().Changed(FlagOriginURL).Return(true)
|
||||
flags.EXPECT().Changed(FlagOriginWebURL).Return(true)
|
||||
flags.EXPECT().Changed(FlagOriginApiPath).Return(true)
|
||||
flags.EXPECT().Changed(FlagOriginAPIPath).Return(true)
|
||||
flags.EXPECT().Changed(FlagOriginUsername).Return(true)
|
||||
flags.EXPECT().Changed(FlagOriginPassword).Return(true)
|
||||
flags.EXPECT().Changed(FlagOriginCookie).Return(true)
|
||||
@@ -163,7 +164,7 @@ var _ = Describe("Config", func() {
|
||||
|
||||
flags.EXPECT().GetString(FlagOriginURL).Return("a", nil)
|
||||
flags.EXPECT().GetString(FlagOriginWebURL).Return("b", nil)
|
||||
flags.EXPECT().GetString(FlagOriginApiPath).Return("c", nil)
|
||||
flags.EXPECT().GetString(FlagOriginAPIPath).Return("c", nil)
|
||||
flags.EXPECT().GetString(FlagOriginUsername).Return("d", nil)
|
||||
flags.EXPECT().GetString(FlagOriginPassword).Return("e", nil)
|
||||
flags.EXPECT().GetString(FlagOriginCookie).Return("f", nil)
|
||||
@@ -198,7 +199,7 @@ var _ = Describe("Config", func() {
|
||||
|
||||
flags.EXPECT().Changed(FlagReplicaURL).Return(true)
|
||||
flags.EXPECT().Changed(FlagReplicaWebURL).Return(true)
|
||||
flags.EXPECT().Changed(FlagReplicaApiPath).Return(true)
|
||||
flags.EXPECT().Changed(FlagReplicaAPIPath).Return(true)
|
||||
flags.EXPECT().Changed(FlagReplicaUsername).Return(true)
|
||||
flags.EXPECT().Changed(FlagReplicaPassword).Return(true)
|
||||
flags.EXPECT().Changed(FlagReplicaCookie).Return(true)
|
||||
@@ -209,7 +210,7 @@ var _ = Describe("Config", func() {
|
||||
|
||||
flags.EXPECT().GetString(FlagReplicaURL).Return("a", nil)
|
||||
flags.EXPECT().GetString(FlagReplicaWebURL).Return("b", nil)
|
||||
flags.EXPECT().GetString(FlagReplicaApiPath).Return("c", nil)
|
||||
flags.EXPECT().GetString(FlagReplicaAPIPath).Return("c", nil)
|
||||
flags.EXPECT().GetString(FlagReplicaUsername).Return("d", nil)
|
||||
flags.EXPECT().GetString(FlagReplicaPassword).Return("e", nil)
|
||||
flags.EXPECT().GetString(FlagReplicaCookie).Return("f", nil)
|
||||
|
||||
@@ -9,10 +9,11 @@ import (
|
||||
"strings"
|
||||
"text/template"
|
||||
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/client"
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
"github.com/bakito/adguardhome-sync/version"
|
||||
"gopkg.in/yaml.v3"
|
||||
)
|
||||
|
||||
//go:embed print-config.md
|
||||
@@ -25,7 +26,7 @@ func (ac *AppConfig) Print() error {
|
||||
replicaVersions = append(replicaVersions, aghVersion(replica))
|
||||
}
|
||||
|
||||
out, err := ac.print(os.Environ(), originVersion, replicaVersions)
|
||||
out, err := ac.printInternal(os.Environ(), originVersion, replicaVersions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -50,7 +51,7 @@ func aghVersion(i types.AdGuardInstance) string {
|
||||
return stats.Version
|
||||
}
|
||||
|
||||
func (ac *AppConfig) print(env []string, originVersion string, replicaVersions []string) (string, error) {
|
||||
func (ac *AppConfig) printInternal(env []string, originVersion string, replicaVersions []string) (string, error) {
|
||||
config, err := yaml.Marshal(ac.Get())
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -72,7 +73,7 @@ func (ac *AppConfig) print(env []string, originVersion string, replicaVersions [
|
||||
|
||||
var buf bytes.Buffer
|
||||
|
||||
if err = t.Execute(&buf, map[string]interface{}{
|
||||
err = t.Execute(&buf, map[string]any{
|
||||
"Version": version.Version,
|
||||
"Build": version.Build,
|
||||
"OperatingSystem": runtime.GOOS,
|
||||
@@ -83,8 +84,6 @@ func (ac *AppConfig) print(env []string, originVersion string, replicaVersions [
|
||||
"EnvironmentVariables": strings.Join(env, "\n"),
|
||||
"OriginVersion": originVersion,
|
||||
"ReplicaVersions": replicaVersions,
|
||||
}); err != nil {
|
||||
return "", err
|
||||
}
|
||||
return buf.String(), nil
|
||||
})
|
||||
return buf.String(), err
|
||||
}
|
||||
|
||||
@@ -7,10 +7,11 @@ import (
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
"github.com/bakito/adguardhome-sync/version"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
"github.com/bakito/adguardhome-sync/version"
|
||||
)
|
||||
|
||||
var _ = Describe("AppConfig", func() {
|
||||
@@ -32,17 +33,17 @@ origin:
|
||||
}
|
||||
env = []string{"FOO=foo", "BAR=bar"}
|
||||
})
|
||||
Context("print", func() {
|
||||
It("should print config without file", func() {
|
||||
out, err := ac.print(env, "v0.0.1", []string{"v0.0.2"})
|
||||
Context("printInternal", func() {
|
||||
It("should printInternal config without file", func() {
|
||||
out, err := ac.printInternal(env, "v0.0.1", []string{"v0.0.2"})
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(
|
||||
out,
|
||||
).Should(Equal(fmt.Sprintf(expected(1), version.Version, version.Build, runtime.GOOS, runtime.GOARCH)))
|
||||
})
|
||||
It("should print config with file", func() {
|
||||
It("should printInternal config with file", func() {
|
||||
ac.filePath = "config.yaml"
|
||||
out, err := ac.print(env, "v0.0.1", []string{"v0.0.2"})
|
||||
out, err := ac.printInternal(env, "v0.0.1", []string{"v0.0.2"})
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
Ω(
|
||||
out,
|
||||
@@ -52,7 +53,9 @@ origin:
|
||||
})
|
||||
|
||||
func expected(id int) string {
|
||||
b, err := os.ReadFile(filepath.Join("../../testdata/config", fmt.Sprintf("print-config_test_expected%d.md", id)))
|
||||
b, err := os.ReadFile(
|
||||
filepath.Join("..", "..", "testdata", "config", fmt.Sprintf("print-config_test_expected%d.md", id)),
|
||||
)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
return string(b)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package config
|
||||
|
||||
import (
|
||||
_ "embed"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
@@ -17,20 +18,26 @@ var schemaData string
|
||||
func validateSchema(cfgFile string) error {
|
||||
// ignore if file not exists
|
||||
if _, err := os.Stat(cfgFile); err != nil {
|
||||
// Config file does not exist or is not readable - ignore it
|
||||
//nolint:nilerr
|
||||
return nil
|
||||
}
|
||||
// Load YAML file
|
||||
yamlContent, err := os.ReadFile(cfgFile)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("config file %q is invalid: %w", cfgFile, err)
|
||||
}
|
||||
|
||||
return validateYAML(yamlContent)
|
||||
}
|
||||
|
||||
func validateYAML(yamlContent []byte) error {
|
||||
if yamlContent == nil || strings.TrimSpace(string(yamlContent)) == "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Convert YAML to JSON
|
||||
var yamlData interface{}
|
||||
var yamlData any
|
||||
err := yaml.Unmarshal(yamlContent, &yamlData)
|
||||
if err != nil {
|
||||
return err
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
"github.com/go-faker/faker/v4"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"gopkg.in/yaml.v3"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/types"
|
||||
)
|
||||
|
||||
var _ = Describe("Config", func() {
|
||||
@@ -35,5 +36,10 @@ var _ = Describe("Config", func() {
|
||||
err = validateYAML(data)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
It("validate config with empty file", func() {
|
||||
var data []byte
|
||||
err := validateYAML(data)
|
||||
Ω(err).ShouldNot(HaveOccurred())
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
@@ -18,7 +18,7 @@ var (
|
||||
logs []string
|
||||
)
|
||||
|
||||
// GetLogger returns a named logger
|
||||
// GetLogger returns a named logger.
|
||||
func GetLogger(name string) *zap.SugaredLogger {
|
||||
return rootLogger.Named(name).Sugar()
|
||||
}
|
||||
@@ -101,12 +101,12 @@ func (l *logList) Sync() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Logs get the current logs
|
||||
// Logs get the current logs.
|
||||
func Logs() []string {
|
||||
return logs
|
||||
}
|
||||
|
||||
// Clear the current logs
|
||||
// Clear the current logs.
|
||||
func Clear() {
|
||||
logs = nil
|
||||
}
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/client/model"
|
||||
"github.com/bakito/adguardhome-sync/pkg/log"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
const StatsTotal = "total"
|
||||
@@ -11,7 +12,7 @@ const StatsTotal = "total"
|
||||
var (
|
||||
l = log.GetLogger("metrics")
|
||||
|
||||
// avgProcessingTime - Average processing time for a DNS query
|
||||
// avgProcessingTime - Average processing time for a DNS query.
|
||||
avgProcessingTime = prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "avg_processing_time",
|
||||
@@ -21,7 +22,7 @@ var (
|
||||
[]string{"hostname"},
|
||||
)
|
||||
|
||||
// dnsQueries - Number of DNS queries
|
||||
// dnsQueries - Number of DNS queries.
|
||||
dnsQueries = prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "num_dns_queries",
|
||||
@@ -31,7 +32,7 @@ var (
|
||||
[]string{"hostname"},
|
||||
)
|
||||
|
||||
// blockedFiltering - Number of DNS queries blocked
|
||||
// blockedFiltering - Number of DNS queries blocked.
|
||||
blockedFiltering = prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "num_blocked_filtering",
|
||||
@@ -41,7 +42,7 @@ var (
|
||||
[]string{"hostname"},
|
||||
)
|
||||
|
||||
// parentalFiltering - Number of DNS queries replaced by parental control
|
||||
// parentalFiltering - Number of DNS queries replaced by parental control.
|
||||
parentalFiltering = prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "num_replaced_parental",
|
||||
@@ -51,7 +52,7 @@ var (
|
||||
[]string{"hostname"},
|
||||
)
|
||||
|
||||
// safeBrowsingFiltering - Number of DNS queries replaced by safe browsing
|
||||
// safeBrowsingFiltering - Number of DNS queries replaced by safe browsing.
|
||||
safeBrowsingFiltering = prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "num_replaced_safebrowsing",
|
||||
@@ -61,7 +62,7 @@ var (
|
||||
[]string{"hostname"},
|
||||
)
|
||||
|
||||
// safeSearchFiltering - Number of DNS queries replaced by safe search
|
||||
// safeSearchFiltering - Number of DNS queries replaced by safe search.
|
||||
safeSearchFiltering = prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "num_replaced_safesearch",
|
||||
@@ -71,7 +72,7 @@ var (
|
||||
[]string{"hostname"},
|
||||
)
|
||||
|
||||
// topQueries - The number of top queries
|
||||
// topQueries - The number of top queries.
|
||||
topQueries = prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "top_queried_domains",
|
||||
@@ -81,7 +82,7 @@ var (
|
||||
[]string{"hostname", "domain"},
|
||||
)
|
||||
|
||||
// topBlocked - The number of top domains blocked
|
||||
// topBlocked - The number of top domains blocked.
|
||||
topBlocked = prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "top_blocked_domains",
|
||||
@@ -91,7 +92,7 @@ var (
|
||||
[]string{"hostname", "domain"},
|
||||
)
|
||||
|
||||
// topClients - The number of top clients
|
||||
// topClients - The number of top clients.
|
||||
topClients = prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "top_clients",
|
||||
@@ -111,7 +112,7 @@ var (
|
||||
[]string{"hostname", "type"},
|
||||
)
|
||||
|
||||
// running - If Adguard is running
|
||||
// running - If Adguard is running.
|
||||
running = prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "running",
|
||||
@@ -121,7 +122,7 @@ var (
|
||||
[]string{"hostname"},
|
||||
)
|
||||
|
||||
// protectionEnabled - If Adguard protection is enabled
|
||||
// protectionEnabled - If Adguard protection is enabled.
|
||||
protectionEnabled = prometheus.NewGaugeVec(
|
||||
prometheus.GaugeOpts{
|
||||
Name: "protection_enabled",
|
||||
@@ -157,22 +158,22 @@ func initMetric(name string, metric *prometheus.GaugeVec) {
|
||||
|
||||
func Update(iml InstanceMetricsList) {
|
||||
for _, im := range iml.Metrics {
|
||||
update(im)
|
||||
updateMetrics(im)
|
||||
stats[im.HostName] = im.Stats
|
||||
}
|
||||
|
||||
l.Debug("updated")
|
||||
}
|
||||
|
||||
func update(im InstanceMetrics) {
|
||||
func updateMetrics(im InstanceMetrics) {
|
||||
// Status
|
||||
var isRunning int = 0
|
||||
isRunning := 0
|
||||
if im.Status.Running {
|
||||
isRunning = 1
|
||||
}
|
||||
running.WithLabelValues(im.HostName).Set(float64(isRunning))
|
||||
|
||||
var isProtected int = 0
|
||||
isProtected := 0
|
||||
if im.Status.ProtectionEnabled {
|
||||
isProtected = 1
|
||||
}
|
||||
@@ -218,7 +219,7 @@ func update(im InstanceMetrics) {
|
||||
if len(dnsanswer) > 0 {
|
||||
for _, dnsa := range dnsanswer {
|
||||
dnsType := *dnsa.Type
|
||||
m[dnsType] += 1
|
||||
m[dnsType]++
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"github.com/bakito/adguardhome-sync/pkg/client/model"
|
||||
"github.com/go-faker/faker/v4"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
"k8s.io/utils/ptr"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/client/model"
|
||||
)
|
||||
|
||||
var _ = Describe("Metrics", func() {
|
||||
@@ -85,15 +86,15 @@ var _ = Describe("Metrics", func() {
|
||||
})
|
||||
})
|
||||
|
||||
func verifyStats(lines []line) {
|
||||
var total line
|
||||
func verifyStats(lines []Line) {
|
||||
var total Line
|
||||
sum := make([]int, len(lines[0].Data))
|
||||
for _, l := range lines {
|
||||
if l.Title == labelTotal {
|
||||
total = l
|
||||
} else {
|
||||
for i, d := range l.Data {
|
||||
sum[i] = sum[i] + d
|
||||
sum[i] += d
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -47,19 +47,19 @@ var (
|
||||
}
|
||||
)
|
||||
|
||||
func StatsGraph() (*model.Stats, []line, []line, []line, []line) {
|
||||
func StatsGraph() (t *model.Stats, dns, blocked, malware, adult []Line) {
|
||||
s := getStats()
|
||||
t := s.Total()
|
||||
dns := graphLines(t, s, blue, blueAlternatives, func(s *model.Stats) []int {
|
||||
t = s.Total()
|
||||
dns = graphLines(t, s, blue, blueAlternatives, func(s *model.Stats) []int {
|
||||
return safeStats(s.DnsQueries)
|
||||
})
|
||||
blocked := graphLines(t, s, red, redAlternatives, func(s *model.Stats) []int {
|
||||
blocked = graphLines(t, s, red, redAlternatives, func(s *model.Stats) []int {
|
||||
return safeStats(s.BlockedFiltering)
|
||||
})
|
||||
malware := graphLines(t, s, green, greenAlternatives, func(s *model.Stats) []int {
|
||||
malware = graphLines(t, s, green, greenAlternatives, func(s *model.Stats) []int {
|
||||
return safeStats(s.ReplacedSafebrowsing)
|
||||
})
|
||||
adult := graphLines(t, s, yellow, yellowAlternatives, func(s *model.Stats) []int {
|
||||
adult = graphLines(t, s, yellow, yellowAlternatives, func(s *model.Stats) []int {
|
||||
return safeStats(s.ReplacedParental)
|
||||
})
|
||||
|
||||
@@ -79,9 +79,9 @@ func graphLines(
|
||||
baseColor []int,
|
||||
altColors [][]int,
|
||||
dataCB func(s *model.Stats) []int,
|
||||
) []line {
|
||||
) []Line {
|
||||
g := &graph{
|
||||
total: line{
|
||||
total: Line{
|
||||
Fill: true,
|
||||
Title: labelTotal,
|
||||
Data: dataCB(t),
|
||||
@@ -94,7 +94,7 @@ func graphLines(
|
||||
var i int
|
||||
for name, data := range s {
|
||||
if name != StatsTotal {
|
||||
g.replicas = append(g.replicas, line{
|
||||
g.replicas = append(g.replicas, Line{
|
||||
Fill: false,
|
||||
Title: name,
|
||||
Data: dataCB(data),
|
||||
@@ -106,9 +106,9 @@ func graphLines(
|
||||
}
|
||||
}
|
||||
|
||||
lines := []line{g.total}
|
||||
lines := []Line{g.total}
|
||||
|
||||
slices.SortFunc(g.replicas, func(a, b line) int {
|
||||
slices.SortFunc(g.replicas, func(a, b Line) int {
|
||||
return strings.Compare(a.Title, b.Title)
|
||||
})
|
||||
lines = append(lines, g.replicas...)
|
||||
@@ -116,11 +116,11 @@ func graphLines(
|
||||
}
|
||||
|
||||
type graph struct {
|
||||
total line
|
||||
replicas []line
|
||||
total Line
|
||||
replicas []Line
|
||||
}
|
||||
|
||||
type line struct {
|
||||
type Line struct {
|
||||
Data []int `json:"data"`
|
||||
R int `json:"r"`
|
||||
G int `json:"g"`
|
||||
|
||||
@@ -384,17 +384,17 @@ func (mr *MockClientMockRecorder) SafeSearchConfig() *gomock.Call {
|
||||
}
|
||||
|
||||
// SetAccessList mocks base method.
|
||||
func (m *MockClient) SetAccessList(arg0 *model.AccessList) error {
|
||||
func (m *MockClient) SetAccessList(accessList *model.AccessList) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SetAccessList", arg0)
|
||||
ret := m.ctrl.Call(m, "SetAccessList", accessList)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SetAccessList indicates an expected call of SetAccessList.
|
||||
func (mr *MockClientMockRecorder) SetAccessList(arg0 any) *gomock.Call {
|
||||
func (mr *MockClientMockRecorder) SetAccessList(accessList any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetAccessList", reflect.TypeOf((*MockClient)(nil).SetAccessList), arg0)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetAccessList", reflect.TypeOf((*MockClient)(nil).SetAccessList), accessList)
|
||||
}
|
||||
|
||||
// SetBlockedServicesSchedule mocks base method.
|
||||
@@ -426,31 +426,31 @@ func (mr *MockClientMockRecorder) SetCustomRules(rules any) *gomock.Call {
|
||||
}
|
||||
|
||||
// SetDNSConfig mocks base method.
|
||||
func (m *MockClient) SetDNSConfig(arg0 *model.DNSConfig) error {
|
||||
func (m *MockClient) SetDNSConfig(config *model.DNSConfig) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SetDNSConfig", arg0)
|
||||
ret := m.ctrl.Call(m, "SetDNSConfig", config)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SetDNSConfig indicates an expected call of SetDNSConfig.
|
||||
func (mr *MockClientMockRecorder) SetDNSConfig(arg0 any) *gomock.Call {
|
||||
func (mr *MockClientMockRecorder) SetDNSConfig(config any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDNSConfig", reflect.TypeOf((*MockClient)(nil).SetDNSConfig), arg0)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDNSConfig", reflect.TypeOf((*MockClient)(nil).SetDNSConfig), config)
|
||||
}
|
||||
|
||||
// SetDhcpConfig mocks base method.
|
||||
func (m *MockClient) SetDhcpConfig(arg0 *model.DhcpStatus) error {
|
||||
func (m *MockClient) SetDhcpConfig(status *model.DhcpStatus) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SetDhcpConfig", arg0)
|
||||
ret := m.ctrl.Call(m, "SetDhcpConfig", status)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SetDhcpConfig indicates an expected call of SetDhcpConfig.
|
||||
func (mr *MockClientMockRecorder) SetDhcpConfig(arg0 any) *gomock.Call {
|
||||
func (mr *MockClientMockRecorder) SetDhcpConfig(status any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDhcpConfig", reflect.TypeOf((*MockClient)(nil).SetDhcpConfig), arg0)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetDhcpConfig", reflect.TypeOf((*MockClient)(nil).SetDhcpConfig), status)
|
||||
}
|
||||
|
||||
// SetProfileInfo mocks base method.
|
||||
@@ -468,17 +468,17 @@ func (mr *MockClientMockRecorder) SetProfileInfo(settings any) *gomock.Call {
|
||||
}
|
||||
|
||||
// SetQueryLogConfig mocks base method.
|
||||
func (m *MockClient) SetQueryLogConfig(arg0 *model.QueryLogConfigWithIgnored) error {
|
||||
func (m *MockClient) SetQueryLogConfig(ql *model.QueryLogConfigWithIgnored) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SetQueryLogConfig", arg0)
|
||||
ret := m.ctrl.Call(m, "SetQueryLogConfig", ql)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// SetQueryLogConfig indicates an expected call of SetQueryLogConfig.
|
||||
func (mr *MockClientMockRecorder) SetQueryLogConfig(arg0 any) *gomock.Call {
|
||||
func (mr *MockClientMockRecorder) SetQueryLogConfig(ql any) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetQueryLogConfig", reflect.TypeOf((*MockClient)(nil).SetQueryLogConfig), arg0)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SetQueryLogConfig", reflect.TypeOf((*MockClient)(nil).SetQueryLogConfig), ql)
|
||||
}
|
||||
|
||||
// SetSafeSearchConfig mocks base method.
|
||||
@@ -496,7 +496,7 @@ func (mr *MockClientMockRecorder) SetSafeSearchConfig(settings any) *gomock.Call
|
||||
}
|
||||
|
||||
// SetStatsConfig mocks base method.
|
||||
func (m *MockClient) SetStatsConfig(sc *model.GetStatsConfigResponse) error {
|
||||
func (m *MockClient) SetStatsConfig(sc *model.PutStatsConfigUpdateRequest) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SetStatsConfig", sc)
|
||||
ret0, _ := ret[0].(error)
|
||||
@@ -539,10 +539,10 @@ func (mr *MockClientMockRecorder) Stats() *gomock.Call {
|
||||
}
|
||||
|
||||
// StatsConfig mocks base method.
|
||||
func (m *MockClient) StatsConfig() (*model.GetStatsConfigResponse, error) {
|
||||
func (m *MockClient) StatsConfig() (*model.PutStatsConfigUpdateRequest, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "StatsConfig")
|
||||
ret0, _ := ret[0].(*model.GetStatsConfigResponse)
|
||||
ret0, _ := ret[0].(*model.PutStatsConfigUpdateRequest)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package sync
|
||||
|
||||
import (
|
||||
"go.uber.org/zap"
|
||||
|
||||
"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 (
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
package sync
|
||||
|
||||
import (
|
||||
"go.uber.org/zap"
|
||||
|
||||
"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) {
|
||||
|
||||
@@ -14,10 +14,11 @@ import (
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/log"
|
||||
"github.com/bakito/adguardhome-sync/pkg/metrics"
|
||||
"github.com/bakito/adguardhome-sync/version"
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -35,13 +36,13 @@ func (w *worker) handleSync(c *gin.Context) {
|
||||
func (w *worker) handleRoot(c *gin.Context) {
|
||||
total, dns, blocked, malware, adult := metrics.StatsGraph()
|
||||
|
||||
c.HTML(http.StatusOK, "index.html", map[string]interface{}{
|
||||
c.HTML(http.StatusOK, "index.html", map[string]any{
|
||||
"DarkMode": w.cfg.API.DarkMode,
|
||||
"Metrics": w.cfg.API.Metrics.Enabled,
|
||||
"Version": version.Version,
|
||||
"Build": version.Build,
|
||||
"SyncStatus": w.status(),
|
||||
"Stats": map[string]interface{}{
|
||||
"Stats": map[string]any{
|
||||
"Labels": getLast24Hours(),
|
||||
"DNS": dns,
|
||||
"Blocked": blocked,
|
||||
@@ -169,8 +170,6 @@ func (w *worker) listenAndServe() {
|
||||
|
||||
// manually cancel context if not using httpServer.RegisterOnShutdown(cancel)
|
||||
cancel()
|
||||
|
||||
defer os.Exit(0)
|
||||
}
|
||||
|
||||
type syncStatus struct {
|
||||
@@ -192,7 +191,7 @@ func getLast24Hours() []string {
|
||||
currentTime := time.Now()
|
||||
|
||||
// Loop to get the last 24 hours
|
||||
for i := 0; i < 24; i++ {
|
||||
for i := range 24 {
|
||||
// Calculate the time for the current hour in the loop
|
||||
timeInstance := currentTime.Add(time.Duration(-i) * time.Hour)
|
||||
timeInstance = timeInstance.Truncate(time.Hour)
|
||||
|
||||
@@ -35,16 +35,17 @@ func (w *worker) scrape() {
|
||||
metrics.Update(iml)
|
||||
}
|
||||
|
||||
func (w *worker) getMetrics(inst types.AdGuardInstance) (im metrics.InstanceMetrics) {
|
||||
func (w *worker) getMetrics(inst types.AdGuardInstance) metrics.InstanceMetrics {
|
||||
var im metrics.InstanceMetrics
|
||||
client, err := w.createClient(inst)
|
||||
if err != nil {
|
||||
l.With("error", err, "url", w.cfg.Origin.URL).Error("Error creating origin client")
|
||||
return
|
||||
return im
|
||||
}
|
||||
|
||||
im.HostName = inst.Host
|
||||
im.Status, _ = client.Status()
|
||||
im.Stats, _ = client.Stats()
|
||||
im.QueryLog, _ = client.QueryLog(w.cfg.API.Metrics.QueryLogLimit)
|
||||
return
|
||||
return im
|
||||
}
|
||||
|
||||
@@ -2,11 +2,13 @@ package sync
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"runtime"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/robfig/cron/v3"
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/client"
|
||||
"github.com/bakito/adguardhome-sync/pkg/client/model"
|
||||
"github.com/bakito/adguardhome-sync/pkg/log"
|
||||
@@ -14,20 +16,18 @@ import (
|
||||
"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"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
var l = log.GetLogger("sync")
|
||||
|
||||
// Sync config from origin to replica
|
||||
// Sync config from origin to replica.
|
||||
func Sync(cfg *types.Config) error {
|
||||
if cfg.Origin.URL == "" {
|
||||
return fmt.Errorf("origin URL is required")
|
||||
return errors.New("origin URL is required")
|
||||
}
|
||||
|
||||
if len(cfg.UniqueReplicas()) == 0 {
|
||||
return fmt.Errorf("no replicas configured")
|
||||
return errors.New("no replicas configured")
|
||||
}
|
||||
|
||||
l.With(
|
||||
@@ -41,10 +41,8 @@ func Sync(cfg *types.Config) error {
|
||||
cfg.Origin.AutoSetup = false
|
||||
|
||||
w := &worker{
|
||||
cfg: cfg,
|
||||
createClient: func(ai types.AdGuardInstance) (client.Client, error) {
|
||||
return client.New(ai)
|
||||
},
|
||||
cfg: cfg,
|
||||
createClient: client.New,
|
||||
}
|
||||
if cfg.Cron != "" {
|
||||
w.cron = cron.New()
|
||||
@@ -120,15 +118,15 @@ func (w *worker) status() *syncStatus {
|
||||
return syncStatus
|
||||
}
|
||||
|
||||
func (w *worker) getStatus(inst types.AdGuardInstance) (st replicaStatus) {
|
||||
st = replicaStatus{Host: inst.WebHost, URL: inst.WebURL}
|
||||
func (w *worker) getStatus(inst types.AdGuardInstance) 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
|
||||
return st
|
||||
}
|
||||
sl := l.With("from", inst.WebHost)
|
||||
status, err := oc.Status()
|
||||
@@ -136,16 +134,16 @@ func (w *worker) getStatus(inst types.AdGuardInstance) (st replicaStatus) {
|
||||
if errors.Is(err, client.ErrSetupNeeded) {
|
||||
st.Status = "warning"
|
||||
st.Error = err.Error()
|
||||
return
|
||||
return st
|
||||
}
|
||||
sl.With("error", err).Error("Error getting origin status")
|
||||
st.Status = "danger"
|
||||
st.Error = err.Error()
|
||||
return
|
||||
return st
|
||||
}
|
||||
st.Status = "success"
|
||||
st.ProtectionEnabled = utils.Ptr(status.ProtectionEnabled)
|
||||
return
|
||||
return st
|
||||
}
|
||||
|
||||
func (w *worker) sync() {
|
||||
|
||||
@@ -3,16 +3,17 @@ package sync
|
||||
import (
|
||||
"errors"
|
||||
|
||||
"github.com/google/uuid"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
gm "go.uber.org/mock/gomock"
|
||||
|
||||
"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"
|
||||
"github.com/google/uuid"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
gm "go.uber.org/mock/gomock"
|
||||
)
|
||||
|
||||
var _ = Describe("Sync", func() {
|
||||
|
||||
@@ -25,33 +25,33 @@ func NewFeatures(enabled bool) Features {
|
||||
}
|
||||
}
|
||||
|
||||
// Features feature flags
|
||||
// Features feature flags.
|
||||
type Features struct {
|
||||
DNS DNS `json:"dns" yaml:"dns"`
|
||||
DHCP DHCP `json:"dhcp" yaml:"dhcp"`
|
||||
GeneralSettings bool `json:"generalSettings" yaml:"generalSettings" env:"FEATURES_GENERAL_SETTINGS"`
|
||||
QueryLogConfig bool `json:"queryLogConfig" yaml:"queryLogConfig" env:"FEATURES_QUERY_LOG_CONFIG"`
|
||||
StatsConfig bool `json:"statsConfig" yaml:"statsConfig" env:"FEATURES_STATS_CONFIG"`
|
||||
ClientSettings bool `json:"clientSettings" yaml:"clientSettings" env:"FEATURES_CLIENT_SETTINGS"`
|
||||
Services bool `json:"services" yaml:"services" env:"FEATURES_SERVICES"`
|
||||
Filters bool `json:"filters" yaml:"filters" env:"FEATURES_FILTERS"`
|
||||
Theme bool `json:"theme" yaml:"theme" env:"FEATURES_THEME"`
|
||||
GeneralSettings bool `json:"generalSettings" yaml:"generalSettings" documentation:"Sync general settings" env:"FEATURES_GENERAL_SETTINGS"`
|
||||
QueryLogConfig bool `json:"queryLogConfig" yaml:"queryLogConfig" documentation:"Sync query log config" env:"FEATURES_QUERY_LOG_CONFIG"`
|
||||
StatsConfig bool `json:"statsConfig" yaml:"statsConfig" documentation:"Sync stats config" env:"FEATURES_STATS_CONFIG"`
|
||||
ClientSettings bool `json:"clientSettings" yaml:"clientSettings" documentation:"Sync client settings" env:"FEATURES_CLIENT_SETTINGS"`
|
||||
Services bool `json:"services" yaml:"services" documentation:"Sync services" env:"FEATURES_SERVICES"`
|
||||
Filters bool `json:"filters" yaml:"filters" documentation:"Sync filters" env:"FEATURES_FILTERS"`
|
||||
Theme bool `json:"theme" yaml:"theme" documentation:"Sync the weg UI theme" env:"FEATURES_THEME"`
|
||||
}
|
||||
|
||||
// DHCP features
|
||||
// DHCP features.
|
||||
type DHCP struct {
|
||||
ServerConfig bool `json:"serverConfig" yaml:"serverConfig" env:"FEATURES_DHCP_SERVER_CONFIG"`
|
||||
StaticLeases bool `json:"staticLeases" yaml:"staticLeases" env:"FEATURES_DHCP_STATIC_LEASES"`
|
||||
ServerConfig bool `documentation:"Sync DHCP server config" env:"FEATURES_DHCP_SERVER_CONFIG" json:"serverConfig" yaml:"serverConfig"`
|
||||
StaticLeases bool `documentation:"Sync DHCP static leases" env:"FEATURES_DHCP_STATIC_LEASES" json:"staticLeases" yaml:"staticLeases"`
|
||||
}
|
||||
|
||||
// DNS features
|
||||
// DNS features.
|
||||
type DNS struct {
|
||||
AccessLists bool `json:"accessLists" yaml:"accessLists" env:"FEATURES_DNS_ACCESS_LISTS"`
|
||||
ServerConfig bool `json:"serverConfig" yaml:"serverConfig" env:"FEATURES_DNS_SERVER_CONFIG"`
|
||||
Rewrites bool `json:"rewrites" yaml:"rewrites" env:"FEATURES_DNS_REWRITES"`
|
||||
AccessLists bool `documentation:"Sync DNS access lists" env:"FEATURES_DNS_ACCESS_LISTS" json:"accessLists" yaml:"accessLists"`
|
||||
ServerConfig bool `documentation:"Sync DNS server config" env:"FEATURES_DNS_SERVER_CONFIG" json:"serverConfig" yaml:"serverConfig"`
|
||||
Rewrites bool `documentation:"Sync DNS rewrites" env:"FEATURES_DNS_REWRITES" json:"rewrites" yaml:"rewrites"`
|
||||
}
|
||||
|
||||
// LogDisabled log all disabled features
|
||||
// LogDisabled log all disabled features.
|
||||
func (f *Features) LogDisabled(l *zap.SugaredLogger) {
|
||||
features := f.collectDisabled()
|
||||
|
||||
|
||||
@@ -11,72 +11,75 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
// DefaultAPIPath default api path
|
||||
// DefaultAPIPath default api path.
|
||||
DefaultAPIPath = "/control"
|
||||
)
|
||||
|
||||
// Config application configuration struct
|
||||
// +k8s:deepcopy-gen=true
|
||||
type Config struct {
|
||||
Origin AdGuardInstance `json:"origin" yaml:"origin" env:"ORIGIN"`
|
||||
Replica *AdGuardInstance `json:"replica,omitempty" yaml:"replica,omitempty" env:"REPLICA"`
|
||||
Replicas []AdGuardInstance `json:"replicas,omitempty" yaml:"replicas,omitempty" faker:"slice_len=2"`
|
||||
Cron string `json:"cron,omitempty" yaml:"cron,omitempty" env:"CRON"`
|
||||
RunOnStart bool `json:"runOnStart,omitempty" yaml:"runOnStart,omitempty" env:"RUN_ON_START"`
|
||||
PrintConfigOnly bool `json:"printConfigOnly,omitempty" yaml:"printConfigOnly,omitempty" env:"PRINT_CONFIG_ONLY"`
|
||||
ContinueOnError bool `json:"continueOnError,omitempty" yaml:"continueOnError,omitempty" env:"CONTINUE_ON_ERROR"`
|
||||
API API `json:"api,omitempty" yaml:"api,omitempty" env:"API"`
|
||||
Features Features `json:"features,omitempty" yaml:"features,omitempty" env:"FEATURES_"`
|
||||
// Origin adguardhome instance
|
||||
Origin AdGuardInstance `env:"ORIGIN" json:"origin" yaml:"origin"`
|
||||
// One single replica adguardhome instance
|
||||
Replica *AdGuardInstance `env:"REPLICA" json:"replica,omitempty" yaml:"replica,omitempty"`
|
||||
// Multiple replica instances
|
||||
Replicas []AdGuardInstance ` json:"replicas,omitempty" yaml:"replicas,omitempty" faker:"slice_len=2"`
|
||||
Cron string `env:"CRON" json:"cron,omitempty" yaml:"cron,omitempty" documentation:"Cron expression for the sync interval"`
|
||||
RunOnStart bool `env:"RUN_ON_START" json:"runOnStart,omitempty" yaml:"runOnStart,omitempty" documentation:"Run the sung on startup"`
|
||||
PrintConfigOnly bool `env:"PRINT_CONFIG_ONLY" json:"printConfigOnly,omitempty" yaml:"printConfigOnly,omitempty" documentation:"Print current config only and stop the application"`
|
||||
ContinueOnError bool `env:"CONTINUE_ON_ERROR" json:"continueOnError,omitempty" yaml:"continueOnError,omitempty" documentation:"Continue sync on errors"`
|
||||
API API ` json:"api,omitempty" yaml:"api,omitempty"`
|
||||
Features Features ` json:"features,omitempty" yaml:"features,omitempty"`
|
||||
}
|
||||
|
||||
// API configuration
|
||||
// API configuration.
|
||||
type API struct {
|
||||
Port int `json:"port,omitempty" yaml:"port,omitempty" env:"API_PORT"`
|
||||
Username string `json:"username,omitempty" yaml:"username,omitempty" env:"API_USERNAME"`
|
||||
Password string `json:"password,omitempty" yaml:"password,omitempty" env:"API_PASSWORD"`
|
||||
DarkMode bool `json:"darkMode,omitempty" yaml:"darkMode,omitempty" env:"API_DARK_MODE"`
|
||||
Metrics Metrics `json:"metrics,omitempty" yaml:"metrics,omitempty" env:"API_METRICS"`
|
||||
TLS TLS `json:"tls,omitempty" yaml:"tls,omitempty" env:"API_TLS"`
|
||||
Port int `documentation:"API port" env:"API_PORT" json:"port,omitempty" yaml:"port,omitempty"`
|
||||
Username string `documentation:"API username" env:"API_USERNAME" json:"username,omitempty" yaml:"username,omitempty"`
|
||||
Password string `documentation:"API password" env:"API_PASSWORD" json:"password,omitempty" yaml:"password,omitempty"`
|
||||
DarkMode bool `documentation:"API dark mode" env:"API_DARK_MODE" json:"darkMode,omitempty" yaml:"darkMode,omitempty"`
|
||||
Metrics Metrics ` json:"metrics,omitempty" yaml:"metrics,omitempty"`
|
||||
TLS TLS ` json:"tls,omitempty" yaml:"tls,omitempty"`
|
||||
}
|
||||
|
||||
// Metrics configuration
|
||||
// Metrics configuration.
|
||||
type Metrics struct {
|
||||
Enabled bool `json:"enabled,omitempty" yaml:"enabled,omitempty" env:"API_METRICS_ENABLED"`
|
||||
ScrapeInterval time.Duration `json:"scrapeInterval,omitempty" yaml:"scrapeInterval,omitempty" env:"API_METRICS_SCRAPE_INTERVAL"`
|
||||
QueryLogLimit int `json:"queryLogLimit,omitempty" yaml:"queryLogLimit,omitempty" env:"API_METRICS_QUERY_LOG_LIMIT"`
|
||||
Enabled bool `documentation:"Enable metrics" env:"API_METRICS_ENABLED" json:"enabled,omitempty" yaml:"enabled,omitempty"`
|
||||
ScrapeInterval time.Duration `documentation:"Interval for metrics scraping" env:"API_METRICS_SCRAPE_INTERVAL" json:"scrapeInterval,omitempty" yaml:"scrapeInterval,omitempty"`
|
||||
QueryLogLimit int `documentation:"Metrics log query limit" env:"API_METRICS_QUERY_LOG_LIMIT" json:"queryLogLimit,omitempty" yaml:"queryLogLimit,omitempty"`
|
||||
}
|
||||
|
||||
// TLS configuration
|
||||
// TLS configuration.
|
||||
type TLS struct {
|
||||
CertDir string `json:"certDir,omitempty" yaml:"certDir,omitempty" env:"API_TLS_CERT_DIR"`
|
||||
CertName string `json:"certName,omitempty" yaml:"certName,omitempty" env:"API_TLS_CERT_NAME"`
|
||||
KeyName string `json:"keyName,omitempty" yaml:"keyName,omitempty" env:"API_TLS_KEY_NAME"`
|
||||
CertDir string `documentation:"API TLS certificate directory" env:"API_TLS_CERT_DIR" json:"certDir,omitempty" yaml:"certDir,omitempty"`
|
||||
CertName string `documentation:"API TLS certificate file name" env:"API_TLS_CERT_NAME" json:"certName,omitempty" yaml:"certName,omitempty"`
|
||||
KeyName string `documentation:"API TLS key file name" env:"API_TLS_KEY_NAME" json:"keyName,omitempty" yaml:"keyName,omitempty"`
|
||||
}
|
||||
|
||||
func (t TLS) Enabled() bool {
|
||||
return strings.TrimSpace(t.CertDir) != ""
|
||||
}
|
||||
|
||||
func (t TLS) Certs() (cert string, key string) {
|
||||
func (t TLS) Certs() (cert, key string) {
|
||||
cert = filepath.Join(t.CertDir, defaultIfEmpty(t.CertName, "tls.crt"))
|
||||
key = filepath.Join(t.CertDir, defaultIfEmpty(t.KeyName, "tls.key"))
|
||||
return
|
||||
return cert, key
|
||||
}
|
||||
|
||||
func defaultIfEmpty(val string, fallback string) string {
|
||||
func defaultIfEmpty(val, fallback string) string {
|
||||
if strings.TrimSpace(val) == "" {
|
||||
return fallback
|
||||
}
|
||||
return val
|
||||
}
|
||||
|
||||
// Mask maks username and password
|
||||
// Mask maks username and password.
|
||||
func (a *API) Mask() {
|
||||
a.Username = mask(a.Username)
|
||||
a.Password = mask(a.Password)
|
||||
}
|
||||
|
||||
// UniqueReplicas get unique replication instances
|
||||
// UniqueReplicas get unique replication instances.
|
||||
func (cfg *Config) UniqueReplicas() []AdGuardInstance {
|
||||
dedup := make(map[string]AdGuardInstance)
|
||||
if cfg.Replica != nil && cfg.Replica.URL != "" {
|
||||
@@ -101,7 +104,7 @@ func (cfg *Config) UniqueReplicas() []AdGuardInstance {
|
||||
return r
|
||||
}
|
||||
|
||||
// Log the current config
|
||||
// Log the current config.
|
||||
func (cfg *Config) Log(l *zap.SugaredLogger) {
|
||||
c := cfg.mask()
|
||||
l.With("config", c).Debug("Using config")
|
||||
@@ -140,27 +143,27 @@ func (cfg *Config) Init() error {
|
||||
// AdGuardInstance AdguardHome config instance
|
||||
// +k8s:deepcopy-gen=true
|
||||
type AdGuardInstance struct {
|
||||
URL string `json:"url" yaml:"url" env:"URL" faker:"url"`
|
||||
WebURL string `json:"webURL" yaml:"webURL" env:"WEB_URL" faker:"url"`
|
||||
APIPath string `json:"apiPath,omitempty" yaml:"apiPath,omitempty" env:"API_PATH"`
|
||||
Username string `json:"username,omitempty" yaml:"username,omitempty" env:"USERNAME"`
|
||||
Password string `json:"password,omitempty" yaml:"password,omitempty" env:"PASSWORD"`
|
||||
Cookie string `json:"cookie,omitempty" yaml:"cookie,omitempty" env:"COOKIE"`
|
||||
InsecureSkipVerify bool `json:"insecureSkipVerify" yaml:"insecureSkipVerify" env:"INSECURE_SKIP_VERIFY"`
|
||||
AutoSetup bool `json:"autoSetup" yaml:"autoSetup" env:"AUTO_SETUP"`
|
||||
InterfaceName string `json:"interfaceName,omitempty" yaml:"interfaceName,omitempty" env:"INTERFACE_NAME"`
|
||||
DHCPServerEnabled *bool `json:"dhcpServerEnabled,omitempty" yaml:"dhcpServerEnabled,omitempty" env:"DHCP_SERVER_ENABLED"`
|
||||
URL string `documentation:"URL of adguardhome instance" env:"URL" faker:"url" json:"url" yaml:"url"`
|
||||
WebURL string `documentation:"Web URL of adguardhome instance" env:"WEB_URL" faker:"url" json:"webURL" yaml:"webURL"`
|
||||
APIPath string `documentation:"API Path" env:"API_PATH" json:"apiPath,omitempty" yaml:"apiPath,omitempty"`
|
||||
Username string `documentation:"Adguardhome username" env:"USERNAME" json:"username,omitempty" yaml:"username,omitempty"`
|
||||
Password string `documentation:"Adguardhome password" env:"PASSWORD" json:"password,omitempty" yaml:"password,omitempty"`
|
||||
Cookie string `documentation:"Adguardhome cookie" env:"COOKIE" json:"cookie,omitempty" yaml:"cookie,omitempty"`
|
||||
InsecureSkipVerify bool `documentation:"Skip TLS verification" env:"INSECURE_SKIP_VERIFY" json:"insecureSkipVerify" yaml:"insecureSkipVerify"`
|
||||
AutoSetup bool `documentation:"Automatically setup the instance if it is not initialized" env:"AUTO_SETUP" json:"autoSetup" yaml:"autoSetup"`
|
||||
InterfaceName string `documentation:"Network interface name" env:"INTERFACE_NAME" json:"interfaceName,omitempty" yaml:"interfaceName,omitempty"`
|
||||
DHCPServerEnabled *bool `documentation:"Enable DHCP server" env:"DHCP_SERVER_ENABLED" json:"dhcpServerEnabled,omitempty" yaml:"dhcpServerEnabled,omitempty"`
|
||||
|
||||
Host string `json:"-" yaml:"-"`
|
||||
WebHost string `json:"-" yaml:"-"`
|
||||
}
|
||||
|
||||
// Key AdGuardInstance key
|
||||
// Key AdGuardInstance key.
|
||||
func (i *AdGuardInstance) Key() string {
|
||||
return fmt.Sprintf("%s#%s", i.URL, i.APIPath)
|
||||
}
|
||||
|
||||
// Mask maks username and password
|
||||
// Mask maks username and password.
|
||||
func (i *AdGuardInstance) Mask() {
|
||||
i.Username = mask(i.Username)
|
||||
i.Password = mask(i.Password)
|
||||
@@ -194,12 +197,12 @@ func mask(s string) string {
|
||||
return fmt.Sprintf("%v%s%v", string(s[0]), mask, string(s[len(s)-1]))
|
||||
}
|
||||
|
||||
// Protection API struct
|
||||
// Protection API struct.
|
||||
type Protection struct {
|
||||
ProtectionEnabled bool `json:"protection_enabled"`
|
||||
}
|
||||
|
||||
// InstallConfig AdguardHome install config
|
||||
// InstallConfig AdguardHome install config.
|
||||
type InstallConfig struct {
|
||||
Web InstallPort `json:"web"`
|
||||
DNS InstallPort `json:"dns"`
|
||||
@@ -207,7 +210,7 @@ type InstallConfig struct {
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
// InstallPort AdguardHome install config port
|
||||
// InstallPort AdguardHome install config port.
|
||||
type InstallPort struct {
|
||||
IP string `json:"ip"`
|
||||
Port int `json:"port"`
|
||||
|
||||
@@ -1,15 +1,18 @@
|
||||
package utils
|
||||
|
||||
import "encoding/json"
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
)
|
||||
|
||||
func Clone[I interface{}](in I, out I) I {
|
||||
func Clone[I any](in, out I) I {
|
||||
b, _ := json.Marshal(in)
|
||||
_ = json.Unmarshal(b, out)
|
||||
return out
|
||||
}
|
||||
|
||||
func JsonEquals(a interface{}, b interface{}) bool {
|
||||
func JSONEquals(a, b any) bool {
|
||||
ja, _ := json.Marshal(a)
|
||||
jb, _ := json.Marshal(b)
|
||||
return string(ja) == string(jb)
|
||||
return bytes.Equal(ja, jb)
|
||||
}
|
||||
|
||||
@@ -2,18 +2,18 @@ package utils
|
||||
|
||||
import "fmt"
|
||||
|
||||
func Ptr[I interface{}](i I) *I {
|
||||
func Ptr[I any](i I) *I {
|
||||
return &i
|
||||
}
|
||||
|
||||
func PtrToString[I interface{}](i *I) string {
|
||||
func PtrToString[I any](i *I) string {
|
||||
if i == nil {
|
||||
return ""
|
||||
}
|
||||
return fmt.Sprintf("%v", i)
|
||||
}
|
||||
|
||||
func PtrEquals[I comparable](a *I, b *I) bool {
|
||||
func PtrEquals[I comparable](a, b *I) bool {
|
||||
if a == nil && b == nil {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -3,15 +3,15 @@ package versions
|
||||
import "golang.org/x/mod/semver"
|
||||
|
||||
const (
|
||||
// MinAgh minimal adguardhome version
|
||||
// MinAgh minimal adguardhome version.
|
||||
MinAgh = "v0.107.40"
|
||||
)
|
||||
|
||||
func IsNewerThan(v1 string, v2 string) bool {
|
||||
func IsNewerThan(v1, v2 string) bool {
|
||||
return semver.Compare(sanitize(v1), sanitize(v2)) == 1
|
||||
}
|
||||
|
||||
func IsSame(v1 string, v2 string) bool {
|
||||
func IsSame(v1, v2 string) bool {
|
||||
return semver.Compare(sanitize(v1), sanitize(v2)) == 0
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
package versions_test
|
||||
|
||||
import (
|
||||
"github.com/bakito/adguardhome-sync/pkg/versions"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
|
||||
"github.com/bakito/adguardhome-sync/pkg/versions"
|
||||
)
|
||||
|
||||
var _ = Describe("Versions", func() {
|
||||
|
||||
16
testdata/test-layout.kdl
vendored
Normal file
16
testdata/test-layout.kdl
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
layout {
|
||||
pane split_direction="vertical" {
|
||||
pane name="main"
|
||||
pane {
|
||||
pane {
|
||||
command "make"
|
||||
args "start-replica"
|
||||
}
|
||||
pane {
|
||||
command "make"
|
||||
args "start-replica2"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
package version
|
||||
|
||||
var (
|
||||
// Version the module version
|
||||
// Version the module version.
|
||||
Version = "devel"
|
||||
// Build the build time
|
||||
// Build the build time.
|
||||
Build = "N/A"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user