mirror of
https://github.com/tuna/tunasync.git
synced 2025-06-13 04:17:00 +00:00
Compare commits
53 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
528b799bc4 | ||
|
436386fb73 | ||
|
0933b65144 | ||
|
833027a6a0 | ||
|
a5b72b8c55 | ||
|
033aa60540 | ||
|
d2b3e731bf | ||
|
c01de06ac3 | ||
|
ece3e3d9e3 | ||
|
0a00097301 | ||
|
245a8bfc3f | ||
|
a64557b86d | ||
|
27e4307375 | ||
|
ad97ef8421 | ||
|
748f276d49 | ||
|
0ebfc58126 | ||
|
ab8d1c2120 | ||
|
559f5705f6 | ||
|
f8d7ea1828 | ||
|
b4ca6f4c1e | ||
|
113df44f19 | ||
|
e903c644f2 | ||
|
181fddb87c | ||
|
a6a03decf0 | ||
|
5fb63e119c | ||
|
95c4d54ee2 | ||
|
ef32197fef | ||
|
99c7ab6b65 | ||
|
ab416f6545 | ||
|
15e87a5f48 | ||
|
3ad551f73d | ||
|
3562907af9 | ||
|
6d50645ddb | ||
|
95ba9586e0 | ||
|
c73becc0f1 | ||
|
6132446bc7 | ||
|
bfcbfe75bc | ||
|
fcb8dd5f3a | ||
|
938f67c7b4 | ||
|
dca04a3220 | ||
|
c45974c0bf | ||
|
755c87761d | ||
|
7bc3e8f193 | ||
|
8ddcc46255 | ||
|
37b15d157a | ||
|
f2b22d059c | ||
|
45099fc7d3 | ||
|
c3b742c2a8 | ||
|
68a3149e8d | ||
|
b372744640 | ||
|
4007bb2e4d | ||
|
bca49abd3c | ||
|
60f92ceebb |
46
.github/workflows/release.yml
vendored
46
.github/workflows/release.yml
vendored
@ -1,46 +1,38 @@
|
||||
name: release
|
||||
on:
|
||||
push:
|
||||
# Sequence of patterns matched against refs/tags
|
||||
tags:
|
||||
- 'v*' # Push events to matching v*, i.e. v1.0, v20.15.10
|
||||
- 'v*'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.13
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.13
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
|
||||
uses: actions/checkout@v4
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '^1.23'
|
||||
id: go
|
||||
- name: Build
|
||||
run: |
|
||||
for i in linux-amd64 linux-arm64; do
|
||||
TAG=$(git describe --tags)
|
||||
for i in linux-amd64 linux-arm64 linux-riscv64 linux-loong64; do
|
||||
make ARCH=$i all
|
||||
tar -cz --numeric-owner --owner root --group root -f tunasync-$i-bin.tar.gz -C build-$i tunasync tunasynctl
|
||||
tar -cz --numeric-owner --owner root --group root -f tunasync-${TAG}-$i-bin.tar.gz -C build-$i tunasync tunasynctl
|
||||
done
|
||||
|
||||
- name: Create Release
|
||||
id: create_release
|
||||
uses: actions/create-release@v1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: ${{ github.ref }}
|
||||
release_name: Release ${{ github.ref }}
|
||||
draft: false
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
tag_name: ${{ github.ref_name }}
|
||||
name: Release ${{ github.ref_name }}
|
||||
prerelease: false
|
||||
- name: Upload Release Assets
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TAG_NAME: ${{ github.ref }}
|
||||
run: |
|
||||
hub release edit $(find . -type f -name "tunasync-*.tar.gz" -printf "-a %p ") -m "" "${TAG_NAME##*/}"
|
||||
files: |
|
||||
tunasync-*.tar.gz
|
||||
|
99
.github/workflows/tunasync.yml
vendored
99
.github/workflows/tunasync.yml
vendored
@ -1,6 +1,11 @@
|
||||
name: tunasync
|
||||
|
||||
on: [push]
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
|
||||
@ -9,14 +14,14 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Set up Go 1.16
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.16
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '^1.23'
|
||||
id: go
|
||||
|
||||
- name: Get dependencies
|
||||
run: |
|
||||
@ -29,7 +34,7 @@ jobs:
|
||||
make tunasynctl
|
||||
|
||||
- name: Keep artifacts
|
||||
uses: actions/upload-artifact@v1
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: tunasync-bin
|
||||
path: build-linux-amd64/
|
||||
@ -49,28 +54,30 @@ jobs:
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y cgroup-tools
|
||||
docker pull alpine:3.8
|
||||
lssubsys -am
|
||||
sudo cgcreate -a $USER -t $USER -g cpu:tunasync
|
||||
sudo cgcreate -a $USER -t $USER -g memory:tunasync
|
||||
|
||||
- name: Set up Go 1.16
|
||||
uses: actions/setup-go@v1
|
||||
with:
|
||||
go-version: 1.16
|
||||
id: go
|
||||
|
||||
- name: Check out code into the Go module directory
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '^1.22'
|
||||
id: go
|
||||
|
||||
- name: Run Unit tests.
|
||||
run: |
|
||||
go install github.com/wadey/gocovmerge@latest
|
||||
TERM=xterm-256color make test
|
||||
sudo systemd-run --service-type=oneshot --uid="$(id --user)" --pipe --wait \
|
||||
--property=Delegate=yes --setenv=USECURCGROUP=1 \
|
||||
--setenv=TERM=xterm-256color --same-dir \
|
||||
make test
|
||||
|
||||
- name: Run Additional Unit tests.
|
||||
run: |
|
||||
make build-test-worker
|
||||
sudo cgexec -g "*:/" bash -c "echo 0 > /sys/fs/cgroup/systemd/tasks; exec sudo -u $USER env USECURCGROUP=1 TERM=xterm-256color cgexec -g cpu,memory:tunasync ./worker.test -test.v=true -test.coverprofile profile2.cov -test.run TestCgroup"
|
||||
sudo mkdir /sys/fs/cgroup/tunasync
|
||||
sudo ./worker.test -test.v=true -test.coverprofile profile2.gcov -test.run TestCgroup
|
||||
sudo rmdir /sys/fs/cgroup/tunasync
|
||||
touch /tmp/dummy_exec
|
||||
chmod +x /tmp/dummy_exec
|
||||
run_test_reexec (){
|
||||
@ -78,7 +85,7 @@ jobs:
|
||||
shift
|
||||
argv0="$1"
|
||||
shift
|
||||
(TESTREEXEC="$case" TERM=xterm-256color exec -a "$argv0" ./worker.test -test.v=true -test.coverprofile "profile5_$case.cov" -test.run TestReexec -- "$@")
|
||||
(TESTREEXEC="$case" TERM=xterm-256color exec -a "$argv0" ./worker.test -test.v=true -test.coverprofile "profile5_$case.gcov" -test.run TestReexec -- "$@")
|
||||
}
|
||||
run_test_reexec 1 tunasync-exec __dummy__
|
||||
run_test_reexec 2 tunasync-exec /tmp/dummy_exec
|
||||
@ -87,11 +94,11 @@ jobs:
|
||||
run_test_reexec 5 tunasync-exec2
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
uses: docker/setup-buildx-action@v3
|
||||
with:
|
||||
driver-opts: network=host
|
||||
- name: Cache Docker layers
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v4
|
||||
if: github.event_name == 'push'
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
@ -99,7 +106,7 @@ jobs:
|
||||
restore-keys: |
|
||||
${{ runner.os }}-buildx-
|
||||
- name: Cache Docker layers
|
||||
uses: actions/cache@v2
|
||||
uses: actions/cache@v4
|
||||
if: github.event_name == 'pull_request'
|
||||
with:
|
||||
path: /tmp/.buildx-cache
|
||||
@ -118,7 +125,7 @@ jobs:
|
||||
mkdir -p /tmp/.buildx-cache
|
||||
|
||||
- name: Build Docker image for uml rootfs
|
||||
uses: docker/build-push-action@v2
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .umlrootfs
|
||||
file: .umlrootfs/Dockerfile
|
||||
@ -132,10 +139,10 @@ jobs:
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y debian-archive-keyring
|
||||
sudo ln -sf /usr/share/keyrings/debian-archive-keyring.gpg /etc/apt/trusted.gpg.d/
|
||||
echo "deb http://deb.debian.org/debian buster main" | sudo tee /etc/apt/sources.list.d/buster.list
|
||||
echo "deb http://deb.debian.org/debian bullseye main" | sudo tee /etc/apt/sources.list.d/bullseye.list
|
||||
sudo apt-get update
|
||||
apt-get download user-mode-linux/buster
|
||||
sudo rm /etc/apt/sources.list.d/buster.list
|
||||
apt-get download user-mode-linux/bullseye
|
||||
sudo rm /etc/apt/sources.list.d/bullseye.list
|
||||
sudo apt-get update
|
||||
sudo mv user-mode-linux_*.deb /tmp/uml.deb
|
||||
sudo apt-get install --no-install-recommends -y /tmp/uml.deb
|
||||
@ -157,7 +164,7 @@ jobs:
|
||||
- name: Start Uml
|
||||
run: |
|
||||
start_uml () {
|
||||
sudo bash -c 'linux root=/dev/root rootflags=/ rw rootfstype=hostfs mem=2G eth0=tuntap,umltap hostfs="$PWD/umlrootfs" con1=pts systemd.unified_cgroup_hierarchy=1 & pid=$!; echo "UMLINUX_PID=$pid" >> '"$GITHUB_ENV"
|
||||
sudo bash -c 'linux root=/dev/root rootflags=/ rw rootfstype=hostfs mem=2G eth0=tuntap,umltap hostfs="$PWD/umlrootfs" con1=pts systemd.unified_cgroup_hierarchy=0 & pid=$!; echo "UMLINUX_PID=$pid" >> '"$GITHUB_ENV"
|
||||
}
|
||||
( start_uml )
|
||||
started=0
|
||||
@ -184,20 +191,18 @@ jobs:
|
||||
EOF
|
||||
ln ./worker.test "umlrootfs/home/${CUSER}/worker.test"
|
||||
|
||||
- name: Run Tests in Cgroupv2
|
||||
- name: Run Tests in Cgroupv1
|
||||
run: |
|
||||
CUSER="$(id --user --name)"
|
||||
sudo rsh 254.255.255.2 bash --noprofile --norc -eo pipefail << EOF
|
||||
exec 2>&1
|
||||
cd "/home/${CUSER}"
|
||||
mkdir -p /sys/fs/cgroup/tunasync
|
||||
lssubsys -am
|
||||
cgcreate -a "$CUSER" -t "$CUSER" -g cpu:tunasync
|
||||
cgcreate -a "$CUSER" -t "$CUSER" -g memory:tunasync
|
||||
TERM=xterm-256color ./worker.test -test.v=true -test.coverprofile \
|
||||
profile3.cov -test.run TestCgroup
|
||||
rmdir /sys/fs/cgroup/tunasync
|
||||
systemd-run --service-type=oneshot --uid="${CUSER}" --pipe --wait \
|
||||
--property=Delegate=yes --setenv=USECURCGROUP=1 \
|
||||
--setenv=TERM=xterm-256color --same-dir \
|
||||
"\${PWD}/worker.test" -test.v=true -test.coverprofile \
|
||||
profile4.cov -test.run TestCgroup
|
||||
profile3.gcov -test.run TestCgroup
|
||||
cgexec -g "*:/" bash -c "echo 0 > /sys/fs/cgroup/systemd/tasks; exec sudo -u $CUSER env USECURCGROUP=1 TERM=xterm-256color cgexec -g cpu,memory:tunasync ./worker.test -test.v=true -test.coverprofile profile4.gcov -test.run TestCgroup"
|
||||
EOF
|
||||
|
||||
- name: Stop Uml
|
||||
@ -222,19 +227,21 @@ jobs:
|
||||
- name: Combine coverage files
|
||||
run : |
|
||||
CUSER="$(id --user --name)"
|
||||
"${HOME}/go/bin/gocovmerge" profile.cov profile2.cov \
|
||||
"umlrootfs/home/${CUSER}/profile3.cov" \
|
||||
"umlrootfs/home/${CUSER}/profile4.cov" \
|
||||
profile5_*.cov > profile-all.cov
|
||||
"${HOME}/go/bin/gocovmerge" profile.gcov profile2.gcov \
|
||||
"umlrootfs/home/${CUSER}/profile3.gcov" \
|
||||
"umlrootfs/home/${CUSER}/profile4.gcov" \
|
||||
profile5_*.gcov > merged.gcov
|
||||
# remove cmdline tools from coverage statistics
|
||||
grep -v "cmd/.*\.go" merged.gcov > profile-all.gcov
|
||||
|
||||
- name: Convert coverage to lcov
|
||||
uses: jandelgado/gcov2lcov-action@v1.0.0
|
||||
uses: jandelgado/gcov2lcov-action@v1
|
||||
with:
|
||||
infile: profile-all.cov
|
||||
infile: profile-all.gcov
|
||||
outfile: coverage.lcov
|
||||
|
||||
- name: Coveralls
|
||||
uses: coverallsapp/github-action@v1.0.1
|
||||
uses: coverallsapp/github-action@v2
|
||||
with:
|
||||
github-token: ${{ secrets.github_token }}
|
||||
path-to-lcov: coverage.lcov
|
||||
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,2 +1,4 @@
|
||||
/build
|
||||
/build-*
|
||||
worker.test
|
||||
profile*
|
@ -1,13 +1,8 @@
|
||||
FROM debian:buster
|
||||
RUN apt-get update && apt-get install -y systemd rsh-redone-server ifupdown sudo kmod
|
||||
FROM debian:bullseye
|
||||
RUN apt-get update && apt-get install -y systemd rsh-redone-server ifupdown sudo kmod cgroup-tools systemd-sysv
|
||||
RUN echo "host" > /root/.rhosts && \
|
||||
chmod 600 /root/.rhosts && \
|
||||
/bin/echo -e "auto eth0\niface eth0 inet static\naddress 254.255.255.2/24" > /etc/network/interfaces.d/eth0 && \
|
||||
sed -i '/pam_securetty/d' /etc/pam.d/rlogin && \
|
||||
cp /usr/share/systemd/tmp.mount /etc/systemd/system && \
|
||||
systemctl enable tmp.mount
|
||||
|
||||
RUN echo "deb http://deb.debian.org/debian experimental main" >> /etc/apt/sources.list && \
|
||||
apt-get update && \
|
||||
apt-get install -y make && \
|
||||
apt-get install -y -t experimental cgroup-tools
|
||||
|
11
Makefile
11
Makefile
@ -14,12 +14,15 @@ $(BUILDBIN): % : build-$(ARCH) build-$(ARCH)/%
|
||||
|
||||
$(BUILDBIN:%=build-$(ARCH)/%) : build-$(ARCH)/% : cmd/%
|
||||
GOOS=$(GOOS) GOARCH=$(GOARCH) go get ./$<
|
||||
GOOS=$(GOOS) GOARCH=$(GOARCH) go build -o $@ -ldflags ${LDFLAGS} github.com/tuna/tunasync/$<
|
||||
GOOS=$(GOOS) GOARCH=$(GOARCH) CGO_ENABLED=0 go build -o $@ -ldflags ${LDFLAGS} github.com/tuna/tunasync/$<
|
||||
|
||||
test:
|
||||
go test -v -covermode=count -coverprofile=profile.cov ./...
|
||||
go test -v -covermode=count -coverprofile=profile.gcov ./...
|
||||
|
||||
build-test-worker:
|
||||
go test -c -covermode=count ./worker
|
||||
CGO_ENABLED=0 go test -c -covermode=count github.com/tuna/tunasync/worker
|
||||
|
||||
.PHONY: all test $(BUILDBIN) build-test-worker
|
||||
clean:
|
||||
rm -rf build-$(ARCH)
|
||||
|
||||
.PHONY: all test $(BUILDBIN) build-test-worker clean
|
||||
|
@ -51,10 +51,13 @@ PreSyncing Syncing Succe
|
||||
|
||||
## Building
|
||||
|
||||
Go version: 1.13
|
||||
Go version: 1.22
|
||||
|
||||
```shell
|
||||
# for native arch
|
||||
> make all
|
||||
# for other arch
|
||||
> make ARCH=linux-arm64 all
|
||||
```
|
||||
|
||||
Binaries in the `build-linux-amd64/`.
|
||||
Binaries are in `build-$ARCH/`, e.g., `build-linux-amd64/`.
|
||||
|
@ -9,10 +9,10 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/moby/sys/reexec"
|
||||
"github.com/pkg/profile"
|
||||
"gopkg.in/op/go-logging.v1"
|
||||
"github.com/urfave/cli"
|
||||
"github.com/moby/moby/pkg/reexec"
|
||||
"gopkg.in/op/go-logging.v1"
|
||||
|
||||
tunasync "github.com/tuna/tunasync/internal"
|
||||
"github.com/tuna/tunasync/manager"
|
||||
@ -40,7 +40,7 @@ func startManager(c *cli.Context) error {
|
||||
|
||||
m := manager.GetTUNASyncManager(cfg)
|
||||
if m == nil {
|
||||
logger.Errorf("Error intializing TUNA sync worker.")
|
||||
logger.Errorf("Error intializing TUNA sync manager.")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
|
@ -3,7 +3,7 @@ package main
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"strconv"
|
||||
@ -122,7 +122,7 @@ func initialize(c *cli.Context) error {
|
||||
var err error
|
||||
client, err = tunasync.CreateHTTPClient(cfg.CACert)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("Error initializing HTTP client: %s", err.Error())
|
||||
err = fmt.Errorf("error initializing HTTP client: %s", err.Error())
|
||||
// logger.Error(err.Error())
|
||||
return err
|
||||
|
||||
@ -266,7 +266,7 @@ func listJobs(c *cli.Context) error {
|
||||
func updateMirrorSize(c *cli.Context) error {
|
||||
args := c.Args()
|
||||
if len(args) != 2 {
|
||||
return cli.NewExitError("Usage: tunasynctl -w <worker-id> <mirror> <size>", 1)
|
||||
return cli.NewExitError("Usage: tunasynctl set-size -w <worker-id> <mirror> <size>", 1)
|
||||
}
|
||||
workerID := c.String("worker")
|
||||
mirrorID := args.Get(0)
|
||||
@ -292,7 +292,7 @@ func updateMirrorSize(c *cli.Context) error {
|
||||
1)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, _ := ioutil.ReadAll(resp.Body)
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return cli.NewExitError(
|
||||
fmt.Sprintf("Manager failed to update mirror size: %s", body), 1,
|
||||
@ -338,7 +338,7 @@ func removeWorker(c *cli.Context) error {
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return cli.NewExitError(
|
||||
fmt.Sprintf("Failed to parse response: %s", err.Error()),
|
||||
@ -351,7 +351,7 @@ func removeWorker(c *cli.Context) error {
|
||||
}
|
||||
|
||||
res := map[string]string{}
|
||||
err = json.NewDecoder(resp.Body).Decode(&res)
|
||||
_ = json.NewDecoder(resp.Body).Decode(&res)
|
||||
if res["message"] == "deleted" {
|
||||
fmt.Println("Successfully removed the worker")
|
||||
} else {
|
||||
@ -376,7 +376,7 @@ func flushDisabledJobs(c *cli.Context) error {
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return cli.NewExitError(
|
||||
fmt.Sprintf("Failed to parse response: %s", err.Error()),
|
||||
@ -430,7 +430,7 @@ func cmdJob(cmd tunasync.CmdVerb) cli.ActionFunc {
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return cli.NewExitError(
|
||||
fmt.Sprintf("Failed to parse response: %s", err.Error()),
|
||||
@ -468,7 +468,7 @@ func cmdWorker(cmd tunasync.CmdVerb) cli.ActionFunc {
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return cli.NewExitError(
|
||||
fmt.Sprintf("Failed to parse response: %s", err.Error()),
|
||||
|
@ -39,7 +39,7 @@ name = "test_worker"
|
||||
log_dir = "/tmp/tunasync/log/tunasync/{{.Name}}"
|
||||
mirror_dir = "/tmp/tunasync"
|
||||
concurrent = 10
|
||||
interval = 1
|
||||
interval = 120
|
||||
|
||||
[manager]
|
||||
api_base = "http://localhost:12345"
|
||||
|
103
go.mod
103
go.mod
@ -1,38 +1,89 @@
|
||||
module github.com/tuna/tunasync
|
||||
|
||||
go 1.13
|
||||
go 1.23.0
|
||||
|
||||
toolchain go1.23.5
|
||||
|
||||
require (
|
||||
github.com/BurntSushi/toml v0.3.1
|
||||
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect
|
||||
github.com/BurntSushi/toml v1.4.0
|
||||
github.com/alicebob/miniredis v2.5.0+incompatible
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be
|
||||
github.com/boltdb/bolt v1.3.1
|
||||
github.com/cilium/ebpf v0.6.2 // indirect
|
||||
github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27
|
||||
github.com/containerd/cgroups v1.0.2-0.20210729163027-ddda8a174e9a
|
||||
github.com/dennwc/btrfs v0.0.0-20190517175702-d917b30ff035
|
||||
github.com/dgraph-io/badger/v2 v2.2007.2
|
||||
github.com/docker/go-units v0.4.0
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 // indirect
|
||||
github.com/gin-gonic/gin v1.7.0
|
||||
github.com/go-redis/redis/v8 v8.3.0
|
||||
github.com/gomodule/redigo v1.8.2 // indirect
|
||||
github.com/imdario/mergo v0.3.9
|
||||
github.com/moby/moby v20.10.7+incompatible
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417
|
||||
github.com/codeskyblue/go-sh v0.0.0-20200712050446-30169cf553fe
|
||||
github.com/containerd/cgroups/v3 v3.0.5
|
||||
github.com/dennwc/btrfs v0.0.0-20241002142654-12ae127e0bf6
|
||||
github.com/dgraph-io/badger/v2 v2.2007.4
|
||||
github.com/docker/go-units v0.5.0
|
||||
github.com/gin-gonic/gin v1.10.0
|
||||
github.com/go-redis/redis/v8 v8.11.5
|
||||
github.com/imdario/mergo v0.3.16
|
||||
github.com/moby/moby v28.0.1+incompatible
|
||||
github.com/moby/sys/reexec v0.1.0
|
||||
github.com/opencontainers/runtime-spec v1.2.1
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/pkg/profile v1.4.0
|
||||
github.com/pkg/profile v1.7.0
|
||||
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46
|
||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||
github.com/smartystreets/assertions v1.2.0 // indirect
|
||||
github.com/smartystreets/goconvey v1.6.4
|
||||
github.com/syndtr/goleveldb v1.0.0
|
||||
github.com/urfave/cli v1.22.3
|
||||
github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb // indirect
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b // indirect
|
||||
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887
|
||||
google.golang.org/protobuf v1.26.0 // indirect
|
||||
github.com/urfave/cli v1.22.16
|
||||
golang.org/x/sys v0.30.0
|
||||
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473
|
||||
gotest.tools/v3 v3.0.3 // indirect
|
||||
)
|
||||
|
||||
replace github.com/boltdb/bolt v1.3.1 => go.etcd.io/bbolt v1.3.11
|
||||
|
||||
require (
|
||||
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect
|
||||
github.com/bytedance/sonic v1.12.9 // indirect
|
||||
github.com/bytedance/sonic/loader v0.2.3 // indirect
|
||||
github.com/cespare/xxhash v1.1.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/cilium/ebpf v0.17.3 // indirect
|
||||
github.com/cloudwego/base64x v0.1.5 // indirect
|
||||
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 // indirect
|
||||
github.com/containerd/log v0.1.0 // indirect
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6 // indirect
|
||||
github.com/dennwc/ioctl v1.0.0 // indirect
|
||||
github.com/dgraph-io/ristretto v0.2.0 // indirect
|
||||
github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/felixge/fgprof v0.9.5 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||
github.com/gin-contrib/sse v1.0.0 // indirect
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/go-playground/validator/v10 v10.25.0 // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/godbus/dbus/v5 v5.1.0 // indirect
|
||||
github.com/golang/protobuf v1.5.4 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/gomodule/redigo v1.8.2 // indirect
|
||||
github.com/google/pprof v0.0.0-20250208200701-d0013a598941 // indirect
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/jtolds/gls v4.20.0+incompatible // indirect
|
||||
github.com/klauspost/compress v1.18.0 // 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/moby/sys/userns v0.1.0 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 // indirect
|
||||
github.com/rogpeppe/go-internal v1.13.1 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sirupsen/logrus v1.9.3 // indirect
|
||||
github.com/smartystreets/assertions v1.2.0 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb // indirect
|
||||
golang.org/x/arch v0.14.0 // indirect
|
||||
golang.org/x/crypto v0.35.0 // indirect
|
||||
golang.org/x/net v0.35.0 // indirect
|
||||
golang.org/x/text v0.22.0 // indirect
|
||||
google.golang.org/protobuf v1.36.5 // indirect
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
|
||||
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||
)
|
||||
|
403
go.sum
403
go.sum
@ -1,178 +1,239 @@
|
||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/DataDog/zstd v1.4.1 h1:3oxKN3wbHibqx897utPC2LTQU4J+IHWWJO+glkAkpFM=
|
||||
github.com/DataDog/zstd v1.4.1/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo=
|
||||
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
|
||||
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
|
||||
github.com/OneOfOne/xxhash v1.2.2 h1:KMrpdQIwFcEqXDklaen+P1axHaj9BSKzvpUUfnHldSE=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a h1:HbKu58rmZpUGpz5+4FfNmIU+FmZg2P3Xaj2v2bfNWmk=
|
||||
github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a/go.mod h1:SGnFV6hVsYE877CKEZ6tDNTjaSXYUk6QqoIK6PrAtcc=
|
||||
github.com/alicebob/miniredis v2.5.0+incompatible h1:yBHoLpsyjupjz3NL3MhKMVkR41j82Yjf3KFv7ApYzUI=
|
||||
github.com/alicebob/miniredis v2.5.0+incompatible/go.mod h1:8HZjEj4yU0dwhYHky+DxYx+6BMjkBbe5ONFIF1MXffk=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
|
||||
github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/boltdb/bolt v1.3.1 h1:JQmyP4ZBrce+ZQu0dY660FMfatumYDLun9hBCUVIkF4=
|
||||
github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps=
|
||||
github.com/bytedance/sonic v1.12.7 h1:CQU8pxOy9HToxhndH0Kx/S1qU/CuS9GnKYrGioDcU1Q=
|
||||
github.com/bytedance/sonic v1.12.7/go.mod h1:tnbal4mxOMju17EGfknm2XyYcpyCnIROYOEYuemj13I=
|
||||
github.com/bytedance/sonic v1.12.9 h1:Od1BvK55NnewtGaJsTDeAOSnLVO2BTSLOe0+ooKokmQ=
|
||||
github.com/bytedance/sonic v1.12.9/go.mod h1:uVvFidNmlt9+wa31S1urfwwthTWteBgG0hWuoKAXTx8=
|
||||
github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4yY2JpfqGeCtNLU=
|
||||
github.com/bytedance/sonic/loader v0.2.2 h1:jxAJuN9fOot/cyz5Q6dUuMJF5OqQ6+5GfA8FjjQ0R4o=
|
||||
github.com/bytedance/sonic/loader v0.2.2/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
|
||||
github.com/bytedance/sonic/loader v0.2.3 h1:yctD0Q3v2NOGfSWPLPvG2ggA2kV6TS6s4wioyEqssH0=
|
||||
github.com/bytedance/sonic/loader v0.2.3/go.mod h1:N8A3vUdtUebEY2/VQC0MyhYeKUFosQU6FxH2JmUe6VI=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
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/chromedp/cdproto v0.0.0-20230802225258-3cf4e6d46a89/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
|
||||
github.com/chromedp/chromedp v0.9.2/go.mod h1:LkSXJKONWTCHAfQasKFUZI+mxqS4tZqhmtGzzhLsnLs=
|
||||
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
|
||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||
github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ=
|
||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||
github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk=
|
||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||
github.com/cilium/ebpf v0.4.0/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
|
||||
github.com/cilium/ebpf v0.6.2 h1:iHsfF/t4aW4heW2YKfeHrVPGdtYTL4C4KocpM8KTSnI=
|
||||
github.com/cilium/ebpf v0.6.2/go.mod h1:4tRaxcgiL706VnOzHOdBlY8IEAIdxINsQBcU4xJJXRs=
|
||||
github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8=
|
||||
github.com/cilium/ebpf v0.17.1 h1:G8mzU81R2JA1nE5/8SRubzqvBMmAmri2VL8BIZPWvV0=
|
||||
github.com/cilium/ebpf v0.17.1/go.mod h1:vay2FaYSmIlv3r8dNACd4mW/OCaZLJKJOo+IHBvCIO8=
|
||||
github.com/cilium/ebpf v0.17.3 h1:FnP4r16PWYSE4ux6zN+//jMcW4nMVRvuTLVTvCjyyjg=
|
||||
github.com/cilium/ebpf v0.17.3/go.mod h1:G5EDHij8yiLzaqn0WjyfJHvRa+3aDlReIaLVRMvOyJk=
|
||||
github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y=
|
||||
github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w=
|
||||
github.com/cloudwego/base64x v0.1.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/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0 h1:sDMmm+q/3+BukdIpxwO365v/Rbspp2Nt5XntgQRXq8Q=
|
||||
github.com/codegangsta/inject v0.0.0-20150114235600-33e0aa1cb7c0/go.mod h1:4Zcjuz89kmFXt9morQgcfYZAYZ5n8WHjt81YYWIwtTM=
|
||||
github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27 h1:HHUr4P/aKh4quafGxDT9LDasjGdlGkzLbfmmrlng3kA=
|
||||
github.com/codeskyblue/go-sh v0.0.0-20190412065543-76bd3d59ff27/go.mod h1:VQx0hjo2oUeQkQUET7wRwradO6f+fN5jzXgB/zROxxE=
|
||||
github.com/containerd/cgroups v1.0.2-0.20210729163027-ddda8a174e9a h1:Se756mbFRj+3RITm/9NYHknEo1TJEpCV8jHI2e8QOEo=
|
||||
github.com/containerd/cgroups v1.0.2-0.20210729163027-ddda8a174e9a/go.mod h1:M9MzGh4G4yzSq0e3Bf6tQCoDsvGewJdfhIix9CRaOWo=
|
||||
github.com/codeskyblue/go-sh v0.0.0-20200712050446-30169cf553fe h1:69JI97HlzP+PH5Mi1thcGlDoBr6PS2Oe+l3mNmAkbs4=
|
||||
github.com/codeskyblue/go-sh v0.0.0-20200712050446-30169cf553fe/go.mod h1:VQx0hjo2oUeQkQUET7wRwradO6f+fN5jzXgB/zROxxE=
|
||||
github.com/containerd/cgroups/v3 v3.0.5 h1:44na7Ud+VwyE7LIoJ8JTNQOa549a8543BmzaJHo6Bzo=
|
||||
github.com/containerd/cgroups/v3 v3.0.5/go.mod h1:SA5DLYnXO8pTGYiAHXz94qvLQTKfVM5GEVisn4jpins=
|
||||
github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I=
|
||||
github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo=
|
||||
github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk=
|
||||
github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
|
||||
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF22jk=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6 h1:XJtiaUW6dEEqVuZiMTn1ldk455QWwEIsMIJlo5vtkx0=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dennwc/btrfs v0.0.0-20190517175702-d917b30ff035 h1:4e+UEZaKPx0ZEiCMPUHMV51RGwbb1VJGCYqRFn/qmWM=
|
||||
github.com/dennwc/btrfs v0.0.0-20190517175702-d917b30ff035/go.mod h1:MYsOV9Dgsec3FFSOjywi0QK5r6TeBbdWxdrMGtiYXHA=
|
||||
github.com/dennwc/btrfs v0.0.0-20241002142654-12ae127e0bf6 h1:fV+JlCY0cCJh3l0jfE7iB3ZmrdfJSgfcjdrCQhPokGg=
|
||||
github.com/dennwc/btrfs v0.0.0-20241002142654-12ae127e0bf6/go.mod h1:MYsOV9Dgsec3FFSOjywi0QK5r6TeBbdWxdrMGtiYXHA=
|
||||
github.com/dennwc/ioctl v1.0.0 h1:DsWAAjIxRqNcLn9x6mwfuf2pet3iB7aK90K4tF16rLg=
|
||||
github.com/dennwc/ioctl v1.0.0/go.mod h1:ellh2YB5ldny99SBU/VX7Nq0xiZbHphf1DrtHxxjMk0=
|
||||
github.com/dgraph-io/badger/v2 v2.2007.2 h1:EjjK0KqwaFMlPin1ajhP943VPENHJdEz1KLIegjaI3k=
|
||||
github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE=
|
||||
github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de h1:t0UHb5vdojIDUqktM6+xJAfScFBsVpXZmqC9dsgJmeA=
|
||||
github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o=
|
||||
github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk=
|
||||
github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
|
||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2 h1:tdlZCpZ/P9DhczCTSixgIKmwPv6+wP5DGjqLYw5SUiA=
|
||||
github.com/dgraph-io/ristretto v0.2.0 h1:XAfl+7cmoUDWW/2Lx8TGZQjjxIQ2Ley9DSf52dru4WE=
|
||||
github.com/dgraph-io/ristretto v0.2.0/go.mod h1:8uBHCU/PBV4Ag0CJrP47b9Ofby5dqWNh4FicAdoqFNU=
|
||||
github.com/dgryski/go-farm v0.0.0-20190423205320-6a90982ecee2/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da h1:aIftn67I1fkbMa512G+w+Pxci9hJPB8oMnkcP3iZF38=
|
||||
github.com/dgryski/go-farm v0.0.0-20240924180020-3414d57e47da/go.mod h1:SqUrOPUnsFjfmXRMNPybcSiG0BgUW2AuFH8PAnS2iTw=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
|
||||
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
|
||||
github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4=
|
||||
github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
|
||||
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ=
|
||||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
|
||||
github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY=
|
||||
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
|
||||
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
|
||||
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
|
||||
github.com/felixge/fgprof v0.9.3/go.mod h1:RdbpDgzqYVh/T9fPELJyV7EYJuHB55UTEULNun8eiPw=
|
||||
github.com/felixge/fgprof v0.9.5 h1:8+vR6yu2vvSKn08urWyEuxx75NWPEvybbkBirEpsbVY=
|
||||
github.com/felixge/fgprof v0.9.5/go.mod h1:yKl+ERSa++RYOs32d8K6WEXCB4uXdLls4ZaZPpayhMM=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||
github.com/gin-gonic/gin v1.7.0 h1:jGB9xAJQ12AIGNB4HguylppmDK1Am9ppF7XnGXXJuoU=
|
||||
github.com/gin-gonic/gin v1.7.0/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
|
||||
github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
|
||||
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q=
|
||||
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
|
||||
github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no=
|
||||
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
|
||||
github.com/go-playground/validator/v10 v10.4.1 h1:pH2c5ADXtd66mxoE0Zm9SUhxE20r7aM3F26W0hOn+GE=
|
||||
github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
|
||||
github.com/go-redis/redis/v8 v8.3.0 h1:Xrwvn8+QqUYD1MbQmda3cVR2U9li5XbtRFkKZN5Y0hk=
|
||||
github.com/go-redis/redis/v8 v8.3.0/go.mod h1:a2xkpBM7NJUN5V5kiF46X5Ltx4WeXJ9757X/ScKUBdE=
|
||||
github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA=
|
||||
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.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E=
|
||||
github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0=
|
||||
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-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
|
||||
github.com/go-playground/assert/v2 v2.2.0/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
|
||||
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
|
||||
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
|
||||
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
|
||||
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
|
||||
github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o=
|
||||
github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
|
||||
github.com/go-playground/validator/v10 v10.25.0 h1:5Dh7cjvzR7BRZadnsVOzPhWsrwUr0nmsZJxEAnFLNO8=
|
||||
github.com/go-playground/validator/v10 v10.25.0/go.mod h1:GGzBIJMuE98Ic/kJsBXbz1x/7cByt++cQ+YOuDM5wus=
|
||||
github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI=
|
||||
github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow=
|
||||
github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI=
|
||||
github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo=
|
||||
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
|
||||
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
|
||||
github.com/gobwas/ws v1.2.1/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
|
||||
github.com/goccy/go-json v0.10.4 h1:JSwxQzIqKfmFX1swYPpUThQZp/Ka4wzJdK0LWVytLPM=
|
||||
github.com/goccy/go-json v0.10.4/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M=
|
||||
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/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/godbus/dbus/v5 v5.1.0 h1:4KLkAxT3aOY8Li4FRJe/KvhoNFFxo0m6fNuFUO8QJUk=
|
||||
github.com/godbus/dbus/v5 v5.1.0/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM=
|
||||
github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/gomodule/redigo v1.8.2 h1:H5XSIre1MB5NbPYFp+i1NBbb5qN1W8Y8YAQoAYbkm8k=
|
||||
github.com/gomodule/redigo v1.8.2/go.mod h1:P9dn9mFrCBvWhGE1wpxx6fgq7BAeLBk+UUUzlpkBYO0=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/pprof v0.0.0-20211214055906-6f57359322fd/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg=
|
||||
github.com/google/pprof v0.0.0-20240227163752-401108e1b7e7/go.mod h1:czg5+yv1E0ZGTi6S6vVK1mke0fV+FaUhNGcd6VRS9Ik=
|
||||
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-20250208200701-d0013a598941 h1:43XjGa6toxLpeksjcxs1jIoIyr+vUfOqY2c6HB4bpoc=
|
||||
github.com/google/pprof v0.0.0-20250208200701-d0013a598941/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 h1:EGx4pi6eqNxGaHF6qqu48+N2wcFQ5qg5FXgOdqsJ5d8=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||
github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg=
|
||||
github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w=
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20230524184225-eabc099b10ab/go.mod h1:gx7rwoVhcfuVKG5uya9Hs3Sxj7EIvldVofAWIUtGouw=
|
||||
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
|
||||
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns=
|
||||
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/josharian/native v1.1.0 h1:uuaP0hAbW7Y4l0ZRQ6C9zfb7Mg1mbFKry/xzDAfmtLA=
|
||||
github.com/josharian/native v1.1.0/go.mod h1:7X/raswPFr05uY3HiLlYeyQntB6OO7E/d2Cu7qoaN2w=
|
||||
github.com/jsimonetti/rtnetlink/v2 v2.0.1 h1:xda7qaHDSVOsADNouv7ukSuicKZO7GgVUCXxpaIEIlM=
|
||||
github.com/jsimonetti/rtnetlink/v2 v2.0.1/go.mod h1:7MoNYNbb3UaDHtF8udiJo/RH6VsTKP1pqKLUTVCvToE=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo=
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
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.12.3/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
|
||||
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.9 h1:66ze0taIn2H33fBvCkXuv9BmCwDfafmiIVpKV9kKGuY=
|
||||
github.com/klauspost/cpuid/v2 v2.2.9/go.mod h1:rqkxqrZ1EhYM9G+hXH7YdowN5R5RGN6NK4QwQ3WMXF8=
|
||||
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.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
|
||||
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y=
|
||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
|
||||
github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ=
|
||||
github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
|
||||
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
|
||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mdlayher/netlink v1.7.2 h1:/UtM3ofJap7Vl4QWCPDGXY8d3GIY2UGSDbK+QWmY8/g=
|
||||
github.com/mdlayher/netlink v1.7.2/go.mod h1:xraEF7uJbxLhc5fpHL4cPe221LI2bdttWlU+ZGLfQSw=
|
||||
github.com/mdlayher/socket v0.4.1 h1:eM9y2/jlbs1M615oshPQOHZzj6R6wMT7bX5NPiQvn2U=
|
||||
github.com/mdlayher/socket v0.4.1/go.mod h1:cAqeGjoufqdxWkD7DkpyS+wcefOtmu5OQ8KuoJGIReA=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||
github.com/moby/moby v20.10.7+incompatible h1:mMDsIjUeon2FpxCJz0Xj32wzRcTbGLVzG1uEbPalok4=
|
||||
github.com/moby/moby v20.10.7+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||
github.com/moby/moby v27.4.1+incompatible h1:z6detzbcLRt7U+w4ovHV+8oYpJfpHKTmUbFWPG6cudA=
|
||||
github.com/moby/moby v27.4.1+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc=
|
||||
github.com/moby/moby v28.0.1+incompatible h1:10ejBTwFhM3/9p6pSaKrLyXnx7QzzCmCYHAedOp67cQ=
|
||||
github.com/moby/moby v28.0.1+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc=
|
||||
github.com/moby/sys/reexec v0.1.0 h1:RrBi8e0EBTLEgfruBOFcxtElzRGTEUkeIFaVXgU7wok=
|
||||
github.com/moby/sys/reexec v0.1.0/go.mod h1:EqjBg8F3X7iZe5pU6nRZnYCMUTXoxsjiIfHup5wYIN8=
|
||||
github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g=
|
||||
github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28=
|
||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg=
|
||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||
github.com/nxadm/tail v1.4.4 h1:DQuhQpB1tVlglWS2hLQ5OV6B5r8aGxSrPc5Qo6uTN78=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
|
||||
github.com/onsi/ginkgo v1.14.1 h1:jMU0WaQrP0a/YAEq8eJmJKjBoMs+pClEr1vDMlM/Do4=
|
||||
github.com/onsi/ginkgo v1.14.1/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
|
||||
github.com/onsi/ginkgo v1.16.5 h1:8xi0RTUf59SOSfEtZMvwTvXYMzG4gV23XVHOZiXNtnE=
|
||||
github.com/onsi/ginkgo v1.16.5/go.mod h1:+E8gABHa3K6zRBolWtd+ROzc/U5bkGt0FwiG042wbpU=
|
||||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
||||
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
|
||||
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/onsi/gomega v1.10.2 h1:aY/nuoWlKJud2J6U0E3NWsjlg+0GtwXxgEqthRdzlcs=
|
||||
github.com/onsi/gomega v1.10.2/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
|
||||
github.com/opencontainers/runtime-spec v1.0.2/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417 h1:3snG66yBm59tKhhSPQrQ/0bCrv1LQbKt40LnUPiUxdc=
|
||||
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/onsi/gomega v1.18.1 h1:M1GfJqGRrBrrGGsbxzV5dqM2U2ApXefZCQpkukxYRLE=
|
||||
github.com/onsi/gomega v1.18.1/go.mod h1:0q+aL8jAiMXy9hbwj2mr5GziHiwhAIQpFmmtT5hitRs=
|
||||
github.com/opencontainers/runtime-spec v1.2.0 h1:z97+pHb3uELt/yiAWD691HNHQIF07bE7dzrbT927iTk=
|
||||
github.com/opencontainers/runtime-spec v1.2.0/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/opencontainers/runtime-spec v1.2.1 h1:S4k4ryNgEpxW1dzyqffOmhI1BHYcjzU8lpJfSlR0xww=
|
||||
github.com/opencontainers/runtime-spec v1.2.1/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
|
||||
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3 h1:YmeHyLY8mFWbdkNWwpr+qIL2bEqT0o95WSdkNHvL12M=
|
||||
github.com/pelletier/go-toml/v2 v2.2.3/go.mod h1:MfCQTFTvCcUyyvvwm1+G6H/jORL20Xlb6rzQu9GuUkc=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/profile v1.4.0 h1:uCmaf4vVbWAOZz36k1hrQD7ijGRzLwaME8Am/7a4jZI=
|
||||
github.com/pkg/profile v1.4.0/go.mod h1:NWz/XGvpEW1FyYQ7fCx4dqYBLlfTcE+A9FLAkNKqjFE=
|
||||
github.com/pkg/profile v1.7.0 h1:hnbDkaNWPCLMO9wGLdBFTIZvzDrDfBM2072E1S9gJkA=
|
||||
github.com/pkg/profile v1.7.0/go.mod h1:8Uer0jas47ZQMJ7VD+OHknK4YDY07LPUC6dEvqDjvNo=
|
||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo=
|
||||
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
|
||||
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
github.com/russross/blackfriday/v2 v2.0.1 h1:lPqVAte+HuHNfhJ/0LC98ESWRz8afy9tM/0RK8m9o+Q=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46 h1:GHRpF1pTW19a8tTFrMLUcfWwyC0pnifVo2ClaLq+hP8=
|
||||
github.com/ryszard/goskiplist v0.0.0-20150312221310-2dfbae5fcf46/go.mod h1:uAQ5PCi+MFsC7HjREoAz1BU+Mq60+05gifQSsHSDG/8=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0 h1:PdmoCO6wvbs+7yrJyMORt4/BmY5IYyJwS/kOiWx8mHo=
|
||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ=
|
||||
github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/assertions v1.2.0 h1:42S6lae5dvLc7BrLu/0ugRtcFVjoJNMC/N3yZFZkDFs=
|
||||
github.com/smartystreets/assertions v1.2.0/go.mod h1:tcbTF8ujkAEcZ8TElKY+i30BzYlVhC/LOxJk7iOWnoo=
|
||||
@ -188,95 +249,85 @@ github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb6
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s=
|
||||
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.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/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/syndtr/goleveldb v1.0.0 h1:fBdIW9lB4Iz0n9khmH8w27SJ3QEJ7+IgjPEwGSZiFdE=
|
||||
github.com/syndtr/goleveldb v1.0.0/go.mod h1:ZVVdQEZoIme9iO1Ch2Jdy24qqXrMMOU6lpPAyBWyWuQ=
|
||||
github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo=
|
||||
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs=
|
||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/cli v1.22.3 h1:FpNT6zq26xNpHZy08emi755QwzLPs6Pukqjlc7RfOMU=
|
||||
github.com/urfave/cli v1.22.3/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
|
||||
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
|
||||
github.com/urfave/cli v1.22.16 h1:MH0k6uJxdwdeWQTwhSO42Pwr4YLrNLwBtg1MRgTqPdQ=
|
||||
github.com/urfave/cli v1.22.16/go.mod h1:EeJR6BKodywf4zciqrdw6hpCPk68JO9z5LazXZMn5Po=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb h1:ZkM6LRnq40pR1Ox0hTHlnpkcOTuFIDQpZ1IN8rKKhX0=
|
||||
github.com/yuin/gopher-lua v0.0.0-20191220021717-ab39c6098bdb/go.mod h1:gqRgreBUhTSL0GeU64rtZ3Uq3wtjOa/TB2YfrtkCbVQ=
|
||||
go.opentelemetry.io/otel v0.13.0 h1:2isEnyzjjJZq6r2EKMsFj4TxiQiexsM04AVhwbR/oBA=
|
||||
go.opentelemetry.io/otel v0.13.0/go.mod h1:dlSNewoRYikTkotEnxdmuBHgzT+k/idJSfDv/FxEnOY=
|
||||
go.etcd.io/bbolt v1.3.11 h1:yGEzV1wPz2yVCLsD8ZAiGHhHVlczyC9d1rP43/VCRJ0=
|
||||
go.etcd.io/bbolt v1.3.11/go.mod h1:dksAq7YMXoljX0xu6VF5DMZGbhYYoLUalEiSySYAS4I=
|
||||
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
|
||||
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||
golang.org/x/arch v0.13.0 h1:KCkqVVV1kGg0X87TFysjCJ8MxtZEIU4Ja/yXGeoECdA=
|
||||
golang.org/x/arch v0.13.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/arch v0.14.0 h1:z9JUEZWr8x4rR0OU6c4/4t6E6jOZ8/QBS2bBYBm4tx4=
|
||||
golang.org/x/arch v0.14.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
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 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
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/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
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/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
||||
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b h1:iFwSg7t5GZmB/Q5TjiEAsdoLDrdJRC1RiF2WhuV29Qw=
|
||||
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0=
|
||||
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
|
||||
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
|
||||
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w=
|
||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190204203706-41f3e6584952/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
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-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20191120155948-bd437916bb0e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200519105757-fe76b779f299/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887 h1:dXfMednGJh/SUUFjTLsWJz3P+TQt9qnR11GgeI3vWKs=
|
||||
golang.org/x/sys v0.0.0-20210426230700-d19ff857e887/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
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/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
|
||||
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
|
||||
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
||||
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/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 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.36.2 h1:R8FeyR1/eLmkutZOM5CWghmo5itiG9z0ktFlTVLuTmU=
|
||||
google.golang.org/protobuf v1.36.2/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 h1:YR8cESwS4TdDjEe65xsg0ogRM/Nc3DYOhEAlW+xobZo=
|
||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
|
||||
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
|
||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
||||
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473 h1:6D+BvnJ/j6e222UW8s2qTSe3wGBtvo0MbVQG/c5k8RE=
|
||||
gopkg.in/op/go-logging.v1 v1.0.0-20160211212156-b2cb9fa56473/go.mod h1:N1eN2tsCx0Ydtgjl4cqmbRCsY4/+z4cYDeqwZTk6zog=
|
||||
@ -284,11 +335,9 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkep
|
||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
|
||||
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
|
||||
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||
nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50=
|
||||
|
@ -71,8 +71,7 @@ func TestStatus(t *testing.T) {
|
||||
Size: "4GB",
|
||||
}
|
||||
|
||||
var m2 WebMirrorStatus
|
||||
m2 = BuildWebMirrorStatus(m)
|
||||
var m2 WebMirrorStatus = BuildWebMirrorStatus(m)
|
||||
// fmt.Printf("%#v", m2)
|
||||
So(m2.Name, ShouldEqual, m.Name)
|
||||
So(m2.Status, ShouldEqual, m.Status)
|
||||
|
@ -7,8 +7,9 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"net/http"
|
||||
"os"
|
||||
"os/exec"
|
||||
"regexp"
|
||||
"time"
|
||||
@ -39,19 +40,19 @@ var rsyncExitValues = map[int]string{
|
||||
|
||||
// GetTLSConfig generate tls.Config from CAFile
|
||||
func GetTLSConfig(CAFile string) (*tls.Config, error) {
|
||||
caCert, err := ioutil.ReadFile(CAFile)
|
||||
caCert, err := os.ReadFile(CAFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
caCertPool := x509.NewCertPool()
|
||||
if ok := caCertPool.AppendCertsFromPEM(caCert); !ok {
|
||||
return nil, errors.New("Failed to add CA to pool")
|
||||
return nil, errors.New("failed to add CA to pool")
|
||||
}
|
||||
|
||||
tlsConfig := &tls.Config{
|
||||
RootCAs: caCertPool,
|
||||
}
|
||||
tlsConfig.BuildNameToCertificate()
|
||||
// tlsConfig.BuildNameToCertificate()
|
||||
return tlsConfig, nil
|
||||
}
|
||||
|
||||
@ -104,7 +105,7 @@ func GetJSON(url string, obj interface{}, client *http.Client) (*http.Response,
|
||||
return resp, errors.New("HTTP status code is not 200")
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
return resp, err
|
||||
}
|
||||
@ -114,10 +115,10 @@ func GetJSON(url string, obj interface{}, client *http.Client) (*http.Response,
|
||||
// FindAllSubmatchInFile calls re.FindAllSubmatch to find matches in given file
|
||||
func FindAllSubmatchInFile(fileName string, re *regexp.Regexp) (matches [][][]byte, err error) {
|
||||
if fileName == "/dev/null" {
|
||||
err = errors.New("Invalid log file")
|
||||
err = errors.New("invalid log file")
|
||||
return
|
||||
}
|
||||
if content, err := ioutil.ReadFile(fileName); err == nil {
|
||||
if content, err := os.ReadFile(fileName); err == nil {
|
||||
matches = re.FindAllSubmatch(content, -1)
|
||||
// fmt.Printf("FindAllSubmatchInFile: %q\n", matches)
|
||||
}
|
||||
@ -127,7 +128,7 @@ func FindAllSubmatchInFile(fileName string, re *regexp.Regexp) (matches [][][]by
|
||||
// ExtractSizeFromLog uses a regexp to extract the size from log files
|
||||
func ExtractSizeFromLog(logFile string, re *regexp.Regexp) string {
|
||||
matches, _ := FindAllSubmatchInFile(logFile, re)
|
||||
if matches == nil || len(matches) == 0 {
|
||||
if len(matches) == 0 {
|
||||
return ""
|
||||
}
|
||||
// return the first capture group of the last occurrence
|
||||
|
@ -1,7 +1,6 @@
|
||||
package internal
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
@ -29,11 +28,11 @@ sent 7.55M bytes received 823.25M bytes 5.11M bytes/sec
|
||||
total size is 1.33T speedup is 1,604.11
|
||||
`
|
||||
Convey("Log parser should work", t, func() {
|
||||
tmpDir, err := ioutil.TempDir("", "tunasync")
|
||||
tmpDir, err := os.MkdirTemp("", "tunasync")
|
||||
So(err, ShouldBeNil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
logFile := filepath.Join(tmpDir, "rs.log")
|
||||
err = ioutil.WriteFile(logFile, []byte(realLogContent), 0755)
|
||||
err = os.WriteFile(logFile, []byte(realLogContent), 0755)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
res := ExtractSizeFromRsyncLog(logFile)
|
||||
|
@ -1,4 +1,4 @@
|
||||
package internal
|
||||
|
||||
// Version of the program
|
||||
const Version string = "0.8.0"
|
||||
const Version string = "0.9.3"
|
||||
|
@ -2,7 +2,6 @@ package manager
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
@ -37,11 +36,11 @@ func TestConfig(t *testing.T) {
|
||||
|
||||
Convey("load Config should work", t, func() {
|
||||
Convey("create config file & cli context", func() {
|
||||
tmpfile, err := ioutil.TempFile("", "tunasync")
|
||||
tmpfile, err := os.CreateTemp("", "tunasync")
|
||||
So(err, ShouldEqual, nil)
|
||||
defer os.Remove(tmpfile.Name())
|
||||
|
||||
err = ioutil.WriteFile(tmpfile.Name(), []byte(cfgBlob), 0644)
|
||||
err = os.WriteFile(tmpfile.Name(), []byte(cfgBlob), 0644)
|
||||
So(err, ShouldEqual, nil)
|
||||
defer tmpfile.Close()
|
||||
|
||||
|
@ -6,7 +6,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
bolt "github.com/boltdb/bolt"
|
||||
"github.com/dgraph-io/badger/v2"
|
||||
"github.com/go-redis/redis/v8"
|
||||
"github.com/pkg/errors"
|
||||
@ -141,7 +141,7 @@ func (b *kvDBAdapter) ListWorkers() (ws []WorkerStatus, err error) {
|
||||
|
||||
func (b *kvDBAdapter) GetWorker(workerID string) (w WorkerStatus, err error) {
|
||||
var v []byte
|
||||
v, err = b.db.Get(_workerBucketKey, workerID)
|
||||
v, _ = b.db.Get(_workerBucketKey, workerID)
|
||||
if v == nil {
|
||||
err = fmt.Errorf("invalid workerID %s", workerID)
|
||||
} else {
|
||||
|
@ -3,7 +3,7 @@ package manager
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/boltdb/bolt"
|
||||
bolt "github.com/boltdb/bolt"
|
||||
)
|
||||
|
||||
// implement kv interface backed by boltdb
|
||||
|
@ -3,7 +3,6 @@ package manager
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
@ -32,7 +31,7 @@ func DBAdapterTest(db dbAdapter) {
|
||||
LastOnline: time.Now(),
|
||||
LastRegister: time.Now(),
|
||||
}
|
||||
w, err = db.CreateWorker(w)
|
||||
_, err = db.CreateWorker(w)
|
||||
So(err, ShouldBeNil)
|
||||
}
|
||||
|
||||
@ -73,7 +72,7 @@ func DBAdapterTest(db dbAdapter) {
|
||||
|
||||
Convey("update mirror status", func() {
|
||||
status := []MirrorStatus{
|
||||
MirrorStatus{
|
||||
{
|
||||
Name: "arch-sync1",
|
||||
Worker: testWorkerIDs[0],
|
||||
IsMaster: true,
|
||||
@ -84,7 +83,7 @@ func DBAdapterTest(db dbAdapter) {
|
||||
Upstream: "mirrors.tuna.tsinghua.edu.cn",
|
||||
Size: "3GB",
|
||||
},
|
||||
MirrorStatus{
|
||||
{
|
||||
Name: "arch-sync2",
|
||||
Worker: testWorkerIDs[1],
|
||||
IsMaster: true,
|
||||
@ -95,7 +94,7 @@ func DBAdapterTest(db dbAdapter) {
|
||||
Upstream: "mirrors.tuna.tsinghua.edu.cn",
|
||||
Size: "4GB",
|
||||
},
|
||||
MirrorStatus{
|
||||
{
|
||||
Name: "arch-sync3",
|
||||
Worker: testWorkerIDs[1],
|
||||
IsMaster: true,
|
||||
@ -159,12 +158,11 @@ func DBAdapterTest(db dbAdapter) {
|
||||
})
|
||||
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
func TestDBAdapter(t *testing.T) {
|
||||
Convey("boltAdapter should work", t, func() {
|
||||
tmpDir, err := ioutil.TempDir("", "tunasync")
|
||||
tmpDir, err := os.MkdirTemp("", "tunasync")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
@ -200,7 +198,7 @@ func TestDBAdapter(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("badgerAdapter should work", t, func() {
|
||||
tmpDir, err := ioutil.TempDir("", "tunasync")
|
||||
tmpDir, err := os.MkdirTemp("", "tunasync")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
@ -218,7 +216,7 @@ func TestDBAdapter(t *testing.T) {
|
||||
})
|
||||
|
||||
Convey("leveldbAdapter should work", t, func() {
|
||||
tmpDir, err := ioutil.TempDir("", "tunasync")
|
||||
tmpDir, err := os.MkdirTemp("", "tunasync")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
|
@ -267,7 +267,7 @@ func (s *Manager) updateSchedulesOfWorker(c *gin.Context) {
|
||||
if len(mirrorName) == 0 {
|
||||
s.returnErrJSON(
|
||||
c, http.StatusBadRequest,
|
||||
errors.New("Mirror Name should not be empty"),
|
||||
errors.New("mirror Name should not be empty"),
|
||||
)
|
||||
}
|
||||
|
||||
@ -312,7 +312,7 @@ func (s *Manager) updateJobOfWorker(c *gin.Context) {
|
||||
if len(mirrorName) == 0 {
|
||||
s.returnErrJSON(
|
||||
c, http.StatusBadRequest,
|
||||
errors.New("Mirror Name should not be empty"),
|
||||
errors.New("mirror Name should not be empty"),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -3,10 +3,11 @@ package manager
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"math/rand"
|
||||
"net/http"
|
||||
"strings"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
@ -35,7 +36,7 @@ func TestHTTPServer(t *testing.T) {
|
||||
So(s, ShouldNotBeNil)
|
||||
s.setDBAdapter(&mockDBAdapter{
|
||||
workerStore: map[string]WorkerStatus{
|
||||
_magicBadWorkerID: WorkerStatus{
|
||||
_magicBadWorkerID: {
|
||||
ID: _magicBadWorkerID,
|
||||
}},
|
||||
statusStore: make(map[string]MirrorStatus),
|
||||
@ -47,7 +48,7 @@ func TestHTTPServer(t *testing.T) {
|
||||
So(resp.StatusCode, ShouldEqual, http.StatusOK)
|
||||
So(resp.Header.Get("Content-Type"), ShouldEqual, "application/json; charset=utf-8")
|
||||
defer resp.Body.Close()
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
body, err := io.ReadAll(resp.Body)
|
||||
So(err, ShouldBeNil)
|
||||
var p map[string]string
|
||||
err = json.Unmarshal(body, &p)
|
||||
@ -179,9 +180,9 @@ func TestHTTPServer(t *testing.T) {
|
||||
So(m.Upstream, ShouldEqual, status.Upstream)
|
||||
So(m.Size, ShouldEqual, status.Size)
|
||||
So(m.IsMaster, ShouldEqual, status.IsMaster)
|
||||
So(time.Now().Sub(m.LastUpdate), ShouldBeLessThan, 1*time.Second)
|
||||
So(time.Since(m.LastUpdate), ShouldBeLessThan, 1*time.Second)
|
||||
So(m.LastStarted.IsZero(), ShouldBeTrue) // hasn't been initialized yet
|
||||
So(time.Now().Sub(m.LastEnded), ShouldBeLessThan, 1*time.Second)
|
||||
So(time.Since(m.LastEnded), ShouldBeLessThan, 1*time.Second)
|
||||
|
||||
})
|
||||
|
||||
@ -207,11 +208,11 @@ func TestHTTPServer(t *testing.T) {
|
||||
So(m.Upstream, ShouldEqual, status.Upstream)
|
||||
So(m.Size, ShouldEqual, status.Size)
|
||||
So(m.IsMaster, ShouldEqual, status.IsMaster)
|
||||
So(time.Now().Sub(m.LastUpdate), ShouldBeLessThan, 3*time.Second)
|
||||
So(time.Now().Sub(m.LastUpdate), ShouldBeGreaterThan, 1*time.Second)
|
||||
So(time.Now().Sub(m.LastStarted), ShouldBeLessThan, 2*time.Second)
|
||||
So(time.Now().Sub(m.LastEnded), ShouldBeLessThan, 3*time.Second)
|
||||
So(time.Now().Sub(m.LastEnded), ShouldBeGreaterThan, 1*time.Second)
|
||||
So(time.Since(m.LastUpdate), ShouldBeLessThan, 3*time.Second)
|
||||
So(time.Since(m.LastUpdate), ShouldBeGreaterThan, 1*time.Second)
|
||||
So(time.Since(m.LastStarted), ShouldBeLessThan, 2*time.Second)
|
||||
So(time.Since(m.LastEnded), ShouldBeLessThan, 3*time.Second)
|
||||
So(time.Since(m.LastEnded), ShouldBeGreaterThan, 1*time.Second)
|
||||
|
||||
})
|
||||
|
||||
@ -227,9 +228,9 @@ func TestHTTPServer(t *testing.T) {
|
||||
So(m.Upstream, ShouldEqual, status.Upstream)
|
||||
So(m.Size, ShouldEqual, status.Size)
|
||||
So(m.IsMaster, ShouldEqual, status.IsMaster)
|
||||
So(time.Now().Sub(m.LastUpdate.Time), ShouldBeLessThan, 3*time.Second)
|
||||
So(time.Now().Sub(m.LastStarted.Time), ShouldBeLessThan, 2*time.Second)
|
||||
So(time.Now().Sub(m.LastEnded.Time), ShouldBeLessThan, 3*time.Second)
|
||||
So(time.Since(m.LastUpdate.Time), ShouldBeLessThan, 3*time.Second)
|
||||
So(time.Since(m.LastStarted.Time), ShouldBeLessThan, 2*time.Second)
|
||||
So(time.Since(m.LastEnded.Time), ShouldBeLessThan, 3*time.Second)
|
||||
|
||||
})
|
||||
|
||||
@ -258,17 +259,17 @@ func TestHTTPServer(t *testing.T) {
|
||||
So(m.Upstream, ShouldEqual, status.Upstream)
|
||||
So(m.Size, ShouldEqual, "5GB")
|
||||
So(m.IsMaster, ShouldEqual, status.IsMaster)
|
||||
So(time.Now().Sub(m.LastUpdate), ShouldBeLessThan, 3*time.Second)
|
||||
So(time.Now().Sub(m.LastStarted), ShouldBeLessThan, 2*time.Second)
|
||||
So(time.Now().Sub(m.LastEnded), ShouldBeLessThan, 3*time.Second)
|
||||
So(time.Since(m.LastUpdate), ShouldBeLessThan, 3*time.Second)
|
||||
So(time.Since(m.LastStarted), ShouldBeLessThan, 2*time.Second)
|
||||
So(time.Since(m.LastEnded), ShouldBeLessThan, 3*time.Second)
|
||||
})
|
||||
})
|
||||
|
||||
Convey("Update schedule of valid mirrors", func(ctx C) {
|
||||
msg := MirrorSchedules{
|
||||
[]MirrorSchedule{
|
||||
MirrorSchedule{"arch-sync1", time.Now().Add(time.Minute * 10)},
|
||||
MirrorSchedule{"arch-sync2", time.Now().Add(time.Minute * 7)},
|
||||
Schedules: []MirrorSchedule{
|
||||
{MirrorName: "arch-sync1", NextSchedule: time.Now().Add(time.Minute * 10)},
|
||||
{MirrorName: "arch-sync2", NextSchedule: time.Now().Add(time.Minute * 7)},
|
||||
},
|
||||
}
|
||||
|
||||
@ -312,9 +313,9 @@ func TestHTTPServer(t *testing.T) {
|
||||
So(m.Upstream, ShouldEqual, status.Upstream)
|
||||
So(m.Size, ShouldEqual, status.Size)
|
||||
So(m.IsMaster, ShouldEqual, status.IsMaster)
|
||||
So(time.Now().Sub(m.LastUpdate), ShouldBeGreaterThan, 3*time.Second)
|
||||
So(time.Now().Sub(m.LastStarted), ShouldBeGreaterThan, 3*time.Second)
|
||||
So(time.Now().Sub(m.LastEnded), ShouldBeLessThan, 1*time.Second)
|
||||
So(time.Since(m.LastUpdate), ShouldBeGreaterThan, 3*time.Second)
|
||||
So(time.Since(m.LastStarted), ShouldBeGreaterThan, 3*time.Second)
|
||||
So(time.Since(m.LastEnded), ShouldBeLessThan, 1*time.Second)
|
||||
})
|
||||
})
|
||||
|
||||
@ -344,9 +345,9 @@ func TestHTTPServer(t *testing.T) {
|
||||
Convey("update schedule of an non-existent worker", func(ctx C) {
|
||||
invalidWorker := "test_worker2"
|
||||
sch := MirrorSchedules{
|
||||
[]MirrorSchedule{
|
||||
MirrorSchedule{"arch-sync1", time.Now().Add(time.Minute * 10)},
|
||||
MirrorSchedule{"arch-sync2", time.Now().Add(time.Minute * 7)},
|
||||
Schedules: []MirrorSchedule{
|
||||
{MirrorName: "arch-sync1", NextSchedule: time.Now().Add(time.Minute * 10)},
|
||||
{MirrorName: "arch-sync2", NextSchedule: time.Now().Add(time.Minute * 7)},
|
||||
},
|
||||
}
|
||||
resp, err := PostJSON(fmt.Sprintf("%s/workers/%s/schedules",
|
||||
@ -424,6 +425,8 @@ func TestHTTPServer(t *testing.T) {
|
||||
type mockDBAdapter struct {
|
||||
workerStore map[string]WorkerStatus
|
||||
statusStore map[string]MirrorStatus
|
||||
workerLock sync.RWMutex
|
||||
statusLock sync.RWMutex
|
||||
}
|
||||
|
||||
func (b *mockDBAdapter) Init() error {
|
||||
@ -431,17 +434,22 @@ func (b *mockDBAdapter) Init() error {
|
||||
}
|
||||
|
||||
func (b *mockDBAdapter) ListWorkers() ([]WorkerStatus, error) {
|
||||
b.workerLock.RLock()
|
||||
workers := make([]WorkerStatus, len(b.workerStore))
|
||||
idx := 0
|
||||
for _, w := range b.workerStore {
|
||||
workers[idx] = w
|
||||
idx++
|
||||
}
|
||||
b.workerLock.RUnlock()
|
||||
return workers, nil
|
||||
}
|
||||
|
||||
func (b *mockDBAdapter) GetWorker(workerID string) (WorkerStatus, error) {
|
||||
b.workerLock.RLock()
|
||||
defer b.workerLock.RUnlock()
|
||||
w, ok := b.workerStore[workerID]
|
||||
|
||||
if !ok {
|
||||
return WorkerStatus{}, fmt.Errorf("invalid workerId")
|
||||
}
|
||||
@ -449,7 +457,9 @@ func (b *mockDBAdapter) GetWorker(workerID string) (WorkerStatus, error) {
|
||||
}
|
||||
|
||||
func (b *mockDBAdapter) DeleteWorker(workerID string) error {
|
||||
b.workerLock.Lock()
|
||||
delete(b.workerStore, workerID)
|
||||
b.workerLock.Unlock()
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -458,7 +468,9 @@ func (b *mockDBAdapter) CreateWorker(w WorkerStatus) (WorkerStatus, error) {
|
||||
// if ok {
|
||||
// return workerStatus{}, fmt.Errorf("duplicate worker name")
|
||||
// }
|
||||
b.workerLock.Lock()
|
||||
b.workerStore[w.ID] = w
|
||||
b.workerLock.Unlock()
|
||||
return w, nil
|
||||
}
|
||||
|
||||
@ -473,7 +485,9 @@ func (b *mockDBAdapter) RefreshWorker(workerID string) (w WorkerStatus, err erro
|
||||
|
||||
func (b *mockDBAdapter) GetMirrorStatus(workerID, mirrorID string) (MirrorStatus, error) {
|
||||
id := mirrorID + "/" + workerID
|
||||
b.statusLock.RLock()
|
||||
status, ok := b.statusStore[id]
|
||||
b.statusLock.RUnlock()
|
||||
if !ok {
|
||||
return MirrorStatus{}, fmt.Errorf("no mirror %s exists in worker %s", mirrorID, workerID)
|
||||
}
|
||||
@ -487,7 +501,9 @@ func (b *mockDBAdapter) UpdateMirrorStatus(workerID, mirrorID string, status Mir
|
||||
// }
|
||||
|
||||
id := mirrorID + "/" + workerID
|
||||
b.statusLock.Lock()
|
||||
b.statusStore[id] = status
|
||||
b.statusLock.Unlock()
|
||||
return status, nil
|
||||
}
|
||||
|
||||
@ -497,19 +513,23 @@ func (b *mockDBAdapter) ListMirrorStatus(workerID string) ([]MirrorStatus, error
|
||||
if workerID == _magicBadWorkerID {
|
||||
return []MirrorStatus{}, fmt.Errorf("database fail")
|
||||
}
|
||||
b.statusLock.RLock()
|
||||
for k, v := range b.statusStore {
|
||||
if wID := strings.Split(k, "/")[1]; wID == workerID {
|
||||
mirrorStatusList = append(mirrorStatusList, v)
|
||||
}
|
||||
}
|
||||
b.statusLock.RUnlock()
|
||||
return mirrorStatusList, nil
|
||||
}
|
||||
|
||||
func (b *mockDBAdapter) ListAllMirrorStatus() ([]MirrorStatus, error) {
|
||||
var mirrorStatusList []MirrorStatus
|
||||
b.statusLock.RLock()
|
||||
for _, v := range b.statusStore {
|
||||
mirrorStatusList = append(mirrorStatusList, v)
|
||||
}
|
||||
b.statusLock.RUnlock()
|
||||
return mirrorStatusList, nil
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
@ -1,3 +1,4 @@
|
||||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
@ -1,3 +1,4 @@
|
||||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
@ -1,3 +1,4 @@
|
||||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
@ -19,9 +19,10 @@ type baseProvider struct {
|
||||
timeout time.Duration
|
||||
isMaster bool
|
||||
|
||||
cmd *cmdJob
|
||||
logFileFd *os.File
|
||||
isRunning atomic.Value
|
||||
cmd *cmdJob
|
||||
logFileFd *os.File
|
||||
isRunning atomic.Value
|
||||
successExitCodes []int
|
||||
|
||||
cgroup *cgroupHook
|
||||
zfs *zfsHook
|
||||
@ -186,3 +187,18 @@ func (p *baseProvider) Terminate() error {
|
||||
func (p *baseProvider) DataSize() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func (p *baseProvider) SetSuccessExitCodes(codes []int) {
|
||||
if codes == nil {
|
||||
p.successExitCodes = []int{}
|
||||
} else {
|
||||
p.successExitCodes = codes
|
||||
}
|
||||
}
|
||||
|
||||
func (p *baseProvider) GetSuccessExitCodes() []int {
|
||||
if p.successExitCodes == nil {
|
||||
return []int{}
|
||||
}
|
||||
return p.successExitCodes
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
package worker
|
||||
|
@ -1,3 +1,4 @@
|
||||
//go:build !linux
|
||||
// +build !linux
|
||||
|
||||
package worker
|
||||
|
@ -3,7 +3,7 @@ package worker
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"io"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
@ -12,32 +12,33 @@ import (
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
|
||||
"github.com/moby/moby/pkg/reexec"
|
||||
cgv1 "github.com/containerd/cgroups"
|
||||
cgv2 "github.com/containerd/cgroups/v2"
|
||||
cgroups "github.com/containerd/cgroups/v3"
|
||||
cgv1 "github.com/containerd/cgroups/v3/cgroup1"
|
||||
cgv2 "github.com/containerd/cgroups/v3/cgroup2"
|
||||
"github.com/moby/sys/reexec"
|
||||
contspecs "github.com/opencontainers/runtime-spec/specs-go"
|
||||
)
|
||||
|
||||
type cgroupHook struct {
|
||||
emptyHook
|
||||
cgCfg cgroupConfig
|
||||
memLimit MemBytes
|
||||
cgMgrV1 cgv1.Cgroup
|
||||
cgMgrV2 *cgv2.Manager
|
||||
cgCfg cgroupConfig
|
||||
memLimit MemBytes
|
||||
cgMgrV1 cgv1.Cgroup
|
||||
cgMgrV2 *cgv2.Manager
|
||||
}
|
||||
|
||||
type execCmd string
|
||||
|
||||
const (
|
||||
cmdCont execCmd = "cont"
|
||||
cmdAbrt execCmd = "abrt"
|
||||
cmdCont execCmd = "cont"
|
||||
cmdAbrt execCmd = "abrt"
|
||||
)
|
||||
|
||||
func init () {
|
||||
func init() {
|
||||
reexec.Register("tunasync-exec", waitExec)
|
||||
}
|
||||
|
||||
func waitExec () {
|
||||
func waitExec() {
|
||||
binary, err := exec.LookPath(os.Args[1])
|
||||
if err != nil {
|
||||
panic(err)
|
||||
@ -46,7 +47,7 @@ func waitExec () {
|
||||
pipe := os.NewFile(3, "pipe")
|
||||
if pipe != nil {
|
||||
if _, err := pipe.Stat(); err == nil {
|
||||
cmdBytes, err := ioutil.ReadAll(pipe)
|
||||
cmdBytes, err := io.ReadAll(pipe)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
@ -54,11 +55,11 @@ func waitExec () {
|
||||
}
|
||||
cmd := execCmd(string(cmdBytes))
|
||||
switch cmd {
|
||||
case cmdAbrt:
|
||||
fallthrough
|
||||
default:
|
||||
panic("Exited on request")
|
||||
case cmdCont:
|
||||
case cmdAbrt:
|
||||
fallthrough
|
||||
default:
|
||||
panic("Exited on request")
|
||||
case cmdCont:
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -71,7 +72,7 @@ func waitExec () {
|
||||
panic("Exec failed.")
|
||||
}
|
||||
|
||||
func initCgroup(cfg *cgroupConfig) (error) {
|
||||
func initCgroup(cfg *cgroupConfig) error {
|
||||
|
||||
logger.Debugf("Initializing cgroup")
|
||||
baseGroup := cfg.Group
|
||||
@ -83,7 +84,7 @@ func initCgroup(cfg *cgroupConfig) (error) {
|
||||
baseGroup = filepath.Join("/", baseGroup)
|
||||
}
|
||||
|
||||
cfg.isUnified = cgv1.Mode() == cgv1.Unified
|
||||
cfg.isUnified = cgroups.Mode() == cgroups.Unified
|
||||
|
||||
if cfg.isUnified {
|
||||
logger.Debugf("Cgroup V2 detected")
|
||||
@ -98,12 +99,12 @@ func initCgroup(cfg *cgroupConfig) (error) {
|
||||
logger.Infof("Using cgroup path: %s", g)
|
||||
|
||||
var err error
|
||||
if cfg.cgMgrV2, err = cgv2.LoadManager("/sys/fs/cgroup", g); err != nil {
|
||||
if cfg.cgMgrV2, err = cgv2.Load(g); err != nil {
|
||||
return err
|
||||
}
|
||||
if baseGroup == "" {
|
||||
logger.Debugf("Creating a sub group and move all processes into it")
|
||||
wkrMgr, err := cfg.cgMgrV2.NewChild("__worker", nil);
|
||||
wkrMgr, err := cfg.cgMgrV2.NewChild("__worker", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -117,8 +118,8 @@ func initCgroup(cfg *cgroupConfig) (error) {
|
||||
if len(procs) == 0 {
|
||||
break
|
||||
}
|
||||
for _, p := range(procs) {
|
||||
if err := wkrMgr.AddProc(p); err != nil{
|
||||
for _, p := range procs {
|
||||
if err := wkrMgr.AddProc(p); err != nil {
|
||||
if errors.Is(err, syscall.ESRCH) {
|
||||
logger.Debugf("Write pid %d to sub group failed: process vanished, ignoring")
|
||||
} else {
|
||||
@ -129,7 +130,7 @@ func initCgroup(cfg *cgroupConfig) (error) {
|
||||
}
|
||||
} else {
|
||||
logger.Debugf("Trying to create a sub group in that group")
|
||||
testMgr, err := cfg.cgMgrV2.NewChild("__test", nil);
|
||||
testMgr, err := cfg.cgMgrV2.NewChild("__test", nil)
|
||||
if err != nil {
|
||||
logger.Errorf("Cannot create a sub group in the cgroup")
|
||||
return err
|
||||
@ -152,9 +153,9 @@ func initCgroup(cfg *cgroupConfig) (error) {
|
||||
if baseGroup != "" {
|
||||
pather = cgv1.StaticPath(baseGroup)
|
||||
} else {
|
||||
pather = (func(p cgv1.Path) (cgv1.Path){
|
||||
return func(subsys cgv1.Name) (string, error){
|
||||
path, err := p(subsys);
|
||||
pather = (func(p cgv1.Path) cgv1.Path {
|
||||
return func(subsys cgv1.Name) (string, error) {
|
||||
path, err := p(subsys)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@ -167,14 +168,14 @@ func initCgroup(cfg *cgroupConfig) (error) {
|
||||
}
|
||||
logger.Infof("Loading cgroup")
|
||||
var err error
|
||||
if cfg.cgMgrV1, err = cgv1.Load(cgv1.V1, pather, func(cfg *cgv1.InitConfig) error{
|
||||
if cfg.cgMgrV1, err = cgv1.Load(pather, func(cfg *cgv1.InitConfig) error {
|
||||
cfg.InitCheck = cgv1.AllowAny
|
||||
return nil
|
||||
}); err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Debugf("Available subsystems:")
|
||||
for _, subsys := range(cfg.cgMgrV1.Subsystems()) {
|
||||
for _, subsys := range cfg.cgMgrV1.Subsystems() {
|
||||
p, err := pather(subsys.Name())
|
||||
if err != nil {
|
||||
return err
|
||||
@ -183,11 +184,11 @@ func initCgroup(cfg *cgroupConfig) (error) {
|
||||
}
|
||||
if baseGroup == "" {
|
||||
logger.Debugf("Creating a sub group and move all processes into it")
|
||||
wkrMgr, err := cfg.cgMgrV1.New("__worker", &contspecs.LinuxResources{});
|
||||
wkrMgr, err := cfg.cgMgrV1.New("__worker", &contspecs.LinuxResources{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, subsys := range(cfg.cgMgrV1.Subsystems()) {
|
||||
for _, subsys := range cfg.cgMgrV1.Subsystems() {
|
||||
logger.Debugf("Reading pids for subsystem %s", subsys.Name())
|
||||
for {
|
||||
procs, err := cfg.cgMgrV1.Processes(subsys.Name(), false)
|
||||
@ -202,7 +203,7 @@ func initCgroup(cfg *cgroupConfig) (error) {
|
||||
if len(procs) == 0 {
|
||||
break
|
||||
}
|
||||
for _, proc := range(procs) {
|
||||
for _, proc := range procs {
|
||||
if err := wkrMgr.Add(proc); err != nil {
|
||||
if errors.Is(err, syscall.ESRCH) {
|
||||
logger.Debugf("Write pid %d to sub group failed: process vanished, ignoring")
|
||||
@ -215,7 +216,7 @@ func initCgroup(cfg *cgroupConfig) (error) {
|
||||
}
|
||||
} else {
|
||||
logger.Debugf("Trying to create a sub group in that group")
|
||||
testMgr, err := cfg.cgMgrV1.New("__test", &contspecs.LinuxResources{});
|
||||
testMgr, err := cfg.cgMgrV1.New("__test", &contspecs.LinuxResources{})
|
||||
if err != nil {
|
||||
logger.Errorf("Cannot create a sub group in the cgroup")
|
||||
return err
|
||||
@ -223,7 +224,7 @@ func initCgroup(cfg *cgroupConfig) (error) {
|
||||
if err := testMgr.Delete(); err != nil {
|
||||
return err
|
||||
}
|
||||
for _, subsys := range(cfg.cgMgrV1.Subsystems()) {
|
||||
for _, subsys := range cfg.cgMgrV1.Subsystems() {
|
||||
logger.Debugf("Reading pids for subsystem %s", subsys.Name())
|
||||
procs, err := cfg.cgMgrV1.Processes(subsys.Name(), false)
|
||||
if err != nil {
|
||||
@ -253,7 +254,7 @@ func newCgroupHook(p mirrorProvider, cfg cgroupConfig, memLimit MemBytes) *cgrou
|
||||
emptyHook: emptyHook{
|
||||
provider: p,
|
||||
},
|
||||
cgCfg: cfg,
|
||||
cgCfg: cfg,
|
||||
memLimit: memLimit,
|
||||
}
|
||||
}
|
||||
@ -263,7 +264,7 @@ func (c *cgroupHook) preExec() error {
|
||||
logger.Debugf("Creating v2 cgroup for task %s", c.provider.Name())
|
||||
var resSet *cgv2.Resources
|
||||
if c.memLimit != 0 {
|
||||
resSet = &cgv2.Resources {
|
||||
resSet = &cgv2.Resources{
|
||||
Memory: &cgv2.Memory{
|
||||
Max: func(i int64) *int64 { return &i }(c.memLimit.Value()),
|
||||
},
|
||||
@ -279,7 +280,7 @@ func (c *cgroupHook) preExec() error {
|
||||
logger.Debugf("Creating v1 cgroup for task %s", c.provider.Name())
|
||||
var resSet contspecs.LinuxResources
|
||||
if c.memLimit != 0 {
|
||||
resSet = contspecs.LinuxResources {
|
||||
resSet = contspecs.LinuxResources{
|
||||
Memory: &contspecs.LinuxMemory{
|
||||
Limit: func(i int64) *int64 { return &i }(c.memLimit.Value()),
|
||||
},
|
||||
@ -334,7 +335,7 @@ func (c *cgroupHook) killAll() error {
|
||||
taskList := []int{}
|
||||
if c.cgCfg.isUnified {
|
||||
procs, err := c.cgMgrV2.Procs(false)
|
||||
if (err != nil) {
|
||||
if err != nil {
|
||||
return []int{}, err
|
||||
}
|
||||
for _, proc := range procs {
|
||||
@ -342,16 +343,16 @@ func (c *cgroupHook) killAll() error {
|
||||
}
|
||||
} else {
|
||||
taskSet := make(map[int]struct{})
|
||||
for _, subsys := range(c.cgMgrV1.Subsystems()) {
|
||||
for _, subsys := range c.cgMgrV1.Subsystems() {
|
||||
procs, err := c.cgMgrV1.Processes(subsys.Name(), false)
|
||||
if err != nil {
|
||||
return []int{}, err
|
||||
}
|
||||
for _, proc := range(procs) {
|
||||
for _, proc := range procs {
|
||||
taskSet[proc.Pid] = struct{}{}
|
||||
}
|
||||
}
|
||||
for proc := range(taskSet) {
|
||||
for proc := range taskSet {
|
||||
taskList = append(taskList, proc)
|
||||
}
|
||||
}
|
||||
|
@ -1,34 +1,34 @@
|
||||
package worker
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"errors"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"syscall"
|
||||
"testing"
|
||||
"time"
|
||||
"errors"
|
||||
"syscall"
|
||||
cgv1 "github.com/containerd/cgroups"
|
||||
cgv2 "github.com/containerd/cgroups/v2"
|
||||
|
||||
cgv1 "github.com/containerd/cgroups/v3/cgroup1"
|
||||
cgv2 "github.com/containerd/cgroups/v3/cgroup2"
|
||||
units "github.com/docker/go-units"
|
||||
"github.com/moby/moby/pkg/reexec"
|
||||
"github.com/moby/sys/reexec"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
)
|
||||
|
||||
func init() {
|
||||
_, testReexec := os.LookupEnv("TESTREEXEC")
|
||||
if ! testReexec {
|
||||
if !testReexec {
|
||||
reexec.Init()
|
||||
}
|
||||
}
|
||||
|
||||
func TestReexec(t *testing.T) {
|
||||
testCase, testReexec := os.LookupEnv("TESTREEXEC")
|
||||
if ! testReexec {
|
||||
if !testReexec {
|
||||
return
|
||||
}
|
||||
for len(os.Args) > 1 {
|
||||
@ -39,51 +39,51 @@ func TestReexec(t *testing.T) {
|
||||
}
|
||||
}
|
||||
switch testCase {
|
||||
case "1":
|
||||
Convey("Reexec should panic when command not found", t, func(ctx C){
|
||||
So(func(){
|
||||
reexec.Init()
|
||||
}, ShouldPanicWith, exec.ErrNotFound)
|
||||
})
|
||||
case "2":
|
||||
Convey("Reexec should run when fd 3 is not open", t, func(ctx C){
|
||||
So((func() error{
|
||||
pipe := os.NewFile(3, "pipe")
|
||||
if pipe == nil {
|
||||
return errors.New("pipe is nil")
|
||||
} else {
|
||||
_, err := pipe.Stat()
|
||||
return err
|
||||
}
|
||||
})(), ShouldNotBeNil)
|
||||
So(func(){
|
||||
reexec.Init()
|
||||
}, ShouldPanicWith, syscall.ENOEXEC)
|
||||
})
|
||||
case "3":
|
||||
Convey("Reexec should fail when fd 3 is sent with abrt cmd", t, func(ctx C){
|
||||
So(func(){
|
||||
reexec.Init()
|
||||
}, ShouldPanicWith, "Exited on request")
|
||||
})
|
||||
case "4":
|
||||
Convey("Reexec should run when fd 3 is sent with cont cmd", t, func(ctx C){
|
||||
So(func(){
|
||||
reexec.Init()
|
||||
}, ShouldPanicWith, syscall.ENOEXEC)
|
||||
})
|
||||
case "5":
|
||||
Convey("Reexec should not be triggered when argv[0] is not reexec", t, func(ctx C){
|
||||
So(func(){
|
||||
reexec.Init()
|
||||
}, ShouldNotPanic)
|
||||
})
|
||||
case "1":
|
||||
Convey("Reexec should panic when command not found", t, func(ctx C) {
|
||||
So(func() {
|
||||
reexec.Init()
|
||||
}, ShouldPanicWith, exec.ErrNotFound)
|
||||
})
|
||||
case "2":
|
||||
Convey("Reexec should run when fd 3 is not open", t, func(ctx C) {
|
||||
So((func() error {
|
||||
pipe := os.NewFile(3, "pipe")
|
||||
if pipe == nil {
|
||||
return errors.New("pipe is nil")
|
||||
} else {
|
||||
_, err := pipe.Stat()
|
||||
return err
|
||||
}
|
||||
})(), ShouldNotBeNil)
|
||||
So(func() {
|
||||
reexec.Init()
|
||||
}, ShouldPanicWith, syscall.ENOEXEC)
|
||||
})
|
||||
case "3":
|
||||
Convey("Reexec should fail when fd 3 is sent with abrt cmd", t, func(ctx C) {
|
||||
So(func() {
|
||||
reexec.Init()
|
||||
}, ShouldPanicWith, "Exited on request")
|
||||
})
|
||||
case "4":
|
||||
Convey("Reexec should run when fd 3 is sent with cont cmd", t, func(ctx C) {
|
||||
So(func() {
|
||||
reexec.Init()
|
||||
}, ShouldPanicWith, syscall.ENOEXEC)
|
||||
})
|
||||
case "5":
|
||||
Convey("Reexec should not be triggered when argv[0] is not reexec", t, func(ctx C) {
|
||||
So(func() {
|
||||
reexec.Init()
|
||||
}, ShouldNotPanic)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCgroup(t *testing.T) {
|
||||
var cgcf *cgroupConfig
|
||||
Convey("init cgroup", t, func(ctx C){
|
||||
Convey("init cgroup", t, func(ctx C) {
|
||||
_, useCurrentCgroup := os.LookupEnv("USECURCGROUP")
|
||||
cgcf = &cgroupConfig{BasePath: "/sys/fs/cgroup", Group: "tunasync", Subsystem: "cpu"}
|
||||
if useCurrentCgroup {
|
||||
@ -97,28 +97,28 @@ func TestCgroup(t *testing.T) {
|
||||
So(cgcf.cgMgrV1, ShouldNotBeNil)
|
||||
}
|
||||
|
||||
Convey("Cgroup Should Work", func(ctx C) {
|
||||
tmpDir, err := ioutil.TempDir("", "tunasync")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
So(err, ShouldBeNil)
|
||||
cmdScript := filepath.Join(tmpDir, "cmd.sh")
|
||||
daemonScript := filepath.Join(tmpDir, "daemon.sh")
|
||||
tmpFile := filepath.Join(tmpDir, "log_file")
|
||||
bgPidfile := filepath.Join(tmpDir, "bg.pid")
|
||||
Convey("Cgroup Should Work", func(ctx C) {
|
||||
tmpDir, err := os.MkdirTemp("", "tunasync")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
So(err, ShouldBeNil)
|
||||
cmdScript := filepath.Join(tmpDir, "cmd.sh")
|
||||
daemonScript := filepath.Join(tmpDir, "daemon.sh")
|
||||
tmpFile := filepath.Join(tmpDir, "log_file")
|
||||
bgPidfile := filepath.Join(tmpDir, "bg.pid")
|
||||
|
||||
c := cmdConfig{
|
||||
name: "tuna-cgroup",
|
||||
upstreamURL: "http://mirrors.tuna.moe/",
|
||||
command: cmdScript + " " + daemonScript,
|
||||
workingDir: tmpDir,
|
||||
logDir: tmpDir,
|
||||
logFile: tmpFile,
|
||||
interval: 600 * time.Second,
|
||||
env: map[string]string{
|
||||
"BG_PIDFILE": bgPidfile,
|
||||
},
|
||||
}
|
||||
cmdScriptContent := `#!/bin/bash
|
||||
c := cmdConfig{
|
||||
name: "tuna-cgroup",
|
||||
upstreamURL: "http://mirrors.tuna.moe/",
|
||||
command: cmdScript + " " + daemonScript,
|
||||
workingDir: tmpDir,
|
||||
logDir: tmpDir,
|
||||
logFile: tmpFile,
|
||||
interval: 600 * time.Second,
|
||||
env: map[string]string{
|
||||
"BG_PIDFILE": bgPidfile,
|
||||
},
|
||||
}
|
||||
cmdScriptContent := `#!/bin/bash
|
||||
redirect-std() {
|
||||
[[ -t 0 ]] && exec </dev/null
|
||||
[[ -t 1 ]] && exec >/dev/null
|
||||
@ -144,167 +144,127 @@ echo $$
|
||||
daemonize $@
|
||||
sleep 5
|
||||
`
|
||||
daemonScriptContent := `#!/bin/bash
|
||||
daemonScriptContent := `#!/bin/bash
|
||||
echo $$ > $BG_PIDFILE
|
||||
sleep 30
|
||||
`
|
||||
err = ioutil.WriteFile(cmdScript, []byte(cmdScriptContent), 0755)
|
||||
So(err, ShouldBeNil)
|
||||
err = ioutil.WriteFile(daemonScript, []byte(daemonScriptContent), 0755)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
provider, err := newCmdProvider(c)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
cg := newCgroupHook(provider, *cgcf, 0)
|
||||
provider.AddHook(cg)
|
||||
|
||||
err = cg.preExec()
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
go func() {
|
||||
err := provider.Run(make(chan empty, 1))
|
||||
ctx.So(err, ShouldNotBeNil)
|
||||
}()
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
// Deamon should be started
|
||||
daemonPidBytes, err := ioutil.ReadFile(bgPidfile)
|
||||
So(err, ShouldBeNil)
|
||||
daemonPid := strings.Trim(string(daemonPidBytes), " \n")
|
||||
logger.Debug("daemon pid: %s", daemonPid)
|
||||
procDir := filepath.Join("/proc", daemonPid)
|
||||
_, err = os.Stat(procDir)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
err = provider.Terminate()
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// Deamon won't be killed
|
||||
_, err = os.Stat(procDir)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// Deamon can be killed by cgroup killer
|
||||
cg.postExec()
|
||||
_, err = os.Stat(procDir)
|
||||
So(os.IsNotExist(err), ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Rsync Memory Should Be Limited", func() {
|
||||
tmpDir, err := ioutil.TempDir("", "tunasync")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
So(err, ShouldBeNil)
|
||||
scriptFile := filepath.Join(tmpDir, "myrsync")
|
||||
tmpFile := filepath.Join(tmpDir, "log_file")
|
||||
|
||||
c := rsyncConfig{
|
||||
name: "tuna-cgroup",
|
||||
upstreamURL: "rsync://rsync.tuna.moe/tuna/",
|
||||
rsyncCmd: scriptFile,
|
||||
workingDir: tmpDir,
|
||||
logDir: tmpDir,
|
||||
logFile: tmpFile,
|
||||
useIPv6: true,
|
||||
interval: 600 * time.Second,
|
||||
}
|
||||
|
||||
provider, err := newRsyncProvider(c)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
cg := newCgroupHook(provider, *cgcf, 512 * units.MiB)
|
||||
provider.AddHook(cg)
|
||||
|
||||
err = cg.preExec()
|
||||
So(err, ShouldBeNil)
|
||||
if cgcf.isUnified {
|
||||
cgpath := filepath.Join(cgcf.BasePath, cgcf.Group, provider.Name())
|
||||
if useCurrentCgroup {
|
||||
group, err := cgv2.NestedGroupPath(filepath.Join("..", provider.Name()))
|
||||
So(err, ShouldBeNil)
|
||||
cgpath = filepath.Join(cgcf.BasePath, group)
|
||||
}
|
||||
memoLimit, err := ioutil.ReadFile(filepath.Join(cgpath, "memory.max"))
|
||||
err = os.WriteFile(cmdScript, []byte(cmdScriptContent), 0755)
|
||||
So(err, ShouldBeNil)
|
||||
So(strings.Trim(string(memoLimit), "\n"), ShouldEqual, strconv.Itoa(512*1024*1024))
|
||||
} else {
|
||||
for _, subsys := range(cg.cgMgrV1.Subsystems()) {
|
||||
if subsys.Name() == cgv1.Memory {
|
||||
cgpath := filepath.Join(cgcf.Group, provider.Name())
|
||||
if useCurrentCgroup {
|
||||
p, err := cgv1.NestedPath(filepath.Join("..", provider.Name()))(cgv1.Memory)
|
||||
err = os.WriteFile(daemonScript, []byte(daemonScriptContent), 0755)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
provider, err := newCmdProvider(c)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
cg := newCgroupHook(provider, *cgcf, 0)
|
||||
provider.AddHook(cg)
|
||||
|
||||
err = cg.preExec()
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
go func() {
|
||||
err := provider.Run(make(chan empty, 1))
|
||||
ctx.So(err, ShouldNotBeNil)
|
||||
}()
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
// Deamon should be started
|
||||
daemonPidBytes, err := os.ReadFile(bgPidfile)
|
||||
So(err, ShouldBeNil)
|
||||
daemonPid := strings.Trim(string(daemonPidBytes), " \n")
|
||||
logger.Debug("daemon pid: %s", daemonPid)
|
||||
procDir := filepath.Join("/proc", daemonPid)
|
||||
_, err = os.Stat(procDir)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
err = provider.Terminate()
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// Deamon won't be killed
|
||||
_, err = os.Stat(procDir)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
// Deamon can be killed by cgroup killer
|
||||
cg.postExec()
|
||||
_, err = os.Stat(procDir)
|
||||
So(os.IsNotExist(err), ShouldBeTrue)
|
||||
|
||||
})
|
||||
|
||||
Convey("Rsync Memory Should Be Limited", func() {
|
||||
tmpDir, err := os.MkdirTemp("", "tunasync")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
So(err, ShouldBeNil)
|
||||
scriptFile := filepath.Join(tmpDir, "myrsync")
|
||||
tmpFile := filepath.Join(tmpDir, "log_file")
|
||||
|
||||
c := rsyncConfig{
|
||||
name: "tuna-cgroup",
|
||||
upstreamURL: "rsync://rsync.tuna.moe/tuna/",
|
||||
rsyncCmd: scriptFile,
|
||||
workingDir: tmpDir,
|
||||
logDir: tmpDir,
|
||||
logFile: tmpFile,
|
||||
useIPv6: true,
|
||||
interval: 600 * time.Second,
|
||||
}
|
||||
|
||||
provider, err := newRsyncProvider(c)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
cg := newCgroupHook(provider, *cgcf, 512*units.MiB)
|
||||
provider.AddHook(cg)
|
||||
|
||||
err = cg.preExec()
|
||||
So(err, ShouldBeNil)
|
||||
if cgcf.isUnified {
|
||||
cgpath := filepath.Join(cgcf.BasePath, cgcf.Group, provider.Name())
|
||||
if useCurrentCgroup {
|
||||
group, err := cgv2.NestedGroupPath(filepath.Join("..", provider.Name()))
|
||||
So(err, ShouldBeNil)
|
||||
cgpath = filepath.Join(cgcf.BasePath, group)
|
||||
}
|
||||
memoLimit, err := os.ReadFile(filepath.Join(cgpath, "memory.max"))
|
||||
So(err, ShouldBeNil)
|
||||
So(strings.Trim(string(memoLimit), "\n"), ShouldEqual, strconv.Itoa(512*1024*1024))
|
||||
} else {
|
||||
for _, subsys := range cg.cgMgrV1.Subsystems() {
|
||||
if subsys.Name() == cgv1.Memory {
|
||||
cgpath := filepath.Join(cgcf.Group, provider.Name())
|
||||
if useCurrentCgroup {
|
||||
p, err := cgv1.NestedPath(filepath.Join("..", provider.Name()))(cgv1.Memory)
|
||||
So(err, ShouldBeNil)
|
||||
cgpath = p
|
||||
}
|
||||
memoLimit, err := os.ReadFile(filepath.Join(cgcf.BasePath, "memory", cgpath, "memory.limit_in_bytes"))
|
||||
So(err, ShouldBeNil)
|
||||
cgpath = p
|
||||
}
|
||||
memoLimit, err := ioutil.ReadFile(filepath.Join(cgcf.BasePath, "memory", cgpath, "memory.limit_in_bytes"))
|
||||
So(err, ShouldBeNil)
|
||||
So(strings.Trim(string(memoLimit), "\n"), ShouldEqual, strconv.Itoa(512*1024*1024))
|
||||
}
|
||||
}
|
||||
}
|
||||
cg.postExec()
|
||||
So(cg.cgMgrV1, ShouldBeNil)
|
||||
})
|
||||
Reset(func() {
|
||||
if cgcf.isUnified {
|
||||
if cgcf.Group == "" {
|
||||
wkrg, err := cgv2.NestedGroupPath("");
|
||||
So(err, ShouldBeNil)
|
||||
wkrMgr, err := cgv2.LoadManager("/sys/fs/cgroup", wkrg);
|
||||
allCtrls, err := wkrMgr.Controllers()
|
||||
So(err, ShouldBeNil)
|
||||
err = wkrMgr.ToggleControllers(allCtrls, cgv2.Disable)
|
||||
So(err, ShouldBeNil)
|
||||
origMgr := cgcf.cgMgrV2
|
||||
for {
|
||||
logger.Debugf("Restoring pids")
|
||||
procs, err := wkrMgr.Procs(false)
|
||||
So(err, ShouldBeNil)
|
||||
if len(procs) == 0 {
|
||||
break
|
||||
}
|
||||
for _, p := range(procs) {
|
||||
if err := origMgr.AddProc(p); err != nil{
|
||||
if errors.Is(err, syscall.ESRCH) {
|
||||
logger.Debugf("Write pid %d to sub group failed: process vanished, ignoring")
|
||||
} else {
|
||||
So(err, ShouldBeNil)
|
||||
}
|
||||
}
|
||||
So(strings.Trim(string(memoLimit), "\n"), ShouldEqual, strconv.Itoa(512*1024*1024))
|
||||
}
|
||||
}
|
||||
err = wkrMgr.Delete()
|
||||
So(err, ShouldBeNil)
|
||||
}
|
||||
} else {
|
||||
if cgcf.Group == "" {
|
||||
pather := (func(p cgv1.Path) (cgv1.Path){
|
||||
return func(subsys cgv1.Name) (string, error){
|
||||
path, err := p(subsys);
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if path == "/" {
|
||||
return "", cgv1.ErrControllerNotActive
|
||||
}
|
||||
return path, err
|
||||
}
|
||||
})(cgv1.NestedPath(""))
|
||||
wkrMgr, err := cgv1.Load(cgv1.V1, pather, func(cfg *cgv1.InitConfig) error{
|
||||
cfg.InitCheck = cgv1.AllowAny
|
||||
return nil
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
origMgr := cgcf.cgMgrV1
|
||||
for _, subsys := range(wkrMgr.Subsystems()){
|
||||
cg.postExec()
|
||||
So(cg.cgMgrV1, ShouldBeNil)
|
||||
})
|
||||
Reset(func() {
|
||||
if cgcf.isUnified {
|
||||
if cgcf.Group == "" {
|
||||
wkrg, err := cgv2.NestedGroupPath("")
|
||||
So(err, ShouldBeNil)
|
||||
wkrMgr, _ := cgv2.Load(wkrg)
|
||||
allCtrls, err := wkrMgr.Controllers()
|
||||
So(err, ShouldBeNil)
|
||||
err = wkrMgr.ToggleControllers(allCtrls, cgv2.Disable)
|
||||
So(err, ShouldBeNil)
|
||||
origMgr := cgcf.cgMgrV2
|
||||
for {
|
||||
procs, err := wkrMgr.Processes(subsys.Name(), false)
|
||||
logger.Debugf("Restoring pids")
|
||||
procs, err := wkrMgr.Procs(false)
|
||||
So(err, ShouldBeNil)
|
||||
if len(procs) == 0 {
|
||||
break
|
||||
}
|
||||
for _, proc := range(procs) {
|
||||
if err := origMgr.Add(proc); err != nil {
|
||||
for _, p := range procs {
|
||||
if err := origMgr.AddProc(p); err != nil {
|
||||
if errors.Is(err, syscall.ESRCH) {
|
||||
logger.Debugf("Write pid %d to sub group failed: process vanished, ignoring")
|
||||
} else {
|
||||
@ -313,11 +273,51 @@ sleep 30
|
||||
}
|
||||
}
|
||||
}
|
||||
err = wkrMgr.Delete()
|
||||
So(err, ShouldBeNil)
|
||||
}
|
||||
} else {
|
||||
if cgcf.Group == "" {
|
||||
pather := (func(p cgv1.Path) cgv1.Path {
|
||||
return func(subsys cgv1.Name) (string, error) {
|
||||
path, err := p(subsys)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
if path == "/" {
|
||||
return "", cgv1.ErrControllerNotActive
|
||||
}
|
||||
return path, err
|
||||
}
|
||||
})(cgv1.NestedPath(""))
|
||||
wkrMgr, err := cgv1.Load(pather, func(cfg *cgv1.InitConfig) error {
|
||||
cfg.InitCheck = cgv1.AllowAny
|
||||
return nil
|
||||
})
|
||||
So(err, ShouldBeNil)
|
||||
origMgr := cgcf.cgMgrV1
|
||||
for _, subsys := range wkrMgr.Subsystems() {
|
||||
for {
|
||||
procs, err := wkrMgr.Processes(subsys.Name(), false)
|
||||
So(err, ShouldBeNil)
|
||||
if len(procs) == 0 {
|
||||
break
|
||||
}
|
||||
for _, proc := range procs {
|
||||
if err := origMgr.Add(proc); err != nil {
|
||||
if errors.Is(err, syscall.ESRCH) {
|
||||
logger.Debugf("Write pid %d to sub group failed: process vanished, ignoring")
|
||||
} else {
|
||||
So(err, ShouldBeNil)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
err = wkrMgr.Delete()
|
||||
So(err, ShouldBeNil)
|
||||
}
|
||||
err = wkrMgr.Delete()
|
||||
So(err, ShouldBeNil)
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -6,10 +6,10 @@ import (
|
||||
"path/filepath"
|
||||
|
||||
"github.com/BurntSushi/toml"
|
||||
"github.com/imdario/mergo"
|
||||
cgv1 "github.com/containerd/cgroups/v3/cgroup1"
|
||||
cgv2 "github.com/containerd/cgroups/v3/cgroup2"
|
||||
units "github.com/docker/go-units"
|
||||
cgv1 "github.com/containerd/cgroups"
|
||||
cgv2 "github.com/containerd/cgroups/v2"
|
||||
"github.com/imdario/mergo"
|
||||
)
|
||||
|
||||
type providerEnum uint8
|
||||
@ -58,8 +58,14 @@ type globalConfig struct {
|
||||
Retry int `toml:"retry"`
|
||||
Timeout int `toml:"timeout"`
|
||||
|
||||
// appended to the options generated by rsync_provider, but before mirror-specific options
|
||||
RsyncOptions []string `toml:"rsync_options"`
|
||||
|
||||
ExecOnSuccess []string `toml:"exec_on_success"`
|
||||
ExecOnFailure []string `toml:"exec_on_failure"`
|
||||
|
||||
// merged with mirror-specific options. make sure you know what you are doing!
|
||||
SuccessExitCodes []int `toml:"dangerous_global_success_exit_codes"`
|
||||
}
|
||||
|
||||
type managerConfig struct {
|
||||
@ -162,23 +168,27 @@ type mirrorConfig struct {
|
||||
ExecOnSuccess []string `toml:"exec_on_success"`
|
||||
ExecOnFailure []string `toml:"exec_on_failure"`
|
||||
|
||||
// These two options the global options
|
||||
// These two options are appended to the global options
|
||||
ExecOnSuccessExtra []string `toml:"exec_on_success_extra"`
|
||||
ExecOnFailureExtra []string `toml:"exec_on_failure_extra"`
|
||||
|
||||
Command string `toml:"command"`
|
||||
FailOnMatch string `toml:"fail_on_match"`
|
||||
SizePattern string `toml:"size_pattern"`
|
||||
UseIPv6 bool `toml:"use_ipv6"`
|
||||
UseIPv4 bool `toml:"use_ipv4"`
|
||||
ExcludeFile string `toml:"exclude_file"`
|
||||
Username string `toml:"username"`
|
||||
Password string `toml:"password"`
|
||||
RsyncNoTimeo bool `toml:"rsync_no_timeout"`
|
||||
RsyncTimeout int `toml:"rsync_timeout"`
|
||||
RsyncOptions []string `toml:"rsync_options"`
|
||||
RsyncOverride []string `toml:"rsync_override"`
|
||||
Stage1Profile string `toml:"stage1_profile"`
|
||||
// will be merged with global option
|
||||
SuccessExitCodes []int `toml:"success_exit_codes"`
|
||||
|
||||
Command string `toml:"command"`
|
||||
FailOnMatch string `toml:"fail_on_match"`
|
||||
SizePattern string `toml:"size_pattern"`
|
||||
UseIPv6 bool `toml:"use_ipv6"`
|
||||
UseIPv4 bool `toml:"use_ipv4"`
|
||||
ExcludeFile string `toml:"exclude_file"`
|
||||
Username string `toml:"username"`
|
||||
Password string `toml:"password"`
|
||||
RsyncNoTimeo bool `toml:"rsync_no_timeout"`
|
||||
RsyncTimeout int `toml:"rsync_timeout"`
|
||||
RsyncOptions []string `toml:"rsync_options"`
|
||||
RsyncOverride []string `toml:"rsync_override"`
|
||||
RsyncOverrideOnly bool `toml:"rsync_override_only"` // only use provided overridden options if true
|
||||
Stage1Profile string `toml:"stage1_profile"`
|
||||
|
||||
MemoryLimit MemBytes `toml:"memory_limit"`
|
||||
|
||||
|
@ -53,34 +53,43 @@ func diffMirrorConfig(oldList, newList []mirrorConfig) []mirrorCfgTrans {
|
||||
sort.Sort(sortableMirrorList(oList))
|
||||
sort.Sort(sortableMirrorList(nList))
|
||||
|
||||
// insert a tail node to both lists
|
||||
// as the maximum node
|
||||
lastOld, lastNew := oList[len(oList)-1], nList[len(nList)-1]
|
||||
maxName := lastOld.Name
|
||||
if lastNew.Name > lastOld.Name {
|
||||
maxName = lastNew.Name
|
||||
}
|
||||
Nil := mirrorConfig{Name: "~" + maxName}
|
||||
if Nil.Name <= maxName {
|
||||
panic("Nil.Name should be larger than maxName")
|
||||
}
|
||||
oList, nList = append(oList, Nil), append(nList, Nil)
|
||||
if len(oList) != 0 && len(nList) != 0 {
|
||||
// insert a tail node to both lists
|
||||
// as the maximum node
|
||||
lastOld, lastNew := oList[len(oList)-1], nList[len(nList)-1]
|
||||
maxName := lastOld.Name
|
||||
if lastNew.Name > lastOld.Name {
|
||||
maxName = lastNew.Name
|
||||
}
|
||||
Nil := mirrorConfig{Name: "~" + maxName}
|
||||
if Nil.Name <= maxName {
|
||||
panic("Nil.Name should be larger than maxName")
|
||||
}
|
||||
oList, nList = append(oList, Nil), append(nList, Nil)
|
||||
|
||||
// iterate over both lists to find the difference
|
||||
for i, j := 0, 0; i < len(oList) && j < len(nList); {
|
||||
o, n := oList[i], nList[j]
|
||||
if n.Name < o.Name {
|
||||
operations = append(operations, mirrorCfgTrans{diffAdd, n})
|
||||
j++
|
||||
} else if o.Name < n.Name {
|
||||
operations = append(operations, mirrorCfgTrans{diffDelete, o})
|
||||
i++
|
||||
} else {
|
||||
if !reflect.DeepEqual(o, n) {
|
||||
operations = append(operations, mirrorCfgTrans{diffModify, n})
|
||||
// iterate over both lists to find the difference
|
||||
for i, j := 0, 0; i < len(oList) && j < len(nList); {
|
||||
o, n := oList[i], nList[j]
|
||||
if n.Name < o.Name {
|
||||
operations = append(operations, mirrorCfgTrans{diffAdd, n})
|
||||
j++
|
||||
} else if o.Name < n.Name {
|
||||
operations = append(operations, mirrorCfgTrans{diffDelete, o})
|
||||
i++
|
||||
} else {
|
||||
if !reflect.DeepEqual(o, n) {
|
||||
operations = append(operations, mirrorCfgTrans{diffModify, n})
|
||||
}
|
||||
i++
|
||||
j++
|
||||
}
|
||||
i++
|
||||
j++
|
||||
}
|
||||
} else {
|
||||
for i := 0; i < len(oList); i++ {
|
||||
operations = append(operations, mirrorCfgTrans{diffDelete, oList[i]})
|
||||
}
|
||||
for i := 0; i < len(nList); i++ {
|
||||
operations = append(operations, mirrorCfgTrans{diffAdd, nList[i]})
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,12 +10,12 @@ import (
|
||||
func TestConfigDiff(t *testing.T) {
|
||||
Convey("When old and new configs are equal", t, func() {
|
||||
oldList := []mirrorConfig{
|
||||
mirrorConfig{Name: "debian"},
|
||||
mirrorConfig{Name: "debian-security"},
|
||||
mirrorConfig{Name: "fedora"},
|
||||
mirrorConfig{Name: "archlinux"},
|
||||
mirrorConfig{Name: "AOSP"},
|
||||
mirrorConfig{Name: "ubuntu"},
|
||||
{Name: "debian"},
|
||||
{Name: "debian-security"},
|
||||
{Name: "fedora"},
|
||||
{Name: "archlinux"},
|
||||
{Name: "AOSP"},
|
||||
{Name: "ubuntu"},
|
||||
}
|
||||
newList := make([]mirrorConfig, len(oldList))
|
||||
copy(newList, oldList)
|
||||
@ -23,21 +23,49 @@ func TestConfigDiff(t *testing.T) {
|
||||
difference := diffMirrorConfig(oldList, newList)
|
||||
So(len(difference), ShouldEqual, 0)
|
||||
})
|
||||
Convey("When old config is empty", t, func() {
|
||||
newList := []mirrorConfig{
|
||||
{Name: "debian"},
|
||||
{Name: "debian-security"},
|
||||
{Name: "fedora"},
|
||||
{Name: "archlinux"},
|
||||
{Name: "AOSP"},
|
||||
{Name: "ubuntu"},
|
||||
}
|
||||
oldList := make([]mirrorConfig, 0)
|
||||
|
||||
difference := diffMirrorConfig(oldList, newList)
|
||||
So(len(difference), ShouldEqual, len(newList))
|
||||
})
|
||||
Convey("When new config is empty", t, func() {
|
||||
oldList := []mirrorConfig{
|
||||
{Name: "debian"},
|
||||
{Name: "debian-security"},
|
||||
{Name: "fedora"},
|
||||
{Name: "archlinux"},
|
||||
{Name: "AOSP"},
|
||||
{Name: "ubuntu"},
|
||||
}
|
||||
newList := make([]mirrorConfig, 0)
|
||||
|
||||
difference := diffMirrorConfig(oldList, newList)
|
||||
So(len(difference), ShouldEqual, len(oldList))
|
||||
})
|
||||
Convey("When giving two config lists with different names", t, func() {
|
||||
oldList := []mirrorConfig{
|
||||
mirrorConfig{Name: "debian"},
|
||||
mirrorConfig{Name: "debian-security"},
|
||||
mirrorConfig{Name: "fedora"},
|
||||
mirrorConfig{Name: "archlinux"},
|
||||
mirrorConfig{Name: "AOSP", Env: map[string]string{"REPO": "/usr/bin/repo"}},
|
||||
mirrorConfig{Name: "ubuntu"},
|
||||
{Name: "debian"},
|
||||
{Name: "debian-security"},
|
||||
{Name: "fedora"},
|
||||
{Name: "archlinux"},
|
||||
{Name: "AOSP", Env: map[string]string{"REPO": "/usr/bin/repo"}},
|
||||
{Name: "ubuntu"},
|
||||
}
|
||||
newList := []mirrorConfig{
|
||||
mirrorConfig{Name: "debian"},
|
||||
mirrorConfig{Name: "debian-cd"},
|
||||
mirrorConfig{Name: "archlinuxcn"},
|
||||
mirrorConfig{Name: "AOSP", Env: map[string]string{"REPO": "/usr/local/bin/aosp-repo"}},
|
||||
mirrorConfig{Name: "ubuntu-ports"},
|
||||
{Name: "debian"},
|
||||
{Name: "debian-cd"},
|
||||
{Name: "archlinuxcn"},
|
||||
{Name: "AOSP", Env: map[string]string{"REPO": "/usr/local/bin/aosp-repo"}},
|
||||
{Name: "ubuntu-ports"},
|
||||
}
|
||||
|
||||
difference := diffMirrorConfig(oldList, newList)
|
||||
|
@ -2,11 +2,11 @@ package worker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
units "github.com/docker/go-units"
|
||||
|
||||
. "github.com/smartystreets/goconvey/convey"
|
||||
@ -76,11 +76,11 @@ exec_on_failure = [
|
||||
})
|
||||
|
||||
Convey("Everything should work on valid config file", t, func() {
|
||||
tmpfile, err := ioutil.TempFile("", "tunasync")
|
||||
tmpfile, err := os.CreateTemp("", "tunasync")
|
||||
So(err, ShouldEqual, nil)
|
||||
defer os.Remove(tmpfile.Name())
|
||||
|
||||
tmpDir, err := ioutil.TempDir("", "tunasync")
|
||||
tmpDir, err := os.MkdirTemp("", "tunasync")
|
||||
So(err, ShouldBeNil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
@ -92,7 +92,7 @@ exec_on_failure = [
|
||||
|
||||
curCfgBlob := cfgBlob + incSection
|
||||
|
||||
err = ioutil.WriteFile(tmpfile.Name(), []byte(curCfgBlob), 0644)
|
||||
err = os.WriteFile(tmpfile.Name(), []byte(curCfgBlob), 0644)
|
||||
So(err, ShouldEqual, nil)
|
||||
defer tmpfile.Close()
|
||||
|
||||
@ -116,9 +116,9 @@ provider = "two-stage-rsync"
|
||||
stage1_profile = "debian"
|
||||
use_ipv6 = true
|
||||
`
|
||||
err = ioutil.WriteFile(filepath.Join(tmpDir, "debian.conf"), []byte(incBlob1), 0644)
|
||||
err = os.WriteFile(filepath.Join(tmpDir, "debian.conf"), []byte(incBlob1), 0644)
|
||||
So(err, ShouldEqual, nil)
|
||||
err = ioutil.WriteFile(filepath.Join(tmpDir, "ubuntu.conf"), []byte(incBlob2), 0644)
|
||||
err = os.WriteFile(filepath.Join(tmpDir, "ubuntu.conf"), []byte(incBlob2), 0644)
|
||||
So(err, ShouldEqual, nil)
|
||||
|
||||
cfg, err := LoadConfig(tmpfile.Name())
|
||||
@ -145,20 +145,20 @@ use_ipv6 = true
|
||||
So(m.Name, ShouldEqual, "debian")
|
||||
So(m.MirrorDir, ShouldEqual, "")
|
||||
So(m.Provider, ShouldEqual, provTwoStageRsync)
|
||||
So(m.MemoryLimit.Value(), ShouldEqual, 256 * units.MiB)
|
||||
So(m.MemoryLimit.Value(), ShouldEqual, 256*units.MiB)
|
||||
|
||||
m = cfg.Mirrors[2]
|
||||
So(m.Name, ShouldEqual, "fedora")
|
||||
So(m.MirrorDir, ShouldEqual, "")
|
||||
So(m.Provider, ShouldEqual, provRsync)
|
||||
So(m.ExcludeFile, ShouldEqual, "/etc/tunasync.d/fedora-exclude.txt")
|
||||
So(m.MemoryLimit.Value(), ShouldEqual, 128 * units.MiB)
|
||||
So(m.MemoryLimit.Value(), ShouldEqual, 128*units.MiB)
|
||||
|
||||
m = cfg.Mirrors[3]
|
||||
So(m.Name, ShouldEqual, "debian-cd")
|
||||
So(m.MirrorDir, ShouldEqual, "")
|
||||
So(m.Provider, ShouldEqual, provTwoStageRsync)
|
||||
So(m.MemoryLimit.Value(), ShouldEqual, 0)
|
||||
So(m.MemoryLimit.Value(), ShouldEqual, 0)
|
||||
|
||||
m = cfg.Mirrors[4]
|
||||
So(m.Name, ShouldEqual, "debian-security")
|
||||
@ -170,11 +170,11 @@ use_ipv6 = true
|
||||
})
|
||||
|
||||
Convey("Everything should work on nested config file", t, func() {
|
||||
tmpfile, err := ioutil.TempFile("", "tunasync")
|
||||
tmpfile, err := os.CreateTemp("", "tunasync")
|
||||
So(err, ShouldEqual, nil)
|
||||
defer os.Remove(tmpfile.Name())
|
||||
|
||||
tmpDir, err := ioutil.TempDir("", "tunasync")
|
||||
tmpDir, err := os.MkdirTemp("", "tunasync")
|
||||
So(err, ShouldBeNil)
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
@ -186,7 +186,7 @@ use_ipv6 = true
|
||||
|
||||
curCfgBlob := cfgBlob + incSection
|
||||
|
||||
err = ioutil.WriteFile(tmpfile.Name(), []byte(curCfgBlob), 0644)
|
||||
err = os.WriteFile(tmpfile.Name(), []byte(curCfgBlob), 0644)
|
||||
So(err, ShouldEqual, nil)
|
||||
defer tmpfile.Close()
|
||||
|
||||
@ -212,7 +212,7 @@ use_ipv6 = true
|
||||
provider = "rsync"
|
||||
upstream = "rsync://test.host3/debian-cd/"
|
||||
`
|
||||
err = ioutil.WriteFile(filepath.Join(tmpDir, "nest.conf"), []byte(incBlob1), 0644)
|
||||
err = os.WriteFile(filepath.Join(tmpDir, "nest.conf"), []byte(incBlob1), 0644)
|
||||
So(err, ShouldEqual, nil)
|
||||
|
||||
cfg, err := LoadConfig(tmpfile.Name())
|
||||
@ -266,11 +266,11 @@ use_ipv6 = true
|
||||
So(len(cfg.Mirrors), ShouldEqual, 6)
|
||||
})
|
||||
Convey("Providers can be inited from a valid config file", t, func() {
|
||||
tmpfile, err := ioutil.TempFile("", "tunasync")
|
||||
tmpfile, err := os.CreateTemp("", "tunasync")
|
||||
So(err, ShouldEqual, nil)
|
||||
defer os.Remove(tmpfile.Name())
|
||||
|
||||
err = ioutil.WriteFile(tmpfile.Name(), []byte(cfgBlob), 0644)
|
||||
err = os.WriteFile(tmpfile.Name(), []byte(cfgBlob), 0644)
|
||||
So(err, ShouldEqual, nil)
|
||||
defer tmpfile.Close()
|
||||
|
||||
@ -317,7 +317,7 @@ use_ipv6 = true
|
||||
})
|
||||
|
||||
Convey("MirrorSubdir should work", t, func() {
|
||||
tmpfile, err := ioutil.TempFile("", "tunasync")
|
||||
tmpfile, err := os.CreateTemp("", "tunasync")
|
||||
So(err, ShouldEqual, nil)
|
||||
defer os.Remove(tmpfile.Name())
|
||||
|
||||
@ -363,7 +363,7 @@ use_ipv6 = true
|
||||
provider = "rsync"
|
||||
upstream = "rsync://test.host3/debian-cd/"
|
||||
`
|
||||
err = ioutil.WriteFile(tmpfile.Name(), []byte(cfgBlob1), 0644)
|
||||
err = os.WriteFile(tmpfile.Name(), []byte(cfgBlob1), 0644)
|
||||
So(err, ShouldEqual, nil)
|
||||
defer tmpfile.Close()
|
||||
|
||||
@ -403,4 +403,178 @@ use_ipv6 = true
|
||||
So(rp.WorkingDir(), ShouldEqual, "/data/mirrors/debian-cd")
|
||||
So(p.Timeout(), ShouldEqual, 86400*time.Second)
|
||||
})
|
||||
|
||||
Convey("rsync_override_only should work", t, func() {
|
||||
tmpfile, err := os.CreateTemp("", "tunasync")
|
||||
So(err, ShouldEqual, nil)
|
||||
defer os.Remove(tmpfile.Name())
|
||||
|
||||
cfgBlob1 := `
|
||||
[global]
|
||||
name = "test_worker"
|
||||
log_dir = "/var/log/tunasync/{{.Name}}"
|
||||
mirror_dir = "/data/mirrors"
|
||||
concurrent = 10
|
||||
interval = 240
|
||||
retry = 3
|
||||
timeout = 86400
|
||||
|
||||
[manager]
|
||||
api_base = "https://127.0.0.1:5000"
|
||||
token = "some_token"
|
||||
|
||||
[server]
|
||||
hostname = "worker1.example.com"
|
||||
listen_addr = "127.0.0.1"
|
||||
listen_port = 6000
|
||||
ssl_cert = "/etc/tunasync.d/worker1.cert"
|
||||
ssl_key = "/etc/tunasync.d/worker1.key"
|
||||
|
||||
[[mirrors]]
|
||||
name = "foo"
|
||||
provider = "rsync"
|
||||
upstream = "rsync://foo.bar/"
|
||||
interval = 720
|
||||
retry = 2
|
||||
timeout = 3600
|
||||
mirror_dir = "/data/foo"
|
||||
rsync_override = ["--bar", "baz"]
|
||||
rsync_override_only = true
|
||||
`
|
||||
|
||||
err = os.WriteFile(tmpfile.Name(), []byte(cfgBlob1), 0644)
|
||||
So(err, ShouldEqual, nil)
|
||||
defer tmpfile.Close()
|
||||
|
||||
cfg, err := LoadConfig(tmpfile.Name())
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
providers := map[string]mirrorProvider{}
|
||||
for _, m := range cfg.Mirrors {
|
||||
p := newMirrorProvider(m, cfg)
|
||||
providers[p.Name()] = p
|
||||
}
|
||||
|
||||
p, ok := providers["foo"].(*rsyncProvider)
|
||||
So(ok, ShouldBeTrue)
|
||||
So(p.options, ShouldResemble, []string{"--bar", "baz"})
|
||||
})
|
||||
|
||||
Convey("rsync global options should work", t, func() {
|
||||
tmpfile, err := os.CreateTemp("", "tunasync")
|
||||
So(err, ShouldEqual, nil)
|
||||
defer os.Remove(tmpfile.Name())
|
||||
|
||||
cfgBlob1 := `
|
||||
[global]
|
||||
name = "test_worker"
|
||||
log_dir = "/var/log/tunasync/{{.Name}}"
|
||||
mirror_dir = "/data/mirrors"
|
||||
concurrent = 10
|
||||
interval = 240
|
||||
retry = 3
|
||||
timeout = 86400
|
||||
rsync_options = ["--global"]
|
||||
|
||||
[manager]
|
||||
api_base = "https://127.0.0.1:5000"
|
||||
token = "some_token"
|
||||
|
||||
[server]
|
||||
hostname = "worker1.example.com"
|
||||
listen_addr = "127.0.0.1"
|
||||
listen_port = 6000
|
||||
ssl_cert = "/etc/tunasync.d/worker1.cert"
|
||||
ssl_key = "/etc/tunasync.d/worker1.key"
|
||||
|
||||
[[mirrors]]
|
||||
name = "foo"
|
||||
provider = "rsync"
|
||||
upstream = "rsync://foo.bar/"
|
||||
interval = 720
|
||||
retry = 2
|
||||
timeout = 3600
|
||||
mirror_dir = "/data/foo"
|
||||
rsync_override = ["--override"]
|
||||
rsync_options = ["--local"]
|
||||
`
|
||||
|
||||
err = os.WriteFile(tmpfile.Name(), []byte(cfgBlob1), 0644)
|
||||
So(err, ShouldEqual, nil)
|
||||
defer tmpfile.Close()
|
||||
|
||||
cfg, err := LoadConfig(tmpfile.Name())
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
providers := map[string]mirrorProvider{}
|
||||
for _, m := range cfg.Mirrors {
|
||||
p := newMirrorProvider(m, cfg)
|
||||
providers[p.Name()] = p
|
||||
}
|
||||
|
||||
p, ok := providers["foo"].(*rsyncProvider)
|
||||
So(ok, ShouldBeTrue)
|
||||
So(p.options, ShouldResemble, []string{
|
||||
"--override", // from mirror.rsync_override
|
||||
"--timeout=120", // generated by newRsyncProvider
|
||||
"--global", // from global.rsync_options
|
||||
"--local", // from mirror.rsync_options
|
||||
})
|
||||
})
|
||||
|
||||
Convey("success_exit_codes should work globally and per mirror", t, func() {
|
||||
tmpfile, err := os.CreateTemp("", "tunasync")
|
||||
So(err, ShouldEqual, nil)
|
||||
defer os.Remove(tmpfile.Name())
|
||||
|
||||
cfgBlob1 := `
|
||||
[global]
|
||||
name = "test_worker"
|
||||
log_dir = "/var/log/tunasync/{{.Name}}"
|
||||
mirror_dir = "/data/mirrors"
|
||||
concurrent = 10
|
||||
interval = 240
|
||||
retry = 3
|
||||
timeout = 86400
|
||||
dangerous_global_success_exit_codes = [10, 20]
|
||||
|
||||
[manager]
|
||||
api_base = "https://127.0.0.1:5000"
|
||||
token = "some_token"
|
||||
|
||||
[server]
|
||||
hostname = "worker1.example.com"
|
||||
listen_addr = "127.0.0.1"
|
||||
listen_port = 6000
|
||||
ssl_cert = "/etc/tunasync.d/worker1.cert"
|
||||
ssl_key = "/etc/tunasync.d/worker1.key"
|
||||
|
||||
[[mirrors]]
|
||||
name = "foo"
|
||||
provider = "rsync"
|
||||
upstream = "rsync://foo.bar/"
|
||||
interval = 720
|
||||
retry = 2
|
||||
timeout = 3600
|
||||
mirror_dir = "/data/foo"
|
||||
success_exit_codes = [30, 40]
|
||||
`
|
||||
|
||||
err = os.WriteFile(tmpfile.Name(), []byte(cfgBlob1), 0644)
|
||||
So(err, ShouldEqual, nil)
|
||||
defer tmpfile.Close()
|
||||
|
||||
cfg, err := LoadConfig(tmpfile.Name())
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
providers := map[string]mirrorProvider{}
|
||||
for _, m := range cfg.Mirrors {
|
||||
p := newMirrorProvider(m, cfg)
|
||||
providers[p.Name()] = p
|
||||
}
|
||||
|
||||
p, ok := providers["foo"].(*rsyncProvider)
|
||||
So(ok, ShouldBeTrue)
|
||||
So(p.successExitCodes, ShouldResemble, []int{10, 20, 30, 40})
|
||||
})
|
||||
}
|
||||
|
@ -10,9 +10,9 @@ import (
|
||||
|
||||
type dockerHook struct {
|
||||
emptyHook
|
||||
image string
|
||||
volumes []string
|
||||
options []string
|
||||
image string
|
||||
volumes []string
|
||||
options []string
|
||||
memoryLimit MemBytes
|
||||
}
|
||||
|
||||
@ -33,9 +33,9 @@ func newDockerHook(p mirrorProvider, gCfg dockerConfig, mCfg mirrorConfig) *dock
|
||||
emptyHook: emptyHook{
|
||||
provider: p,
|
||||
},
|
||||
image: mCfg.DockerImage,
|
||||
volumes: volumes,
|
||||
options: options,
|
||||
image: mCfg.DockerImage,
|
||||
volumes: volumes,
|
||||
options: options,
|
||||
memoryLimit: mCfg.MemoryLimit,
|
||||
}
|
||||
}
|
||||
|
@ -2,12 +2,12 @@ package worker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
units "github.com/docker/go-units"
|
||||
|
||||
"github.com/codeskyblue/go-sh"
|
||||
@ -40,7 +40,7 @@ func getDockerByName(name string) (string, error) {
|
||||
|
||||
func TestDocker(t *testing.T) {
|
||||
Convey("Docker Should Work", t, func(ctx C) {
|
||||
tmpDir, err := ioutil.TempDir("", "tunasync")
|
||||
tmpDir, err := os.MkdirTemp("", "tunasync")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
So(err, ShouldBeNil)
|
||||
cmdScript := filepath.Join(tmpDir, "cmd.sh")
|
||||
@ -64,7 +64,7 @@ func TestDocker(t *testing.T) {
|
||||
echo ${TEST_CONTENT}
|
||||
sleep 20
|
||||
`
|
||||
err = ioutil.WriteFile(cmdScript, []byte(cmdScriptContent), 0755)
|
||||
err = os.WriteFile(cmdScript, []byte(cmdScriptContent), 0755)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
provider, err := newCmdProvider(c)
|
||||
@ -125,7 +125,7 @@ sleep 20
|
||||
So(names, ShouldEqual, "")
|
||||
|
||||
// check log content
|
||||
loggedContent, err := ioutil.ReadFile(provider.LogFile())
|
||||
loggedContent, err := os.ReadFile(provider.LogFile())
|
||||
So(err, ShouldBeNil)
|
||||
So(string(loggedContent), ShouldEqual, expectedOutput+"\n")
|
||||
|
||||
|
@ -1,7 +1,6 @@
|
||||
package worker
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
@ -13,7 +12,7 @@ import (
|
||||
|
||||
func TestExecPost(t *testing.T) {
|
||||
Convey("ExecPost should work", t, func(ctx C) {
|
||||
tmpDir, err := ioutil.TempDir("", "tunasync")
|
||||
tmpDir, err := os.MkdirTemp("", "tunasync")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
So(err, ShouldBeNil)
|
||||
scriptFile := filepath.Join(tmpDir, "cmd.sh")
|
||||
@ -46,7 +45,7 @@ echo $TUNASYNC_UPSTREAM_URL
|
||||
echo $TUNASYNC_LOG_FILE
|
||||
`
|
||||
|
||||
err = ioutil.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
err = os.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
go job.Run(managerChan, semaphore)
|
||||
@ -64,7 +63,7 @@ echo $TUNASYNC_LOG_FILE
|
||||
|
||||
expectedOutput := "success\n"
|
||||
|
||||
outputContent, err := ioutil.ReadFile(filepath.Join(provider.WorkingDir(), "exit_status"))
|
||||
outputContent, err := os.ReadFile(filepath.Join(provider.WorkingDir(), "exit_status"))
|
||||
So(err, ShouldBeNil)
|
||||
So(string(outputContent), ShouldEqual, expectedOutput)
|
||||
})
|
||||
@ -85,7 +84,7 @@ echo $TUNASYNC_LOG_FILE
|
||||
exit 1
|
||||
`
|
||||
|
||||
err = ioutil.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
err = os.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
go job.Run(managerChan, semaphore)
|
||||
@ -105,7 +104,7 @@ exit 1
|
||||
|
||||
expectedOutput := "failure\n"
|
||||
|
||||
outputContent, err := ioutil.ReadFile(filepath.Join(provider.WorkingDir(), "exit_status"))
|
||||
outputContent, err := os.ReadFile(filepath.Join(provider.WorkingDir(), "exit_status"))
|
||||
So(err, ShouldBeNil)
|
||||
So(string(outputContent), ShouldEqual, expectedOutput)
|
||||
})
|
||||
|
@ -87,10 +87,12 @@ func (m *mirrorJob) SetProvider(provider mirrorProvider) error {
|
||||
|
||||
// runMirrorJob is the goroutine where syncing job runs in
|
||||
// arguments:
|
||||
// provider: mirror provider object
|
||||
// ctrlChan: receives messages from the manager
|
||||
// managerChan: push messages to the manager, this channel should have a larger buffer
|
||||
// sempaphore: make sure the concurrent running syncing job won't explode
|
||||
//
|
||||
// provider: mirror provider object
|
||||
// ctrlChan: receives messages from the manager
|
||||
// managerChan: push messages to the manager, this channel should have a larger buffer
|
||||
// sempaphore: make sure the concurrent running syncing job won't explode
|
||||
//
|
||||
// TODO: message struct for managerChan
|
||||
func (m *mirrorJob) Run(managerChan chan<- jobMessage, semaphore chan empty) error {
|
||||
jobsDone.Add(1)
|
||||
|
@ -2,7 +2,6 @@ package worker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
@ -17,7 +16,7 @@ func TestMirrorJob(t *testing.T) {
|
||||
InitLogger(true, true, false)
|
||||
|
||||
Convey("MirrorJob should work", t, func(ctx C) {
|
||||
tmpDir, err := ioutil.TempDir("", "tunasync")
|
||||
tmpDir, err := os.MkdirTemp("", "tunasync")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
So(err, ShouldBeNil)
|
||||
scriptFile := filepath.Join(tmpDir, "cmd.sh")
|
||||
@ -58,9 +57,9 @@ func TestMirrorJob(t *testing.T) {
|
||||
provider.upstreamURL,
|
||||
provider.LogFile(),
|
||||
)
|
||||
err = ioutil.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
err = os.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
So(err, ShouldBeNil)
|
||||
readedScriptContent, err := ioutil.ReadFile(scriptFile)
|
||||
readedScriptContent, err := os.ReadFile(scriptFile)
|
||||
So(err, ShouldBeNil)
|
||||
So(readedScriptContent, ShouldResemble, []byte(scriptContent))
|
||||
|
||||
@ -86,7 +85,7 @@ func TestMirrorJob(t *testing.T) {
|
||||
So(msg.status, ShouldEqual, Syncing)
|
||||
msg = <-managerChan
|
||||
So(msg.status, ShouldEqual, Success)
|
||||
loggedContent, err := ioutil.ReadFile(provider.LogFile())
|
||||
loggedContent, err := os.ReadFile(provider.LogFile())
|
||||
So(err, ShouldBeNil)
|
||||
So(string(loggedContent), ShouldEqual, expectedOutput)
|
||||
job.ctrlChan <- jobStart
|
||||
@ -123,11 +122,11 @@ sleep 3
|
||||
echo $TUNASYNC_WORKING_DIR
|
||||
echo '------'
|
||||
`
|
||||
err = ioutil.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
err = os.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
hookScriptFile := filepath.Join(tmpDir, "hook.sh")
|
||||
err = ioutil.WriteFile(hookScriptFile, []byte(scriptContent), 0755)
|
||||
err = os.WriteFile(hookScriptFile, []byte(scriptContent), 0755)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
h, err := newExecPostHook(provider, execOnFailure, hookScriptFile)
|
||||
@ -188,7 +187,7 @@ echo $TUNASYNC_WORKING_DIR
|
||||
sleep 5
|
||||
echo $TUNASYNC_WORKING_DIR
|
||||
`
|
||||
err = ioutil.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
err = os.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
managerChan := make(chan jobMessage, 10)
|
||||
@ -213,7 +212,7 @@ echo $TUNASYNC_WORKING_DIR
|
||||
So(msg.status, ShouldEqual, Failed)
|
||||
|
||||
expectedOutput := fmt.Sprintf("%s\n", provider.WorkingDir())
|
||||
loggedContent, err := ioutil.ReadFile(provider.LogFile())
|
||||
loggedContent, err := os.ReadFile(provider.LogFile())
|
||||
So(err, ShouldBeNil)
|
||||
So(string(loggedContent), ShouldEqual, expectedOutput)
|
||||
job.ctrlChan <- jobDisable
|
||||
@ -236,7 +235,7 @@ echo $TUNASYNC_WORKING_DIR
|
||||
provider.WorkingDir(), provider.WorkingDir(),
|
||||
)
|
||||
|
||||
loggedContent, err := ioutil.ReadFile(provider.LogFile())
|
||||
loggedContent, err := os.ReadFile(provider.LogFile())
|
||||
So(err, ShouldBeNil)
|
||||
So(string(loggedContent), ShouldEqual, expectedOutput)
|
||||
job.ctrlChan <- jobDisable
|
||||
@ -270,7 +269,7 @@ echo $TUNASYNC_WORKING_DIR
|
||||
provider.WorkingDir(), provider.WorkingDir(),
|
||||
)
|
||||
|
||||
loggedContent, err := ioutil.ReadFile(provider.LogFile())
|
||||
loggedContent, err := os.ReadFile(provider.LogFile())
|
||||
So(err, ShouldBeNil)
|
||||
So(string(loggedContent), ShouldEqual, expectedOutput)
|
||||
job.ctrlChan <- jobDisable
|
||||
@ -326,7 +325,7 @@ echo $TUNASYNC_WORKING_DIR
|
||||
provider.WorkingDir(), provider.WorkingDir(),
|
||||
)
|
||||
|
||||
loggedContent, err := ioutil.ReadFile(provider.LogFile())
|
||||
loggedContent, err := os.ReadFile(provider.LogFile())
|
||||
So(err, ShouldBeNil)
|
||||
So(string(loggedContent), ShouldEqual, expectedOutput)
|
||||
|
||||
@ -341,7 +340,7 @@ echo $TUNASYNC_WORKING_DIR
|
||||
sleep 10
|
||||
echo $TUNASYNC_WORKING_DIR
|
||||
`
|
||||
err = ioutil.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
err = os.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
managerChan := make(chan jobMessage, 10)
|
||||
@ -364,7 +363,7 @@ echo $TUNASYNC_WORKING_DIR
|
||||
So(msg.status, ShouldEqual, Failed)
|
||||
|
||||
expectedOutput := fmt.Sprintf("%s\n", provider.WorkingDir())
|
||||
loggedContent, err := ioutil.ReadFile(provider.LogFile())
|
||||
loggedContent, err := os.ReadFile(provider.LogFile())
|
||||
So(err, ShouldBeNil)
|
||||
So(string(loggedContent), ShouldEqual, expectedOutput)
|
||||
job.ctrlChan <- jobDisable
|
||||
@ -404,7 +403,7 @@ func TestConcurrentMirrorJobs(t *testing.T) {
|
||||
InitLogger(true, true, false)
|
||||
|
||||
Convey("Concurrent MirrorJobs should work", t, func(ctx C) {
|
||||
tmpDir, err := ioutil.TempDir("", "tunasync")
|
||||
tmpDir, err := os.MkdirTemp("", "tunasync")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
|
@ -2,7 +2,6 @@ package worker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
@ -39,7 +38,7 @@ func (l *logLimiter) preExec() error {
|
||||
}
|
||||
|
||||
logDir := p.LogDir()
|
||||
files, err := ioutil.ReadDir(logDir)
|
||||
files, err := os.ReadDir(logDir)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
os.MkdirAll(logDir, 0755)
|
||||
@ -50,7 +49,8 @@ func (l *logLimiter) preExec() error {
|
||||
matchedFiles := []os.FileInfo{}
|
||||
for _, f := range files {
|
||||
if strings.HasPrefix(f.Name(), p.Name()) {
|
||||
matchedFiles = append(matchedFiles, f)
|
||||
info, _ := f.Info()
|
||||
matchedFiles = append(matchedFiles, info)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,6 @@ package worker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
@ -14,8 +13,8 @@ import (
|
||||
|
||||
func TestLogLimiter(t *testing.T) {
|
||||
Convey("LogLimiter should work", t, func(ctx C) {
|
||||
tmpDir, err := ioutil.TempDir("", "tunasync")
|
||||
tmpLogDir, err := ioutil.TempDir("", "tunasync-log")
|
||||
tmpDir, _ := os.MkdirTemp("", "tunasync")
|
||||
tmpLogDir, err := os.MkdirTemp("", "tunasync-log")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
defer os.RemoveAll(tmpLogDir)
|
||||
So(err, ShouldBeNil)
|
||||
@ -58,7 +57,7 @@ echo $TUNASYNC_UPSTREAM_URL
|
||||
echo $TUNASYNC_LOG_FILE
|
||||
`
|
||||
|
||||
err = ioutil.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
err = os.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
go job.Run(managerChan, semaphore)
|
||||
@ -86,7 +85,7 @@ echo $TUNASYNC_LOG_FILE
|
||||
logFile,
|
||||
)
|
||||
|
||||
loggedContent, err := ioutil.ReadFile(filepath.Join(provider.LogDir(), "latest"))
|
||||
loggedContent, err := os.ReadFile(filepath.Join(provider.LogDir(), "latest"))
|
||||
So(err, ShouldBeNil)
|
||||
So(string(loggedContent), ShouldEqual, expectedOutput)
|
||||
})
|
||||
@ -104,7 +103,7 @@ echo $TUNASYNC_LOG_FILE
|
||||
sleep 5
|
||||
`
|
||||
|
||||
err = ioutil.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
err = os.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
go job.Run(managerChan, semaphore)
|
||||
@ -134,10 +133,10 @@ sleep 5
|
||||
logFile,
|
||||
)
|
||||
|
||||
loggedContent, err := ioutil.ReadFile(filepath.Join(provider.LogDir(), "latest"))
|
||||
loggedContent, err := os.ReadFile(filepath.Join(provider.LogDir(), "latest"))
|
||||
So(err, ShouldBeNil)
|
||||
So(string(loggedContent), ShouldEqual, expectedOutput)
|
||||
loggedContent, err = ioutil.ReadFile(logFile + ".fail")
|
||||
loggedContent, err = os.ReadFile(logFile + ".fail")
|
||||
So(err, ShouldBeNil)
|
||||
So(string(loggedContent), ShouldEqual, expectedOutput)
|
||||
})
|
||||
|
@ -60,6 +60,10 @@ type mirrorProvider interface {
|
||||
ExitContext() *Context
|
||||
// return context
|
||||
Context() *Context
|
||||
|
||||
// set in newMirrorProvider, used by cmdJob.Wait
|
||||
SetSuccessExitCodes(codes []int)
|
||||
GetSuccessExitCodes() []int
|
||||
}
|
||||
|
||||
// newProvider creates a mirrorProvider instance
|
||||
@ -142,7 +146,9 @@ func newMirrorProvider(mirror mirrorConfig, cfg *Config) mirrorProvider {
|
||||
extraOptions: mirror.RsyncOptions,
|
||||
rsyncNeverTimeout: mirror.RsyncNoTimeo,
|
||||
rsyncTimeoutValue: mirror.RsyncTimeout,
|
||||
globalOptions: cfg.Global.RsyncOptions,
|
||||
overriddenOptions: mirror.RsyncOverride,
|
||||
useOverrideOnly: mirror.RsyncOverrideOnly,
|
||||
rsyncEnv: mirror.Env,
|
||||
workingDir: mirrorDir,
|
||||
logDir: logDir,
|
||||
@ -247,5 +253,17 @@ func newMirrorProvider(mirror mirrorConfig, cfg *Config) mirrorProvider {
|
||||
}
|
||||
addHookFromCmdList(mirror.ExecOnFailureExtra, execOnFailure)
|
||||
|
||||
successExitCodes := []int{}
|
||||
if cfg.Global.SuccessExitCodes != nil {
|
||||
successExitCodes = append(successExitCodes, cfg.Global.SuccessExitCodes...)
|
||||
}
|
||||
if mirror.SuccessExitCodes != nil {
|
||||
successExitCodes = append(successExitCodes, mirror.SuccessExitCodes...)
|
||||
}
|
||||
if len(successExitCodes) > 0 {
|
||||
logger.Infof("Non-zero success exit codes set for mirror %s: %v", mirror.Name, successExitCodes)
|
||||
provider.SetSuccessExitCodes(successExitCodes)
|
||||
}
|
||||
|
||||
return provider
|
||||
}
|
||||
|
@ -2,7 +2,6 @@ package worker
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
@ -14,7 +13,7 @@ import (
|
||||
|
||||
func TestRsyncProvider(t *testing.T) {
|
||||
Convey("Rsync Provider should work", t, func() {
|
||||
tmpDir, err := ioutil.TempDir("", "tunasync")
|
||||
tmpDir, err := os.MkdirTemp("", "tunasync")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
So(err, ShouldBeNil)
|
||||
scriptFile := filepath.Join(tmpDir, "myrsync")
|
||||
@ -80,7 +79,7 @@ echo "Total file size: 1.33T bytes"
|
||||
echo "Done"
|
||||
exit 0
|
||||
`
|
||||
err = ioutil.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
err = os.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
targetDir, _ := filepath.EvalSymlinks(provider.WorkingDir())
|
||||
@ -100,7 +99,7 @@ exit 0
|
||||
|
||||
err = provider.Run(make(chan empty, 1))
|
||||
So(err, ShouldBeNil)
|
||||
loggedContent, err := ioutil.ReadFile(provider.LogFile())
|
||||
loggedContent, err := os.ReadFile(provider.LogFile())
|
||||
So(err, ShouldBeNil)
|
||||
So(string(loggedContent), ShouldEqual, expectedOutput)
|
||||
// fmt.Println(string(loggedContent))
|
||||
@ -109,7 +108,7 @@ exit 0
|
||||
|
||||
})
|
||||
Convey("If the rsync program fails", t, func() {
|
||||
tmpDir, err := ioutil.TempDir("", "tunasync")
|
||||
tmpDir, err := os.MkdirTemp("", "tunasync")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
So(err, ShouldBeNil)
|
||||
tmpFile := filepath.Join(tmpDir, "log_file")
|
||||
@ -131,7 +130,7 @@ exit 0
|
||||
|
||||
err = provider.Run(make(chan empty, 1))
|
||||
So(err, ShouldNotBeNil)
|
||||
loggedContent, err := ioutil.ReadFile(provider.LogFile())
|
||||
loggedContent, err := os.ReadFile(provider.LogFile())
|
||||
So(err, ShouldBeNil)
|
||||
So(string(loggedContent), ShouldContainSubstring, "Syntax or usage error")
|
||||
})
|
||||
@ -140,7 +139,7 @@ exit 0
|
||||
|
||||
func TestRsyncProviderWithAuthentication(t *testing.T) {
|
||||
Convey("Rsync Provider with password should work", t, func() {
|
||||
tmpDir, err := ioutil.TempDir("", "tunasync")
|
||||
tmpDir, err := os.MkdirTemp("", "tunasync")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
So(err, ShouldBeNil)
|
||||
scriptFile := filepath.Join(tmpDir, "myrsync")
|
||||
@ -180,7 +179,7 @@ sleep 1
|
||||
echo "Done"
|
||||
exit 0
|
||||
`
|
||||
err = ioutil.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
err = os.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
targetDir, _ := filepath.EvalSymlinks(provider.WorkingDir())
|
||||
@ -200,7 +199,7 @@ exit 0
|
||||
|
||||
err = provider.Run(make(chan empty, 1))
|
||||
So(err, ShouldBeNil)
|
||||
loggedContent, err := ioutil.ReadFile(provider.LogFile())
|
||||
loggedContent, err := os.ReadFile(provider.LogFile())
|
||||
So(err, ShouldBeNil)
|
||||
So(string(loggedContent), ShouldEqual, expectedOutput)
|
||||
// fmt.Println(string(loggedContent))
|
||||
@ -211,7 +210,7 @@ exit 0
|
||||
|
||||
func TestRsyncProviderWithOverriddenOptions(t *testing.T) {
|
||||
Convey("Rsync Provider with overridden options should work", t, func() {
|
||||
tmpDir, err := ioutil.TempDir("", "tunasync")
|
||||
tmpDir, err := os.MkdirTemp("", "tunasync")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
So(err, ShouldBeNil)
|
||||
scriptFile := filepath.Join(tmpDir, "myrsync")
|
||||
@ -248,7 +247,7 @@ sleep 1
|
||||
echo "Done"
|
||||
exit 0
|
||||
`
|
||||
err = ioutil.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
err = os.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
targetDir, _ := filepath.EvalSymlinks(provider.WorkingDir())
|
||||
@ -263,7 +262,7 @@ exit 0
|
||||
|
||||
err = provider.Run(make(chan empty, 1))
|
||||
So(err, ShouldBeNil)
|
||||
loggedContent, err := ioutil.ReadFile(provider.LogFile())
|
||||
loggedContent, err := os.ReadFile(provider.LogFile())
|
||||
So(err, ShouldBeNil)
|
||||
So(string(loggedContent), ShouldEqual, expectedOutput)
|
||||
// fmt.Println(string(loggedContent))
|
||||
@ -274,7 +273,7 @@ exit 0
|
||||
|
||||
func TestRsyncProviderWithDocker(t *testing.T) {
|
||||
Convey("Rsync in Docker should work", t, func() {
|
||||
tmpDir, err := ioutil.TempDir("", "tunasync")
|
||||
tmpDir, err := os.MkdirTemp("", "tunasync")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
So(err, ShouldBeNil)
|
||||
scriptFile := filepath.Join(tmpDir, "myrsync")
|
||||
@ -323,9 +322,9 @@ fi
|
||||
shift
|
||||
done
|
||||
`
|
||||
err = ioutil.WriteFile(scriptFile, []byte(cmdScriptContent), 0755)
|
||||
err = os.WriteFile(scriptFile, []byte(cmdScriptContent), 0755)
|
||||
So(err, ShouldBeNil)
|
||||
err = ioutil.WriteFile(excludeFile, []byte("__some_pattern"), 0755)
|
||||
err = os.WriteFile(excludeFile, []byte("__some_pattern"), 0755)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
for _, hook := range provider.Hooks() {
|
||||
@ -338,7 +337,7 @@ done
|
||||
err = hook.postExec()
|
||||
So(err, ShouldBeNil)
|
||||
}
|
||||
loggedContent, err := ioutil.ReadFile(provider.LogFile())
|
||||
loggedContent, err := os.ReadFile(provider.LogFile())
|
||||
So(err, ShouldBeNil)
|
||||
So(string(loggedContent), ShouldEqual, "__some_pattern")
|
||||
})
|
||||
@ -346,7 +345,7 @@ done
|
||||
|
||||
func TestCmdProvider(t *testing.T) {
|
||||
Convey("Command Provider should work", t, func(ctx C) {
|
||||
tmpDir, err := ioutil.TempDir("", "tunasync")
|
||||
tmpDir, err := os.MkdirTemp("", "tunasync")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
So(err, ShouldBeNil)
|
||||
scriptFile := filepath.Join(tmpDir, "cmd.sh")
|
||||
@ -391,25 +390,25 @@ echo $AOSP_REPO_BIN
|
||||
provider.LogFile(),
|
||||
"/usr/local/bin/repo",
|
||||
)
|
||||
err = ioutil.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
err = os.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
So(err, ShouldBeNil)
|
||||
readedScriptContent, err := ioutil.ReadFile(scriptFile)
|
||||
readedScriptContent, err := os.ReadFile(scriptFile)
|
||||
So(err, ShouldBeNil)
|
||||
So(readedScriptContent, ShouldResemble, []byte(scriptContent))
|
||||
|
||||
err = provider.Run(make(chan empty, 1))
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
loggedContent, err := ioutil.ReadFile(provider.LogFile())
|
||||
loggedContent, err := os.ReadFile(provider.LogFile())
|
||||
So(err, ShouldBeNil)
|
||||
So(string(loggedContent), ShouldEqual, expectedOutput)
|
||||
})
|
||||
|
||||
Convey("If a command fails", func() {
|
||||
scriptContent := `exit 1`
|
||||
err = ioutil.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
err = os.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
So(err, ShouldBeNil)
|
||||
readedScriptContent, err := ioutil.ReadFile(scriptFile)
|
||||
readedScriptContent, err := os.ReadFile(scriptFile)
|
||||
So(err, ShouldBeNil)
|
||||
So(readedScriptContent, ShouldResemble, []byte(scriptContent))
|
||||
|
||||
@ -422,7 +421,7 @@ echo $AOSP_REPO_BIN
|
||||
scriptContent := `#!/bin/bash
|
||||
sleep 10
|
||||
`
|
||||
err = ioutil.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
err = os.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
started := make(chan empty, 1)
|
||||
@ -440,7 +439,7 @@ sleep 10
|
||||
})
|
||||
})
|
||||
Convey("Command Provider without log file should work", t, func(ctx C) {
|
||||
tmpDir, err := ioutil.TempDir("", "tunasync")
|
||||
tmpDir, err := os.MkdirTemp("", "tunasync")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
@ -474,7 +473,7 @@ sleep 10
|
||||
})
|
||||
})
|
||||
Convey("Command Provider with RegExprs should work", t, func(ctx C) {
|
||||
tmpDir, err := ioutil.TempDir("", "tunasync")
|
||||
tmpDir, err := os.MkdirTemp("", "tunasync")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
So(err, ShouldBeNil)
|
||||
tmpFile := filepath.Join(tmpDir, "log_file")
|
||||
@ -553,11 +552,64 @@ sleep 10
|
||||
So(provider.DataSize(), ShouldBeEmpty)
|
||||
})
|
||||
})
|
||||
Convey("Command Provider with successExitCodes should work", t, func(ctx C) {
|
||||
tmpDir, err := os.MkdirTemp("", "tunasync")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
So(err, ShouldBeNil)
|
||||
scriptFile := filepath.Join(tmpDir, "cmd.sh")
|
||||
tmpFile := filepath.Join(tmpDir, "log_file")
|
||||
|
||||
c := cmdConfig{
|
||||
name: "tuna-cmd",
|
||||
upstreamURL: "http://mirrors.tuna.moe/",
|
||||
command: "bash " + scriptFile,
|
||||
workingDir: tmpDir,
|
||||
logDir: tmpDir,
|
||||
logFile: tmpFile,
|
||||
interval: 600 * time.Second,
|
||||
}
|
||||
|
||||
provider, err := newCmdProvider(c)
|
||||
provider.SetSuccessExitCodes([]int{199, 200})
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
So(provider.Type(), ShouldEqual, provCommand)
|
||||
So(provider.Name(), ShouldEqual, c.name)
|
||||
So(provider.WorkingDir(), ShouldEqual, c.workingDir)
|
||||
So(provider.LogDir(), ShouldEqual, c.logDir)
|
||||
So(provider.LogFile(), ShouldEqual, c.logFile)
|
||||
So(provider.Interval(), ShouldEqual, c.interval)
|
||||
So(provider.GetSuccessExitCodes(), ShouldResemble, []int{199, 200})
|
||||
|
||||
Convey("Command exits with configured successExitCodes", func() {
|
||||
scriptContent := `exit 199`
|
||||
err = os.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
So(err, ShouldBeNil)
|
||||
readedScriptContent, err := os.ReadFile(scriptFile)
|
||||
So(err, ShouldBeNil)
|
||||
So(readedScriptContent, ShouldResemble, []byte(scriptContent))
|
||||
|
||||
err = provider.Run(make(chan empty, 1))
|
||||
So(err, ShouldBeNil)
|
||||
})
|
||||
|
||||
Convey("Command exits with unknown exit code", func() {
|
||||
scriptContent := `exit 201`
|
||||
err = os.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
So(err, ShouldBeNil)
|
||||
readedScriptContent, err := os.ReadFile(scriptFile)
|
||||
So(err, ShouldBeNil)
|
||||
So(readedScriptContent, ShouldResemble, []byte(scriptContent))
|
||||
|
||||
err = provider.Run(make(chan empty, 1))
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
func TestTwoStageRsyncProvider(t *testing.T) {
|
||||
Convey("TwoStageRsync Provider should work", t, func(ctx C) {
|
||||
tmpDir, err := ioutil.TempDir("", "tunasync")
|
||||
tmpDir, err := os.MkdirTemp("", "tunasync")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
So(err, ShouldBeNil)
|
||||
scriptFile := filepath.Join(tmpDir, "myrsync")
|
||||
@ -597,7 +649,7 @@ sleep 1
|
||||
echo "Done"
|
||||
exit 0
|
||||
`
|
||||
err = ioutil.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
err = os.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
err = provider.Run(make(chan empty, 2))
|
||||
@ -614,7 +666,7 @@ exit 0
|
||||
targetDir,
|
||||
fmt.Sprintf(
|
||||
"-aHvh --no-o --no-g --stats --filter risk .~tmp~/ --exclude .~tmp~/ --safe-links "+
|
||||
"--include=*.diff/ --exclude=*.diff/Index --exclude=Packages* --exclude=Sources* --exclude=Release* --exclude=InRelease --include=i18n/by-hash --exclude=i18n/* --exclude=ls-lR* --timeout=30 -6 "+
|
||||
"--include=*.diff/ --include=by-hash/ --exclude=*.diff/Index --exclude=Contents* --exclude=Packages* --exclude=Sources* --exclude=Release* --exclude=InRelease --exclude=i18n/* --exclude=dep11/* --exclude=installer-*/current --exclude=ls-lR* --timeout=30 -6 "+
|
||||
"--exclude-from %s %s %s",
|
||||
provider.excludeFile, provider.upstreamURL, provider.WorkingDir(),
|
||||
),
|
||||
@ -627,7 +679,7 @@ exit 0
|
||||
),
|
||||
)
|
||||
|
||||
loggedContent, err := ioutil.ReadFile(provider.LogFile())
|
||||
loggedContent, err := os.ReadFile(provider.LogFile())
|
||||
So(err, ShouldBeNil)
|
||||
So(string(loggedContent), ShouldEqual, expectedOutput)
|
||||
// fmt.Println(string(loggedContent))
|
||||
@ -639,7 +691,7 @@ echo $@
|
||||
sleep 10
|
||||
exit 0
|
||||
`
|
||||
err = ioutil.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
err = os.WriteFile(scriptFile, []byte(scriptContent), 0755)
|
||||
So(err, ShouldBeNil)
|
||||
|
||||
started := make(chan empty, 2)
|
||||
@ -656,12 +708,12 @@ exit 0
|
||||
|
||||
expectedOutput := fmt.Sprintf(
|
||||
"-aHvh --no-o --no-g --stats --filter risk .~tmp~/ --exclude .~tmp~/ --safe-links "+
|
||||
"--include=*.diff/ --exclude=*.diff/Index --exclude=Packages* --exclude=Sources* --exclude=Release* --exclude=InRelease --include=i18n/by-hash --exclude=i18n/* --exclude=ls-lR* --timeout=30 -6 "+
|
||||
"--include=*.diff/ --include=by-hash/ --exclude=*.diff/Index --exclude=Contents* --exclude=Packages* --exclude=Sources* --exclude=Release* --exclude=InRelease --exclude=i18n/* --exclude=dep11/* --exclude=installer-*/current --exclude=ls-lR* --timeout=30 -6 "+
|
||||
"--exclude-from %s %s %s\n",
|
||||
provider.excludeFile, provider.upstreamURL, provider.WorkingDir(),
|
||||
)
|
||||
|
||||
loggedContent, err := ioutil.ReadFile(provider.LogFile())
|
||||
loggedContent, err := os.ReadFile(provider.LogFile())
|
||||
So(err, ShouldBeNil)
|
||||
So(string(loggedContent), ShouldStartWith, expectedOutput)
|
||||
// fmt.Println(string(loggedContent))
|
||||
@ -669,7 +721,7 @@ exit 0
|
||||
})
|
||||
|
||||
Convey("If the rsync program fails", t, func(ctx C) {
|
||||
tmpDir, err := ioutil.TempDir("", "tunasync")
|
||||
tmpDir, err := os.MkdirTemp("", "tunasync")
|
||||
defer os.RemoveAll(tmpDir)
|
||||
So(err, ShouldBeNil)
|
||||
tmpFile := filepath.Join(tmpDir, "log_file")
|
||||
@ -691,7 +743,7 @@ exit 0
|
||||
|
||||
err = provider.Run(make(chan empty, 2))
|
||||
So(err, ShouldNotBeNil)
|
||||
loggedContent, err := ioutil.ReadFile(provider.LogFile())
|
||||
loggedContent, err := os.ReadFile(provider.LogFile())
|
||||
So(err, ShouldBeNil)
|
||||
So(string(loggedContent), ShouldContainSubstring, "Error in socket I/O")
|
||||
|
||||
|
@ -14,7 +14,9 @@ type rsyncConfig struct {
|
||||
rsyncCmd string
|
||||
upstreamURL, username, password, excludeFile string
|
||||
extraOptions []string
|
||||
globalOptions []string
|
||||
overriddenOptions []string
|
||||
useOverrideOnly bool
|
||||
rsyncNeverTimeout bool
|
||||
rsyncTimeoutValue int
|
||||
rsyncEnv map[string]string
|
||||
@ -67,7 +69,7 @@ func newRsyncProvider(c rsyncConfig) (*rsyncProvider, error) {
|
||||
|
||||
options := []string{
|
||||
"-aHvh", "--no-o", "--no-g", "--stats",
|
||||
"--filter" , "risk .~tmp~/", "--exclude", ".~tmp~/",
|
||||
"--filter", "risk .~tmp~/", "--exclude", ".~tmp~/",
|
||||
"--delete", "--delete-after", "--delay-updates",
|
||||
"--safe-links",
|
||||
}
|
||||
@ -75,25 +77,36 @@ func newRsyncProvider(c rsyncConfig) (*rsyncProvider, error) {
|
||||
options = c.overriddenOptions
|
||||
}
|
||||
|
||||
if !c.rsyncNeverTimeout {
|
||||
timeo := 120
|
||||
if c.rsyncTimeoutValue > 0 {
|
||||
timeo = c.rsyncTimeoutValue
|
||||
if c.useOverrideOnly {
|
||||
if c.overriddenOptions == nil {
|
||||
return nil, errors.New("rsync_override_only is set but no rsync_override provided")
|
||||
}
|
||||
// use overridden options only
|
||||
} else {
|
||||
if !c.rsyncNeverTimeout {
|
||||
timeo := 120
|
||||
if c.rsyncTimeoutValue > 0 {
|
||||
timeo = c.rsyncTimeoutValue
|
||||
}
|
||||
options = append(options, fmt.Sprintf("--timeout=%d", timeo))
|
||||
}
|
||||
options = append(options, fmt.Sprintf("--timeout=%d", timeo))
|
||||
}
|
||||
|
||||
if c.useIPv6 {
|
||||
options = append(options, "-6")
|
||||
} else if c.useIPv4 {
|
||||
options = append(options, "-4")
|
||||
}
|
||||
if c.useIPv6 {
|
||||
options = append(options, "-6")
|
||||
} else if c.useIPv4 {
|
||||
options = append(options, "-4")
|
||||
}
|
||||
|
||||
if c.excludeFile != "" {
|
||||
options = append(options, "--exclude-from", c.excludeFile)
|
||||
}
|
||||
if c.extraOptions != nil {
|
||||
options = append(options, c.extraOptions...)
|
||||
if c.excludeFile != "" {
|
||||
options = append(options, "--exclude-from", c.excludeFile)
|
||||
}
|
||||
|
||||
if c.globalOptions != nil {
|
||||
options = append(options, c.globalOptions...)
|
||||
}
|
||||
if c.extraOptions != nil {
|
||||
options = append(options, c.extraOptions...)
|
||||
}
|
||||
}
|
||||
provider.options = options
|
||||
|
||||
|
@ -5,15 +5,16 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"slices"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/codeskyblue/go-sh"
|
||||
cgv1 "github.com/containerd/cgroups/v3/cgroup1"
|
||||
"github.com/moby/sys/reexec"
|
||||
"golang.org/x/sys/unix"
|
||||
"github.com/moby/moby/pkg/reexec"
|
||||
cgv1 "github.com/containerd/cgroups"
|
||||
)
|
||||
|
||||
// runner is to run os commands giving command line, env and log file
|
||||
@ -60,7 +61,7 @@ func newCmdJob(provider mirrorProvider, cmdAndArgs []string, workingDir string,
|
||||
}
|
||||
// set memlimit
|
||||
if d.memoryLimit != 0 {
|
||||
args = append(args, "-m", fmt.Sprint(d.memoryLimit.Value()))
|
||||
args = append(args, "-m", fmt.Sprint(d.memoryLimit.Value()))
|
||||
}
|
||||
// apply options
|
||||
args = append(args, d.options...)
|
||||
@ -115,7 +116,7 @@ func (c *cmdJob) Start() error {
|
||||
if cg != nil {
|
||||
logger.Debugf("Preparing cgroup sync pipes for job %s", c.provider.Name())
|
||||
var err error
|
||||
pipeR, pipeW, err = os.Pipe();
|
||||
pipeR, pipeW, err = os.Pipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -139,7 +140,7 @@ func (c *cmdJob) Start() error {
|
||||
}
|
||||
pid := c.cmd.Process.Pid
|
||||
if cg.cgCfg.isUnified {
|
||||
if err := cg.cgMgrV2.AddProc(uint64(pid)); err != nil{
|
||||
if err := cg.cgMgrV2.AddProc(uint64(pid)); err != nil {
|
||||
if errors.Is(err, syscall.ESRCH) {
|
||||
logger.Infof("Write pid %d to cgroup failed: process vanished, ignoring")
|
||||
} else {
|
||||
@ -147,7 +148,7 @@ func (c *cmdJob) Start() error {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if err := cg.cgMgrV1.Add(cgv1.Process{Pid: pid}); err != nil{
|
||||
if err := cg.cgMgrV1.Add(cgv1.Process{Pid: pid}); err != nil {
|
||||
if errors.Is(err, syscall.ESRCH) {
|
||||
logger.Infof("Write pid %d to cgroup failed: process vanished, ignoring")
|
||||
} else {
|
||||
@ -171,9 +172,18 @@ func (c *cmdJob) Wait() error {
|
||||
return c.retErr
|
||||
default:
|
||||
err := c.cmd.Wait()
|
||||
c.retErr = err
|
||||
close(c.finished)
|
||||
return err
|
||||
if err != nil {
|
||||
code := err.(*exec.ExitError).ExitCode()
|
||||
allowedCodes := c.provider.GetSuccessExitCodes()
|
||||
if slices.Contains(allowedCodes, code) {
|
||||
// process exited with non-success status
|
||||
logger.Infof("Command %s exited with code %d: treated as success (allowed: %v)", c.cmd.Args, code, allowedCodes)
|
||||
} else {
|
||||
c.retErr = err
|
||||
}
|
||||
}
|
||||
return c.retErr
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,20 @@ type twoStageRsyncProvider struct {
|
||||
|
||||
// ref: https://salsa.debian.org/mirror-team/archvsync/-/blob/master/bin/ftpsync#L431
|
||||
var rsyncStage1Profiles = map[string]([]string){
|
||||
"debian": []string{"--include=*.diff/", "--exclude=*.diff/Index", "--exclude=Packages*", "--exclude=Sources*", "--exclude=Release*", "--exclude=InRelease", "--include=i18n/by-hash", "--exclude=i18n/*", "--exclude=ls-lR*"},
|
||||
"debian": []string{
|
||||
"--include=*.diff/",
|
||||
"--include=by-hash/",
|
||||
"--exclude=*.diff/Index",
|
||||
"--exclude=Contents*",
|
||||
"--exclude=Packages*",
|
||||
"--exclude=Sources*",
|
||||
"--exclude=Release*",
|
||||
"--exclude=InRelease",
|
||||
"--exclude=i18n/*",
|
||||
"--exclude=dep11/*",
|
||||
"--exclude=installer-*/current",
|
||||
"--exclude=ls-lR*",
|
||||
},
|
||||
"debian-oldstyle": []string{
|
||||
"--exclude=Packages*", "--exclude=Sources*", "--exclude=Release*",
|
||||
"--exclude=InRelease", "--exclude=i18n/*", "--exclude=ls-lR*", "--exclude=dep11/*",
|
||||
@ -114,9 +127,7 @@ func (p *twoStageRsyncProvider) Options(stage int) ([]string, error) {
|
||||
if !ok {
|
||||
return nil, errors.New("Invalid Stage 1 Profile")
|
||||
}
|
||||
for _, exc := range stage1Profile {
|
||||
options = append(options, exc)
|
||||
}
|
||||
options = append(options, stage1Profile...)
|
||||
|
||||
} else if stage == 2 {
|
||||
options = append(options, p.stage2Options...)
|
||||
|
@ -317,7 +317,7 @@ func (w *Worker) runSchedule() {
|
||||
schedInfo := w.schedule.GetJobs()
|
||||
w.updateSchedInfo(schedInfo)
|
||||
|
||||
tick := time.Tick(5 * time.Second)
|
||||
tick := time.NewTicker(5 * time.Second).C
|
||||
for {
|
||||
select {
|
||||
case jobMsg := <-w.managerChan:
|
||||
|
@ -147,7 +147,7 @@ func TestWorker(t *testing.T) {
|
||||
})
|
||||
Convey("with one job", func(ctx C) {
|
||||
workerCfg.Mirrors = []mirrorConfig{
|
||||
mirrorConfig{
|
||||
{
|
||||
Name: "job-ls",
|
||||
Provider: provCommand,
|
||||
Command: "ls",
|
||||
@ -194,17 +194,17 @@ func TestWorker(t *testing.T) {
|
||||
})
|
||||
Convey("with several jobs", func(ctx C) {
|
||||
workerCfg.Mirrors = []mirrorConfig{
|
||||
mirrorConfig{
|
||||
{
|
||||
Name: "job-ls-1",
|
||||
Provider: provCommand,
|
||||
Command: "ls",
|
||||
},
|
||||
mirrorConfig{
|
||||
{
|
||||
Name: "job-fail",
|
||||
Provider: provCommand,
|
||||
Command: "non-existent-command-xxxx",
|
||||
},
|
||||
mirrorConfig{
|
||||
{
|
||||
Name: "job-ls-2",
|
||||
Provider: provCommand,
|
||||
Command: "ls",
|
||||
|
@ -1,7 +1,6 @@
|
||||
package worker
|
||||
|
||||
import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
@ -13,7 +12,7 @@ import (
|
||||
func TestZFSHook(t *testing.T) {
|
||||
|
||||
Convey("ZFS Hook should work", t, func(ctx C) {
|
||||
tmpDir, err := ioutil.TempDir("", "tunasync")
|
||||
tmpDir, _ := os.MkdirTemp("", "tunasync")
|
||||
tmpFile := filepath.Join(tmpDir, "log_file")
|
||||
|
||||
c := cmdConfig{
|
||||
@ -45,4 +44,4 @@ func TestZFSHook(t *testing.T) {
|
||||
So(err, ShouldNotBeNil)
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user