Compare commits

...

22 Commits

Author SHA1 Message Date
86ddb6a4c1 feat(packaging): compress rotated log files on alpine linux
All checks were successful
arcad/emissary/pipeline/head This commit looks good
2023-11-30 19:53:22 +01:00
a6da1be3bf chore: fix goreleaser task
All checks were successful
arcad/emissary/pipeline/head This commit looks good
2023-11-30 19:47:00 +01:00
5c2d128e8c feat: update arcad/edge dependency
Some checks failed
arcad/emissary/pipeline/head There was a failure building this commit
2023-11-30 19:14:37 +01:00
144fdd8bf3 chore: update app spec sample
Some checks reported errors
arcad/emissary/pipeline/head Something is wrong with the build of this commit
2023-11-30 19:13:22 +01:00
8b33bacbd5 chore: improve update-edge-lib task 2023-11-30 19:13:05 +01:00
b842dd5263 feat: update edge library
Some checks failed
arcad/emissary/pipeline/head There was a failure building this commit
2023-11-30 16:01:35 +01:00
0c9d86b850 feat: add docker recipe + environment with default interpolation in config
Some checks failed
arcad/emissary/pipeline/head There was a failure building this commit
2023-10-30 20:05:00 +01:00
b2b839cab4 feat: update arcad/edge dependency
All checks were successful
arcad/emissary/pipeline/head This commit looks good
2023-10-25 21:28:19 +02:00
7fa3011ab2 feat(app-controller): import cache driver
All checks were successful
arcad/emissary/pipeline/head This commit looks good
2023-10-24 22:55:12 +02:00
17e06ce19b feat: update arcad/edge dependency
Some checks reported errors
arcad/emissary/pipeline/head Something is wrong with the build of this commit
2023-10-24 22:53:39 +02:00
0d2aac41a8 feat: update arcad/edge dependency
All checks were successful
arcad/emissary/pipeline/head This commit looks good
2023-10-22 23:18:22 +02:00
38795a9767 feat: update arcad/edge dependency
All checks were successful
arcad/emissary/pipeline/head This commit looks good
2023-10-22 23:05:35 +02:00
327226aa74 feat: update arcad/edge dependency
All checks were successful
arcad/emissary/pipeline/head This commit looks good
2023-10-22 10:48:56 +02:00
fbf818e423 feat(storage): retry transaction when sqlite database is busy
All checks were successful
arcad/emissary/pipeline/head This commit looks good
2023-10-22 09:50:22 +02:00
46a853a3f7 feat: update arcad/edge dependency
All checks were successful
arcad/emissary/pipeline/head This commit looks good
2023-10-21 21:47:18 +02:00
f31a63efdc feat: update arcad/edge dependency
All checks were successful
arcad/emissary/pipeline/head This commit looks good
2023-10-21 21:39:09 +02:00
c8a2303ff3 feat(spec): add 'zim' to apps allowed formats
All checks were successful
arcad/emissary/pipeline/head This commit looks good
2023-10-20 17:39:28 +02:00
ced2658eec feat: update arcad/edge dependency
All checks were successful
arcad/emissary/pipeline/head This commit looks good
2023-10-19 22:22:40 +02:00
ce9b3003fe feat: use new logger.CapturedE() api 2023-10-19 22:09:18 +02:00
b0898eefc3 feat: update arcad/edge dependency 2023-10-19 21:47:38 +02:00
4da723e908 feat(edge): update lib 2023-10-19 20:12:46 +02:00
e756a60373 feat: sentry integration
All checks were successful
arcad/emissary/pipeline/head This commit looks good
2023-10-13 14:22:28 +02:00
43 changed files with 636 additions and 176 deletions

14
.dockerignore Normal file
View File

@ -0,0 +1,14 @@
/apps
/bin
/dist
/out
/tmp
/tools
/.emissary-token
/.env
/agent-key.json
/server-key.json
/CHANGELOG.md
/state.json
/*.sqlite*
/.mktools

View File

@ -1,4 +1,12 @@
FROM golang:1.19 AS BUILD
FROM alpine as certs
RUN apk update && apk add ca-certificates curl openssl bash
RUN curl -k https://forge.cadoles.com/Cadoles/Jenkins/raw/branch/master/resources/com/cadoles/common/add-letsencrypt-ca.sh | bash
#####################################
# Emissary Server #
#####################################
FROM golang:1.21 AS build-emissary-server
RUN apt-get update \
&& apt-get install -y make
@ -7,9 +15,9 @@ COPY . /src
WORKDIR /src
RUN make GORELEASER_ARGS='build --rm-dist --single-target --snapshot' release
RUN make mktools && make GORELEASER_ARGS="build --snapshot --clean --single-target --id emissary-server" goreleaser
FROM busybox:latest AS RUNTIME
FROM busybox:latest AS emissary-server
ARG DUMB_INIT_VERSION=1.2.5
@ -19,11 +27,47 @@ RUN mkdir -p /usr/local/bin \
ENTRYPOINT ["/usr/local/bin/dumb-init", "--"]
COPY --from=BUILD /src/dist/emissary_linux_amd64_v1 /app
COPY --from=BUILD /src/tmp/config.yml /etc/emissary/config.yml
COPY --from=build-emissary-server /src/dist/emissary-server_linux_amd64_v1 /app
COPY misc/docker/server.yml /etc/emissary/server.yml
COPY --from=certs /etc/ssl/certs /etc/ssl/certs
EXPOSE 3000
ENTRYPOINT ["/app/emissary"]
RUN mkdir -p /data
CMD ["server", "run", "-c", "/etc/emissary/config.yml"]
CMD [ "/app/emissary", "-c", "/etc/emissary/config.yml", "server", "run"]
#####################################
# Emissary Agent #
#####################################
FROM golang:1.21 AS build-emissary-agent
RUN apt-get update \
&& apt-get install -y make
COPY . /src
WORKDIR /src
RUN make mktools && make GORELEASER_ARGS="build --snapshot --clean --single-target --id emissary-agent" goreleaser
FROM busybox:latest AS emissary-agent
ARG DUMB_INIT_VERSION=1.2.5
RUN mkdir -p /usr/local/bin \
&& wget -O /usr/local/bin/dumb-init https://github.com/Yelp/dumb-init/releases/download/v${DUMB_INIT_VERSION}/dumb-init_${DUMB_INIT_VERSION}_x86_64 \
&& chmod +x /usr/local/bin/dumb-init
ENTRYPOINT ["/usr/local/bin/dumb-init", "--"]
COPY --from=build-emissary-agent /src/dist/emissary-agent_linux_amd64_v1 /app
COPY --chmod=777 misc/docker/docker-agent-wrapper.sh /usr/local/bin/docker-agent-wrapper
COPY misc/docker/agent.yml /etc/emissary/agent.yml
COPY --from=certs /etc/ssl/certs /etc/ssl/certs
RUN mkdir -p /data
CMD [ "/usr/local/bin/docker-agent-wrapper", "/app/emissary", "-c", "/etc/emissary/agent.yml", "agent", "run" ]

View File

@ -1,12 +1,11 @@
LINT_ARGS ?= --timeout 5m
GORELEASER_VERSION ?= v1.13.1
GORELEASER_ARGS ?= release --snapshot --rm-dist
GORELEASER_ARGS ?= release --snapshot --clean
GITCHLOG_ARGS ?=
SHELL := /bin/bash
EMISSARY_VERSION ?=
DOCKER_IMAGE_NAME ?= bornholm/emissary
DOCKER_IMAGE_NAME ?= reg.cadoles.com/cadoles/emissary
DOCKER_IMAGE_TAG ?= $(MKT_PROJECT_VERSION)
GOTEST_ARGS ?= -short
@ -71,17 +70,23 @@ dump-config: build-emissary
./bin/emissary config dump > tmp/config.yml
.PHONY: goreleaser
goreleaser: .mktools
( set -o allexport && source .env && set +o allexport && VERSION=$(GORELEASER_VERSION) curl -sfL https://goreleaser.com/static/run | GORELEASER_CURRENT_TAG="$(MKT_PROJECT_VERSION)" bash /dev/stdin $(GORELEASER_ARGS) )
goreleaser: .env .mktools
( set -o allexport && source .env && set +o allexport && curl -sfL https://goreleaser.com/static/run | GORELEASER_CURRENT_TAG="$(MKT_PROJECT_VERSION)" bash /dev/stdin $(GORELEASER_ARGS) )
install-git-hooks:
git config core.hooksPath .githooks
docker-build:
docker build -t $(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG) .
docker-build: docker-build-agent docker-build-server
docker-release:
docker push $(DOCKER_IMAGE_NAME):$(DOCKER_IMAGE_TAG)
docker-build-%:
docker build --target emissary-$* -t $(DOCKER_IMAGE_NAME)-$*:latest .
docker-release: docker-release-agent docker-release-server
docker-release-%:
docker tag $(DOCKER_IMAGE_NAME)-$*:latest $(DOCKER_IMAGE_NAME)-$*:$(DOCKER_IMAGE_TAG)
docker push $(DOCKER_IMAGE_NAME)-$*:latest
docker push $(DOCKER_IMAGE_NAME)-$*:$(DOCKER_IMAGE_TAG)
deploy-openwrt-agent:
$(MAKE) GOARCH="arm" GORELEASER_ARGS='build --single-target --snapshot --clean' goreleaser
@ -126,13 +131,15 @@ load-sample-specs:
cat misc/spec-samples/app.emissary.cadoles.com.json | ./bin/server api agent spec update -a $(AGENT_ID) --no-patch --spec-data - --spec-name app.emissary.cadoles.com
cat misc/spec-samples/proxy.emissary.cadoles.com.json | ./bin/server api agent spec update -a $(AGENT_ID) --no-patch --spec-data - --spec-name proxy.emissary.cadoles.com
cat misc/spec-samples/mdns.emissary.cadoles.com.json | ./bin/server api agent spec update -a $(AGENT_ID) --no-patch --spec-data - --spec-name mdns.emissary.cadoles.com
cat misc/spec-samples/uci.emissary.cadoles.com.json | ./bin/server api agent spec update -a $(AGENT_ID) --no-patch --spec-data - --spec-name uci.emissary.cadoles.com
version: .mktools
@echo $(MKT_PROJECT_VERSION)
update-edge-lib:
git pull --rebase
GOPROXY=direct GOPRIVATE=forge.cadoles.com/arcad/edge go get -u forge.cadoles.com/arcad/edge
go clean -modcache
GONOPROXY=forge.cadoles.com/arcad/edge GOPRIVATE=forge.cadoles.com/arcad/edge go get -v -u forge.cadoles.com/arcad/edge
go mod tidy
$(MAKE) test
git add go.mod go.sum

View File

@ -7,6 +7,7 @@
- (FR) - [Premiers pas](./tutorials/fr/first-steps.md)
- (FR) - [Déployer un serveur mandataire inverse sur un agent](./tutorials/fr/deploy-reverse-proxy.md)
- (FR) - [Déployer une configuration UCI personnalisée sur un agent](./tutorials/fr/deploy-uci-configuration.md)
- (FR) - [Démarrer un agent avec Docker](./tutorials/fr/docker-agent.md)
## References

View File

@ -0,0 +1,10 @@
# Lancer un agent avec Docker
```shell
docker run \
--rm -it \
--network bridge \
-v emissary-agent-data:/data \
-e EMISSARY_AGENT_SERVER_URL=<server_url> \
reg.cadoles.com/cadoles/emissary-agent:latest
```

27
go.mod
View File

@ -1,9 +1,11 @@
module forge.cadoles.com/Cadoles/emissary
go 1.19
go 1.21
toolchain go1.21.2
require (
forge.cadoles.com/arcad/edge v0.0.0-20231003032536-4c6e979bb6bf
forge.cadoles.com/arcad/edge v0.0.0-20231130180951-32f04af138d7
github.com/Masterminds/sprig/v3 v3.2.3
github.com/alecthomas/participle/v2 v2.0.0-beta.5
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883
@ -14,7 +16,7 @@ require (
github.com/denisbrodbeck/machineid v1.0.1
github.com/dop251/goja v0.0.0-20230304130813-e2f543bf4b4c
github.com/evanphx/json-patch/v5 v5.6.0
github.com/go-chi/chi v4.1.2+incompatible
github.com/getsentry/sentry-go v0.25.0
github.com/go-chi/cors v1.2.1
github.com/golang-migrate/migrate/v4 v4.15.2
github.com/jackc/pgx/v5 v5.3.1
@ -26,7 +28,7 @@ require (
github.com/pkg/errors v0.9.1
github.com/qri-io/jsonschema v0.2.1
github.com/urfave/cli/v2 v2.24.4
gitlab.com/wpetit/goweb v0.0.0-20230419082146-a94d9ed7202b
gitlab.com/wpetit/goweb v0.0.0-20231019192040-4c72331a7648
gopkg.in/yaml.v3 v3.0.1
modernc.org/sqlite v1.21.0
)
@ -34,6 +36,7 @@ require (
require (
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.2.0 // indirect
github.com/allegro/bigcache/v3 v3.1.0 // indirect
github.com/barnybug/go-cast v0.0.0-20201201064555-a87ccbc26692 // indirect
github.com/dop251/goja_nodejs v0.0.0-20230320130059-dcf93ba651dd // indirect
github.com/gabriel-vasile/mimetype v1.4.1 // indirect
@ -41,11 +44,13 @@ require (
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/pprof v0.0.0-20230309165930-d61513b1440d // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
github.com/hashicorp/mdns v1.0.5 // indirect
github.com/huandu/xstrings v1.3.3 // indirect
github.com/igm/sockjs-go/v3 v3.0.2 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/keegancsmith/rpc v1.3.0 // indirect
github.com/klauspost/compress v1.16.6 // indirect
github.com/miekg/dns v1.1.53 // indirect
github.com/mitchellh/copystructure v1.0.0 // indirect
github.com/mitchellh/reflectwalk v1.0.0 // indirect
@ -53,7 +58,8 @@ require (
github.com/orcaman/concurrent-map v1.0.0 // indirect
github.com/shopspring/decimal v1.2.0 // indirect
github.com/spf13/cast v1.3.1 // indirect
golang.org/x/net v0.9.0 // indirect
github.com/ulikunitz/xz v0.5.11 // indirect
golang.org/x/net v0.11.0 // indirect
google.golang.org/genproto v0.0.0-20220728213248-dd149ef739b9 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)
@ -76,7 +82,7 @@ require (
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/puddle/v2 v2.2.0 // indirect
github.com/jackc/puddle/v2 v2.2.1 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/leodido/go-urn v1.2.2 // indirect
github.com/lestrrat-go/blackmagic v1.0.1 // indirect
@ -97,15 +103,14 @@ require (
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
go.opencensus.io v0.24.0 // indirect
go.uber.org/atomic v1.10.0 // indirect
golang.org/x/crypto v0.7.0 // indirect
golang.org/x/crypto v0.10.0 // indirect
golang.org/x/mod v0.10.0 // indirect
golang.org/x/sync v0.1.0 // indirect
golang.org/x/sys v0.7.0 // indirect
golang.org/x/term v0.7.0 // indirect
golang.org/x/text v0.9.0 // indirect
golang.org/x/sys v0.9.0 // indirect
golang.org/x/term v0.9.0 // indirect
golang.org/x/text v0.10.0 // indirect
golang.org/x/tools v0.8.0 // indirect
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/go-playground/validator.v9 v9.31.0 // indirect
lukechampine.com/uint128 v1.2.0 // indirect
modernc.org/cc/v3 v3.40.0 // indirect

73
go.sum
View File

@ -54,8 +54,8 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
forge.cadoles.com/arcad/edge v0.0.0-20231003032536-4c6e979bb6bf h1:jiQt6WdXCQlgMm+cC/vFd7aEibaXQUVZKB+tpLzyVao=
forge.cadoles.com/arcad/edge v0.0.0-20231003032536-4c6e979bb6bf/go.mod h1:cHbSOTFy09i2RD+EpE76q/rZfTzxZLFD+iHxVfE6QxA=
forge.cadoles.com/arcad/edge v0.0.0-20231130180951-32f04af138d7 h1:aDiZNT87sSC014GIapyEZ9O98EHOWHBNLtJR6p1ngG0=
forge.cadoles.com/arcad/edge v0.0.0-20231130180951-32f04af138d7/go.mod h1:DXxP+2fbR3hD3Q4ePoJn6jJItpOyBWx9wNsxCZEh4M4=
gioui.org v0.0.0-20210308172011-57750fc8a0a6/go.mod h1:RSH6KIUZ0p2xy5zHDxgAM4zumjgTw83q2ge/PI+yyw8=
github.com/AdaLogics/go-fuzz-headers v0.0.0-20210715213245-6c3934b029d8/go.mod h1:CzsSbkDixRphAF5hS6wbMKq0eI6ccJRb7/A0M6JBnwg=
github.com/Azure/azure-pipeline-go v0.2.3/go.mod h1:x841ezTBIMG6O3lAcl8ATHnsOPVl2bqk7S3ta6S6u4k=
@ -128,6 +128,7 @@ github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkK
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38 h1:smF2tmSOzy2Mm+0dGI2AIUHY+w0BUc+4tn40djz7+6U=
github.com/alecthomas/assert v0.0.0-20170929043011-405dbfeb8e38/go.mod h1:r7bzyVFMNntcxPZXK3/+KdruV1H5KSlyVY0gc+NgInI=
github.com/alecthomas/assert/v2 v2.0.3 h1:WKqJODfOiQG0nEJKFKzDIG3E29CN2/4zR9XGJzKIkbg=
github.com/alecthomas/assert/v2 v2.0.3/go.mod h1:b/+1DI2Q6NckYi+3mXyH3wFb8qG37K/DuK80n7WefXA=
github.com/alecthomas/chroma v0.7.0/go.mod h1:1U/PfCsTALWWYHDnsIQkxEBM0+6LLe0v8+RSVMOwxeY=
github.com/alecthomas/chroma v0.10.0 h1:7XDcGkCQopCNKjZHfYrNLraA+M7e0fMiJ/Mfikbfjek=
github.com/alecthomas/chroma v0.10.0/go.mod h1:jtJATyUxlIORhUOFNA9NZDWGAQ8wpxQQqNSB4rjA/1s=
@ -139,6 +140,7 @@ github.com/alecthomas/participle/v2 v2.0.0-beta.5 h1:y6dsSYVb1G5eK6mgmy+BgI3Mw35
github.com/alecthomas/participle/v2 v2.0.0-beta.5/go.mod h1:RC764t6n4L8D8ITAJv0qdokritYSNR3wV5cVwmIEaMM=
github.com/alecthomas/repr v0.0.0-20180818092828-117648cd9897/go.mod h1:xTS7Pm1pD1mvyM075QCDSRqH6qRLXylzS24ZTpRiSzQ=
github.com/alecthomas/repr v0.1.0 h1:ENn2e1+J3k09gyj2shc0dHr/yjaWSHRlrJ4DPMevDqE=
github.com/alecthomas/repr v0.1.0/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@ -146,6 +148,8 @@ github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRF
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
github.com/alexflint/go-filemutex v0.0.0-20171022225611-72bdc8eae2ae/go.mod h1:CgnQgUtFrFz9mxFNtED3jI5tLDjKlOM+oUF/sTk6ps0=
github.com/alexflint/go-filemutex v1.1.0/go.mod h1:7P4iRhttt/nUvUOrYIhcpMzv2G6CY9UnI16Z+UJqRyk=
github.com/allegro/bigcache/v3 v3.1.0 h1:H2Vp8VOvxcrB91o86fUSVJFqeuz8kpyyB02eH3bSzwk=
github.com/allegro/bigcache/v3 v3.1.0/go.mod h1:aPyh7jEvrog9zAwx5N7+JUQX5dZTSGpxF1LAR4dr35I=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883 h1:bvNMNQO63//z+xNgfBlViaCIJKLlCJ6/fmUseuG0wVQ=
github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
@ -504,15 +508,17 @@ github.com/gabriel-vasile/mimetype v1.4.1 h1:TRWk7se+TOjCYgRth7+1/OYLNiRNIotknkF
github.com/gabriel-vasile/mimetype v1.4.1/go.mod h1:05Vi0w3Y9c/lNvJOdmIwvrrAhX3rYhfQQCaf9VJcv7M=
github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7/go.mod h1:NR3MbYisc3/PwhQ00EMzDiPmrwpPxAn5GI05/YaO1SY=
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
github.com/getsentry/sentry-go v0.25.0 h1:q6Eo+hS+yoJlTO3uu/azhQadsD8V+jQn2D8VvX1eOyI=
github.com/getsentry/sentry-go v0.25.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY=
github.com/ghodss/yaml v0.0.0-20150909031657-73d445a93680/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-chi/chi v4.0.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-chi/chi v4.1.2+incompatible h1:fGFk2Gmi/YKXk0OmGfBh0WgmN3XB8lVnEyNz34tQRec=
github.com/go-chi/chi v4.1.2+incompatible/go.mod h1:eB3wogJHnLi3x/kFX2A+IbTBlXxmMeXJVKy9tTv1XzQ=
github.com/go-chi/chi/v5 v5.0.8 h1:lD+NLqFcAi1ovnVZpsnObHGW4xb4J8lNmoYVfECH1Y0=
github.com/go-chi/chi/v5 v5.0.8/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-chi/cors v1.2.1 h1:xEC8UT3Rlp2QuWNEr4Fs/c2EAGVKBwy/1vHx3bppil4=
github.com/go-chi/cors v1.2.1/go.mod h1:sSbTewc+6wYHBBCW7ytsFSn836hqM7JxpglAy2Vzc58=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g=
github.com/go-fonts/latin-modern v0.2.0/go.mod h1:rQVLdDMK+mK1xscDwsqM5J8U2jrRa3T0ecnM9pNujks=
github.com/go-fonts/liberation v0.1.1/go.mod h1:K6qoJYypsmfVjWg8KOVDQhLc8UDgIK2HYqyqAO9z7GY=
@ -550,10 +556,10 @@ github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dp
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
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.16.0/go.mod h1:1AnU7NaIRDWWzGEKwgtJRd2xk99HeFyHw3yid4rvQIY=
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
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-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU=
@ -673,6 +679,7 @@ github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/go-containerregistry v0.5.1/go.mod h1:Ct15B4yir3PLOP5jsy0GNeYVaIZs/MK/Jz5any1wFW0=
github.com/google/go-github/v39 v39.2.0/go.mod h1:C1s8C5aCC9L+JXIYpJM5GYytdX52vC1bLvHEF1IhBrE=
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
@ -761,6 +768,8 @@ github.com/hashicorp/go.net v0.0.0-20151006203346-104dcad90073/go.mod h1:hjKkEWc
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
github.com/hashicorp/mdns v0.0.0-20151206042412-9d85cf22f9f8/go.mod h1:aa76Av3qgPeIQp9Y3qIkTBPieQYNkQ13Kxe7pze9Wb0=
@ -770,6 +779,7 @@ github.com/hashicorp/mdns v1.0.5/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/
github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2pPBoIllUwCN7I=
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/huandu/xstrings v1.3.3 h1:/Gcsuc1x8JVbJ9/rlye4xZnVAbEkGauT8lbebqcQws4=
github.com/huandu/xstrings v1.3.3/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE=
@ -837,8 +847,8 @@ github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0f
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle/v2 v2.2.0 h1:RdcDk92EJBuBS55nQMMYFXTxwstHug4jkhT5pq8VxPk=
github.com/jackc/puddle/v2 v2.2.0/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/jedib0t/go-pretty/v6 v6.4.4 h1:N+gz6UngBPF4M288kiMURPHELDMIhF/Em35aYuKrsSc=
github.com/jedib0t/go-pretty/v6 v6.4.4/go.mod h1:MgmISkTWDSFu0xOqiZ0mKNntMQ2mDgOcwOkwBEkMDJI=
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
@ -891,6 +901,8 @@ github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdY
github.com/klauspost/compress v1.13.1/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/compress v1.13.4/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/compress v1.16.6 h1:91SKEy4K37vkp255cJ8QesJhjyRO0hn9i9G0GoUwLsk=
github.com/klauspost/compress v1.16.6/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
@ -908,7 +920,7 @@ github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/ktrysmt/go-bitbucket v0.6.4/go.mod h1:9u0v3hsd2rqCHRIpbir1oP7F58uo5dq19sBYvuMoyQ4=
github.com/leodido/go-urn v1.1.0/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/leodido/go-urn v1.2.2 h1:7z68G0FCGvDk646jz1AelTYNYWrTNm0bEcFAo147wt4=
github.com/leodido/go-urn v1.2.2/go.mod h1:kUaIbLZWttglzwNuG0pgsh5vuV6u2YcGBYz1hIPjtOQ=
github.com/lestrrat-go/blackmagic v1.0.1 h1:lS5Zts+5HIC/8og6cGHb0uCcNCa3OUt1ygh3Qz2Fe80=
@ -978,6 +990,7 @@ github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOq
github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.10/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
@ -1113,8 +1126,11 @@ github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2
github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pierrec/lz4/v4 v4.1.8/go.mod h1:gZWDp/Ze/IJXGXf23ltt2EXimqmTUXEy0GFuRQyBid4=
github.com/pingcap/errors v0.11.4 h1:lFuQV/oaUMGcD2tqt+01ROSmJs75VG1ToEOkZIZ4nE4=
github.com/pingcap/errors v0.11.4/go.mod h1:Oi8TUi2kEtXXLMJk9l1cGmz20kV3TaQ0usTwv5KuLY8=
github.com/pkg/browser v0.0.0-20210706143420-7d21f8c997e2/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1-0.20171018195549-f15c970de5b7/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@ -1176,6 +1192,7 @@ github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFR
github.com/rogpeppe/go-internal v1.2.2/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
@ -1211,8 +1228,9 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
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.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v0.0.0-20190330032615-68dc04aab96a/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
@ -1273,6 +1291,8 @@ github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tv42/httpunix v0.0.0-20191220191345-2ba4b9c3382c/go.mod h1:hzIxponao9Kjc7aWznkXaL4U4TWaDSs8zcsY4Ka08nM=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/ulikunitz/xz v0.5.11 h1:kpFauv27b6ynzBNT/Xy+1k+fK4WswhN/6PN5WhFAGw8=
github.com/ulikunitz/xz v0.5.11/go.mod h1:nbz6k7qbPmH4IRqmfOplQw/tblSgqTqBwxkY0oWt/14=
github.com/urfave/cli v0.0.0-20171014202726-7bc6a0acffa5/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
@ -1314,8 +1334,8 @@ github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50/go.mod h1:NUSPS
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE=
gitlab.com/wpetit/goweb v0.0.0-20230419082146-a94d9ed7202b h1:nkvOl8TCj/mErADnwFFynjxBtC+hHsrESw6rw56JGmg=
gitlab.com/wpetit/goweb v0.0.0-20230419082146-a94d9ed7202b/go.mod h1:3sus4zjoUv1GB7eDLL60QaPkUnXJCWBpjvbe0jWifeY=
gitlab.com/wpetit/goweb v0.0.0-20231019192040-4c72331a7648 h1:t2UQmCmUoElIBBuVTqxqo8DcTJA/exQ/Q7XycfLqCZo=
gitlab.com/wpetit/goweb v0.0.0-20231019192040-4c72331a7648/go.mod h1:WdxGjM3HJWgBkUa4TwaTXUqY2BnRKlNSyUIv1aF4jxk=
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
@ -1369,6 +1389,8 @@ go.uber.org/atomic v1.10.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0
go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A=
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
@ -1403,8 +1425,9 @@ golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm
golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.7.0 h1:AvwMYaRytfdeVt3u6mLaxYtErKYjxA2OXjJ1HHq6t3A=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM=
golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I=
golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
@ -1533,8 +1556,8 @@ golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.4.0/go.mod h1:MBQ8lrhLObU/6UmLb4fmbmk5OcyYmqtbGd/9yIeKjEE=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/net v0.9.0 h1:aWJ/m6xSmxWBx+V0XRHTlrYrPG56jKsLdTFmsSsCzOM=
golang.org/x/net v0.9.0/go.mod h1:d48xBJpPfHeWQsugry2m+kC02ZBRGRgulfHnEXEuWns=
golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU=
golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ=
golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
@ -1699,8 +1722,8 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s=
golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@ -1710,8 +1733,8 @@ golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.3.0/go.mod h1:q750SLmJuPmVoN1blW3UFBPREJfb1KmY3vwxfr+nFDA=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/term v0.7.0 h1:BEvjmm5fURWqcfbSKTdpkDXYBrUS1c0m8agp14W48vQ=
golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY=
golang.org/x/term v0.9.0 h1:GRRCnKYhdQrD8kfRAdQ6Zcw1P0OcELxGLKJvtjVMZ28=
golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@ -1726,8 +1749,8 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58=
golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@ -1982,6 +2005,7 @@ google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ5
google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
google.golang.org/grpc v1.45.0/go.mod h1:lN7owxKUQEqMfSyQikvvk5tf/6zMPsrK+ONuO11+0rQ=
google.golang.org/grpc v1.48.0 h1:rQOsyJ/8+ufEDJd/Gdsz7HG220Mh9HAhFHRGnIjda0w=
google.golang.org/grpc v1.48.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
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=
@ -1996,8 +2020,8 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.29.1 h1:7QBf+IK2gx70Ap/hDsOmam3GE0v9HicjfEdAxE62UoM=
google.golang.org/protobuf v1.29.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/airbrake/gobrake.v2 v2.0.9/go.mod h1:/h5ZAUhDkGaJfjzjKLSjv6zCL6O0LLBxU4K+aSYdM/U=
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
@ -2108,6 +2132,7 @@ modernc.org/ccgo/v3 v3.9.2/go.mod h1:gnJpy6NIVqkETT+L5zPsQFj7L2kkhfPMzOghRNv/CFo
modernc.org/ccgo/v3 v3.16.13 h1:Mkgdzl46i5F/CNR/Kj80Ri59hC8TKAhZrYSaqvkwzUw=
modernc.org/ccgo/v3 v3.16.13/go.mod h1:2Quk+5YgpImhPjv2Qsob1DnZ/4som1lJTodubIcoUkY=
modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk=
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
modernc.org/db v1.0.0/go.mod h1:kYD/cO29L/29RM0hXYl4i3+Q5VojL31kTUVpVJDw0s8=
modernc.org/file v1.0.0/go.mod h1:uqEokAEn1u6e+J45e54dsEA/pw4o7zLrA2GwyntZzjw=
modernc.org/fileutil v1.0.0/go.mod h1:JHsWpkrk/CnVV1H/eGlFf85BEpfkrp56ro8nojIq9Q8=
@ -2141,12 +2166,14 @@ modernc.org/strutil v1.1.3 h1:fNMm+oJklMGYfU9Ylcywl0CO5O6nTfaowNsh2wpPjzY=
modernc.org/strutil v1.1.3/go.mod h1:MEHNA7PdEnEwLvspRMtWTNnp2nnyvMfkimT1NKNAGbw=
modernc.org/tcl v1.5.2/go.mod h1:pmJYOLgpiys3oI4AeAafkcUfE+TKKilminxNyU/+Zlo=
modernc.org/tcl v1.15.1 h1:mOQwiEK4p7HruMZcwKTZPw/aqtGM4aY00uzWhlKKYws=
modernc.org/tcl v1.15.1/go.mod h1:aEjeGJX2gz1oWKOLDVZ2tnEWLUrIn8H+GFu+akoDhqs=
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/z v1.0.1-0.20210308123920-1f282aa71362/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA=
modernc.org/z v1.0.1/go.mod h1:8/SRk5C/HgiQWCgXdfpb+1RvhORdkz5sw72d3jjtyqA=
modernc.org/z v1.7.0 h1:xkDw/KepgEjeizO2sNco+hqYkU12taxQFqPEmgm1GWE=
modernc.org/z v1.7.0/go.mod h1:hVdgNMh8ggTuRG1rGU8x+xGRFfiQUIAw0ZqlPy8+HyQ=
modernc.org/zappy v1.0.0/go.mod h1:hHe+oGahLVII/aTTyWK/b53VDHMAGCBYYeZ9sn83HC4=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

View File

@ -43,13 +43,15 @@ func (a *Agent) Run(ctx context.Context) error {
logger.Debug(ctx, "registering agent")
if err := a.registerAgent(ctx, client, state); err != nil {
logger.Error(ctx, "could not register agent", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "could not register agent", logger.CapturedE(err))
}
logger.Debug(ctx, "state before reconciliation", logger.F("state", state))
if err := a.Reconcile(ctx, state); err != nil {
logger.Error(ctx, "could not reconcile node with state", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "could not reconcile node with state", logger.CapturedE(err))
return
}
@ -79,7 +81,8 @@ func (a *Agent) Reconcile(ctx context.Context, state *State) error {
)
if err := ctrl.Reconcile(ctrlCtx, state); err != nil {
logger.Error(ctx, "could not reconcile", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "could not reconcile", logger.CapturedE(err))
}
}
@ -110,9 +113,10 @@ func (a *Agent) collectMetadata(ctx context.Context) (map[string]any, error) {
for _, collector := range a.collectors {
name, value, err := collector.Collect(ctx)
if err != nil {
err = errors.WithStack(err)
logger.Error(
ctx, "could not collect metadata",
logger.E(errors.WithStack(err)), logger.F("name", name),
logger.CapturedE(err), logger.F("name", name),
)
continue

View File

@ -16,8 +16,10 @@ import (
appModule "forge.cadoles.com/arcad/edge/pkg/module/app"
"forge.cadoles.com/arcad/edge/pkg/module/blob"
"forge.cadoles.com/arcad/edge/pkg/module/cast"
"forge.cadoles.com/arcad/edge/pkg/module/fetch"
fetchModule "forge.cadoles.com/arcad/edge/pkg/module/fetch"
netModule "forge.cadoles.com/arcad/edge/pkg/module/net"
"forge.cadoles.com/arcad/edge/pkg/module/rpc"
shareModule "forge.cadoles.com/arcad/edge/pkg/module/share"
"forge.cadoles.com/arcad/edge/pkg/storage"
"forge.cadoles.com/arcad/edge/pkg/storage/driver"
@ -29,6 +31,7 @@ import (
"gitlab.com/wpetit/goweb/logger"
// Register storage drivers
_ "forge.cadoles.com/arcad/edge/pkg/storage/driver/cache"
_ "forge.cadoles.com/arcad/edge/pkg/storage/driver/rpc"
_ "forge.cadoles.com/arcad/edge/pkg/storage/driver/sqlite"
)
@ -85,7 +88,12 @@ func (c *Controller) getHandlerOptions(ctx context.Context, appKey string, specs
mounts = append(mounts, authMount)
}
mounts = append(mounts, appModule.Mount(c.appRepository))
mounts = append(
mounts,
appModule.Mount(c.appRepository),
blob.Mount(10<<(10*2)), // 10Mb
fetch.Mount(),
)
deps := Dependencies{
Bus: memory.NewBus(),
@ -197,9 +205,10 @@ func createResolveAppURL(specs *spec.Spec) (ResolveAppURLFunc, error) {
for ifaceName, ifaceTmpl := range ifaceMappings {
iface, err := net.InterfaceByName(ifaceName)
if err != nil {
logger.Error(
err = errors.WithStack(err)
logger.Warn(
ctx, "could not find interface",
logger.E(errors.WithStack(err)), logger.F("iface", ifaceName),
logger.CapturedE(err), logger.F("iface", ifaceName),
)
continue
@ -207,9 +216,10 @@ func createResolveAppURL(specs *spec.Spec) (ResolveAppURLFunc, error) {
addresses, err := iface.Addrs()
if err != nil {
err = errors.WithStack(err)
logger.Error(
ctx, "could not list interface addresses",
logger.E(errors.WithStack(err)),
logger.CapturedE(err),
logger.F("iface", iface.Name),
)
@ -219,9 +229,10 @@ func createResolveAppURL(specs *spec.Spec) (ResolveAppURLFunc, error) {
for _, addr := range addresses {
ifaIP, network, err := net.ParseCIDR(addr.String())
if err != nil {
err = errors.WithStack(err)
logger.Error(
ctx, "could not parse interface ip",
logger.E(errors.WithStack(err)),
logger.CapturedE(err),
logger.F("iface", iface.Name),
)
@ -296,7 +307,7 @@ func (c *Controller) getAppModules(deps Dependencies) []app.ServerModuleFactory
cast.CastModuleFactory(),
module.LifecycleModuleFactory(),
netModule.ModuleFactory(deps.Bus),
module.RPCModuleFactory(deps.Bus),
rpc.ModuleFactory(deps.Bus),
module.StoreModuleFactory(deps.DocumentStore),
blob.ModuleFactory(deps.Bus, deps.BlobStore),
authModuleFactory(deps.KeySet),

View File

@ -63,14 +63,16 @@ func (r *AppRepository) List(ctx context.Context) ([]*app.Manifest, error) {
bundle, err := bundle.FromPath(path)
if err != nil {
logger.Error(bundleCtx, "could not load bundle", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(bundleCtx, "could not load bundle", logger.CapturedE(err))
continue
}
manifest, err := app.LoadManifest(bundle)
if err != nil {
logger.Error(bundleCtx, "could not load manifest", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(bundleCtx, "could not load manifest", logger.CapturedE(err))
continue
}
@ -97,14 +99,16 @@ func (r *AppRepository) findManifest(ctx context.Context, id app.ID) (*app.Manif
bundle, err := bundle.FromPath(path)
if err != nil {
logger.Error(bundleCtx, "could not load bundle", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(bundleCtx, "could not load bundle", logger.CapturedE(err))
continue
}
manifest, err := app.LoadManifest(bundle)
if err != nil {
logger.Error(bundleCtx, "could not load manifest", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(bundleCtx, "could not load manifest", logger.CapturedE(err))
continue
}

View File

@ -66,10 +66,11 @@ func (c *Controller) stopAllApps(ctx context.Context, spec *spec.Spec) {
logger.Info(ctx, "stopping app", logger.F("appID", appID))
if err := entry.Server.Stop(); err != nil {
err = errors.WithStack(err)
logger.Error(
ctx, "error while stopping app",
logger.F("appID", appID),
logger.E(errors.WithStack(err)),
logger.CapturedE(err),
)
delete(c.servers, appID)
@ -87,10 +88,11 @@ func (c *Controller) updateApps(ctx context.Context, specs *spec.Spec) {
logger.Info(ctx, "stopping app", logger.F("appKey", appKey))
if err := server.Server.Stop(); err != nil {
err = errors.WithStack(err)
logger.Error(
ctx, "error while stopping app",
logger.F("appKey", appKey),
logger.E(errors.WithStack(err)),
logger.CapturedE(err),
)
delete(c.servers, appKey)
@ -98,9 +100,10 @@ func (c *Controller) updateApps(ctx context.Context, specs *spec.Spec) {
}
if err := c.updateAppRepository(ctx, specs); err != nil {
err = errors.WithStack(err)
logger.Error(
ctx, "could not update app repository",
logger.E(errors.WithStack(err)),
logger.CapturedE(err),
)
return
@ -111,7 +114,8 @@ func (c *Controller) updateApps(ctx context.Context, specs *spec.Spec) {
appCtx := logger.With(ctx, logger.F("appKey", appKey))
if err := c.updateApp(ctx, specs, appKey); err != nil {
logger.Error(appCtx, "could not update app", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(appCtx, "could not update app", logger.CapturedE(err))
continue
}
}
@ -200,11 +204,13 @@ func (c *Controller) updateApp(ctx context.Context, specs *spec.Spec, appKey str
return nil
}
ctx = logger.With(ctx,
logger.F("appKey", appKey),
logger.F("address", appEntry.Address),
)
if defChanged && server.AppDefHash != 0 {
logger.Info(
ctx, "restarting app",
logger.F("address", appEntry.Address),
)
logger.Info(ctx, "restarting app")
if err := server.Server.Stop(); err != nil {
return errors.WithStack(err)
@ -217,10 +223,7 @@ func (c *Controller) updateApp(ctx context.Context, specs *spec.Spec, appKey str
c.servers[appKey] = serverEntry
} else {
logger.Info(
ctx, "starting app",
logger.F("address", appEntry.Address),
)
logger.Info(ctx, "starting app")
}
if err := server.Server.Start(ctx, appEntry.Address); err != nil {

View File

@ -14,8 +14,8 @@ import (
"gitlab.com/wpetit/goweb/logger"
"forge.cadoles.com/arcad/edge/pkg/bundle"
"github.com/go-chi/chi/middleware"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/pkg/errors"
_ "forge.cadoles.com/Cadoles/emissary/internal/imports/passwd"
@ -48,7 +48,7 @@ func (s *Server) Start(ctx context.Context, addr string) (err error) {
router.Use(middleware.Compress(5))
handler := edgeHTTP.NewHandler(s.handlerOptions...)
if err := handler.Load(s.bundle); err != nil {
if err := handler.Load(ctx, s.bundle); err != nil {
return errors.Wrap(err, "could not load app bundle")
}
@ -72,7 +72,8 @@ func (s *Server) Start(ctx context.Context, addr string) (err error) {
defer func() {
if recovered := recover(); recovered != nil {
if err, ok := recovered.(error); ok {
logger.Error(ctx, err.Error(), logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, err.Error(), logger.CapturedE(err))
return
}

View File

@ -24,7 +24,8 @@
"type": "string",
"enum": [
"zip",
"tar.gz"
"tar.gz",
"zim"
]
},
"storage": {

View File

@ -117,7 +117,8 @@ func (c *Controller) updateResponder(ctx context.Context, spec *mdns.Spec) error
service, err := dnssd.NewService(config)
if err != nil {
logger.Error(ctx, "could not create mdns service", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "could not create mdns service", logger.CapturedE(err))
continue
}
@ -132,7 +133,8 @@ func (c *Controller) updateResponder(ctx context.Context, spec *mdns.Spec) error
for _, service := range services {
if _, err := responder.Add(service); err != nil {
logger.Error(ctx, "could not add mdns service", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "could not add mdns service", logger.CapturedE(err))
continue
}
@ -148,7 +150,8 @@ func (c *Controller) updateResponder(ctx context.Context, spec *mdns.Spec) error
defer c.stopResponder(ctx)
if err := responder.Respond(ctx); err != nil && !errors.Is(err, context.Canceled) {
logger.Error(ctx, "could not respond to mdns queries", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "could not respond to mdns queries", logger.CapturedE(err))
}
}()

View File

@ -64,9 +64,10 @@ func (c *SysUpgradeController) Reconcile(ctx context.Context, state *agent.State
defer func() {
if err := os.RemoveAll(downloadDir); err != nil {
err = errors.WithStack(err)
logger.Error(
ctx, "could not remove download direction",
logger.E(errors.WithStack(err)),
logger.CapturedE(err),
logger.F("downloadDir", downloadDir),
)
}

View File

@ -46,7 +46,8 @@ func (c *UCIController) Reconcile(ctx context.Context, state *agent.State) error
}
if err := c.updateConfiguration(ctx, uciSpec); err != nil {
logger.Error(ctx, "could not update configuration", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "could not update configuration", logger.CapturedE(err))
return nil
}

View File

@ -145,7 +145,8 @@ func (c *Controller) writeState(ctx context.Context, state *agent.State) error {
return
}
logger.Error(ctx, "could not remove temporary file", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "could not remove temporary file", logger.CapturedE(err))
}
}()
@ -155,7 +156,8 @@ func (c *Controller) writeState(ctx context.Context, state *agent.State) error {
return
}
logger.Error(ctx, "could not close temporary file", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "could not close temporary file", logger.CapturedE(err))
}
}()

View File

@ -58,10 +58,11 @@ func (c *Controller) stopAllProxies(ctx context.Context) {
logger.Info(ctx, "stopping proxy", logger.F("proxyID", proxyID))
if err := entry.Proxy.Stop(); err != nil {
err = errors.WithStack(err)
logger.Error(
ctx, "error while stopping proxy",
logger.F("proxyID", proxyID),
logger.E(errors.WithStack(err)),
logger.CapturedE(err),
)
delete(c.proxies, proxyID)
@ -79,10 +80,11 @@ func (c *Controller) updateProxies(ctx context.Context, spec *spec.Spec) {
logger.Info(ctx, "stopping proxy", logger.F("proxyID", proxyID))
if err := entry.Proxy.Stop(); err != nil {
err = errors.WithStack(err)
logger.Error(
ctx, "error while stopping proxy",
logger.F("proxyID", proxyID),
logger.E(errors.WithStack(err)),
logger.CapturedE(err),
)
delete(c.proxies, proxyID)
@ -94,7 +96,8 @@ func (c *Controller) updateProxies(ctx context.Context, spec *spec.Spec) {
proxyCtx := logger.With(ctx, logger.F("proxyID", proxyID))
if err := c.updateProxy(ctx, proxyID, proxySpec); err != nil {
logger.Error(proxyCtx, "could not update proxy", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(proxyCtx, "could not update proxy", logger.CapturedE(err))
continue
}
}

View File

@ -38,12 +38,14 @@ func (p *ReverseProxy) Start(ctx context.Context, addr string, funcs ...proxy.Op
go func() {
defer func() {
if err := p.Stop(); err != nil {
logger.Error(ctx, "error while stopping gateway", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "error while stopping gateway", logger.CapturedE(err))
}
}()
if err := server.ListenAndServe(); err != nil && !errors.Is(err, http.ErrServerClosed) {
logger.Error(ctx, "error while listening", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "error while listening", logger.CapturedE(err))
}
}()

View File

@ -40,14 +40,15 @@ func (c *Controller) reconcileAgent(ctx context.Context, client *client.Client,
ctx = logger.With(ctx, logger.F("agentID", agent.ID))
if agent.Status != datastore.AgentStatusAccepted {
logger.Error(ctx, "unexpected agent status", logger.F("status", agent.Status))
logger.Warn(ctx, "unexpected agent status", logger.F("status", agent.Status))
return nil
}
specs, err := client.GetAgentSpecs(ctx, agent.ID)
if err != nil {
logger.Error(ctx, "could not retrieve agent specs", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "could not retrieve agent specs", logger.CapturedE(err))
return nil
}

View File

@ -7,8 +7,11 @@ import (
"sort"
"time"
"forge.cadoles.com/Cadoles/emissary/internal/command/common"
"github.com/getsentry/sentry-go"
"github.com/pkg/errors"
"github.com/urfave/cli/v2"
"gitlab.com/wpetit/goweb/logger"
)
func Main(buildDate, projectVersion, gitRef, defaultConfigPath string, commands ...*cli.Command) {
@ -46,6 +49,27 @@ func Main(buildDate, projectVersion, gitRef, defaultConfigPath string, commands
return errors.WithStack(err)
}
conf, err := common.LoadConfig(ctx)
if err != nil {
return errors.Wrap(err, "Could not load configuration")
}
if conf.Sentry.DSN != "" {
err = sentry.Init(sentry.ClientOptions{
Dsn: string(conf.Sentry.DSN),
Debug: ctx.Bool("debug"),
AttachStacktrace: true,
Environment: string(conf.Sentry.Environment),
})
if err != nil {
logger.Error(ctx.Context, "could not initialize sentry", logger.E(errors.WithStack(err)))
}
logger.SetCaptureFunc(func(err error) {
sentry.CaptureException(err)
})
}
return nil
},
Flags: []cli.Flag{
@ -84,11 +108,15 @@ func Main(buildDate, projectVersion, gitRef, defaultConfigPath string, commands
},
}
defer sentry.Flush(2 * time.Second)
app.ExitErrHandler = func(ctx *cli.Context, err error) {
if err == nil {
return
}
sentry.CaptureException(err)
debug := ctx.Bool("debug")
if !debug {

View File

@ -32,7 +32,8 @@ func PingCommand() *cli.Command {
defer func() {
if err := db.Close(); err != nil {
logger.Error(ctx.Context, "error while closing database connection", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx.Context, "error while closing database connection", logger.CapturedE(err))
}
}()

View File

@ -11,6 +11,7 @@ import (
// Config definition
type Config struct {
Logger LoggerConfig `yaml:"logger"`
Sentry SentryConfig `yaml:"sentry"`
Server ServerConfig `yaml:"server"`
Agent AgentConfig `yaml:"agent"`
}
@ -44,6 +45,7 @@ func NewDefault() *Config {
Logger: NewDefaultLoggerConfig(),
Agent: NewDefaultAgentConfig(),
Server: NewDefaultServerConfig(),
Sentry: NewDefaultSentryConfig(),
}
}

View File

@ -15,6 +15,6 @@ type DatabaseConfig struct {
func NewDefaultDatabaseConfig() DatabaseConfig {
return DatabaseConfig{
Driver: "sqlite",
DSN: "sqlite://emissary.sqlite?_pragma=foreign_keys(1)&_pragma=busy_timeout=60000",
DSN: "sqlite://emissary.sqlite?_pragma=foreign_keys(1)&_pragma=busy_timeout=150000&_pragma=journal_mode=WAL",
}
}

View File

@ -10,7 +10,41 @@ import (
"gopkg.in/yaml.v3"
)
var reVar = regexp.MustCompile(`^\${(\w+)}$`)
var (
interpolationRegExp = regexp.MustCompile(`^\${((?P<varName>\w+)|((?P<varNameWithDefault>\w+):-(?P<defaultValue>[^}]+)))}$`)
varNameGroupIndex = interpolationRegExp.SubexpIndex("varName")
varNameWithDefaultGroupIndex = interpolationRegExp.SubexpIndex("varNameWithDefault")
defaultValueGroupIndex = interpolationRegExp.SubexpIndex("defaultValue")
)
func interpolate(str string, getValueFunc func(name string) string) string {
for _, match := range interpolationRegExp.FindAllStringSubmatch(str, -1) {
varName := match[varNameWithDefaultGroupIndex]
if varName == "" {
varName = match[varNameGroupIndex]
}
if varName == "" {
continue
}
defaultValue := ""
if defaultValueGroupIndex < len(match) {
defaultValue = match[defaultValueGroupIndex]
}
str = getValueFunc(varName)
if str == "" {
str = defaultValue
}
}
return str
}
func interpolateEnv(str string) string {
return interpolate(str, os.Getenv)
}
type InterpolatedString string
@ -21,11 +55,7 @@ func (is *InterpolatedString) UnmarshalYAML(value *yaml.Node) error {
return errors.WithStack(err)
}
if match := reVar.FindStringSubmatch(str); len(match) > 0 {
*is = InterpolatedString(os.Getenv(match[1]))
} else {
*is = InterpolatedString(str)
}
*is = InterpolatedString(interpolateEnv(str))
return nil
}
@ -39,9 +69,7 @@ func (ii *InterpolatedInt) UnmarshalYAML(value *yaml.Node) error {
return errors.Wrapf(err, "could not decode value '%v' (line '%d') into string", value.Value, value.Line)
}
if match := reVar.FindStringSubmatch(str); len(match) > 0 {
str = os.Getenv(match[1])
}
str = interpolateEnv(str)
intVal, err := strconv.ParseInt(str, 10, 32)
if err != nil {
@ -62,9 +90,7 @@ func (ib *InterpolatedBool) UnmarshalYAML(value *yaml.Node) error {
return errors.Wrapf(err, "could not decode value '%v' (line '%d') into string", value.Value, value.Line)
}
if match := reVar.FindStringSubmatch(str); len(match) > 0 {
str = os.Getenv(match[1])
}
str = interpolateEnv(str)
boolVal, err := strconv.ParseBool(str)
if err != nil {
@ -91,9 +117,7 @@ func (im *InterpolatedMap) UnmarshalYAML(value *yaml.Node) error {
continue
}
if match := reVar.FindStringSubmatch(strVal); len(match) > 0 {
strVal = os.Getenv(match[1])
}
strVal = interpolateEnv(strVal)
data[key] = strVal
}
@ -113,9 +137,7 @@ func (iss *InterpolatedStringSlice) UnmarshalYAML(value *yaml.Node) error {
}
for index, value := range data {
if match := reVar.FindStringSubmatch(value); len(match) > 0 {
value = os.Getenv(match[1])
}
value = interpolateEnv(value)
data[index] = value
}
@ -134,9 +156,7 @@ func (id *InterpolatedDuration) UnmarshalYAML(value *yaml.Node) error {
return errors.Wrapf(err, "could not decode value '%v' (line '%d') into string", value.Value, value.Line)
}
if match := reVar.FindStringSubmatch(str); len(match) > 0 {
str = os.Getenv(match[1])
}
str = interpolateEnv(str)
duration, err := time.ParseDuration(str)
if err != nil {

View File

@ -0,0 +1,63 @@
package config
import (
"fmt"
"testing"
)
type interpolateTestCase struct {
String string
Data map[string]string
Expected string
}
var interpolateTestCases = []interpolateTestCase{
{
String: "${foo}",
Data: map[string]string{
"foo": "bar",
},
Expected: "bar",
},
{
String: "${hello:-world}",
Data: map[string]string{},
Expected: "world",
},
{
String: "${hello:-}",
Data: map[string]string{},
Expected: "${hello:-}",
},
{
String: "foo",
Data: map[string]string{},
Expected: "foo",
},
{
String: "",
Data: map[string]string{},
Expected: "",
},
}
func TestInterpolate(t *testing.T) {
for idx, tc := range interpolateTestCases {
func(idx int, tc interpolateTestCase) {
t.Run(fmt.Sprintf("Case_%d", idx), func(t *testing.T) {
result := interpolate(tc.String, func(name string) string {
value, exists := tc.Data[name]
if !exists {
return ""
}
return value
})
if e, g := tc.Expected, result; e != g {
t.Errorf("result: expected '%v', got '%v'", tc.Expected, result)
}
})
}(idx, tc)
}
}

18
internal/config/sentry.go Normal file
View File

@ -0,0 +1,18 @@
package config
import (
"os"
)
type SentryConfig struct {
DSN InterpolatedString `yaml:"dsn"`
Environment InterpolatedString `yaml:"environment"`
}
func NewDefaultSentryConfig() SentryConfig {
hostname, _ := os.Hostname()
return SentryConfig{
DSN: "",
Environment: InterpolatedString(hostname),
}
}

View File

@ -5,6 +5,7 @@ import (
"database/sql"
"encoding/json"
"fmt"
"strings"
"time"
"forge.cadoles.com/Cadoles/emissary/internal/datastore"
@ -15,12 +16,13 @@ import (
)
type AgentRepository struct {
db *sql.DB
db *sql.DB
sqliteBusyRetryMaxAttempts int
}
// DeleteSpec implements datastore.AgentRepository.
func (r *AgentRepository) DeleteSpec(ctx context.Context, agentID datastore.AgentID, name string) error {
err := r.withTx(ctx, func(tx *sql.Tx) error {
err := r.withTxRetry(ctx, func(tx *sql.Tx) error {
exists, err := r.agentExists(ctx, tx, agentID)
if err != nil {
return errors.WithStack(err)
@ -49,7 +51,7 @@ func (r *AgentRepository) DeleteSpec(ctx context.Context, agentID datastore.Agen
func (r *AgentRepository) GetSpecs(ctx context.Context, agentID datastore.AgentID) ([]*datastore.Spec, error) {
specs := make([]*datastore.Spec, 0)
err := r.withTx(ctx, func(tx *sql.Tx) error {
err := r.withTxRetry(ctx, func(tx *sql.Tx) error {
exists, err := r.agentExists(ctx, tx, agentID)
if err != nil {
return errors.WithStack(err)
@ -72,7 +74,8 @@ func (r *AgentRepository) GetSpecs(ctx context.Context, agentID datastore.AgentI
defer func() {
if err := rows.Close(); err != nil {
logger.Error(ctx, "could not close rows", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "could not close rows", logger.CapturedE(err))
}
}()
@ -107,7 +110,7 @@ func (r *AgentRepository) GetSpecs(ctx context.Context, agentID datastore.AgentI
func (r *AgentRepository) UpdateSpec(ctx context.Context, agentID datastore.AgentID, name string, revision int, data map[string]any) (*datastore.Spec, error) {
spec := &datastore.Spec{}
err := r.withTx(ctx, func(tx *sql.Tx) error {
err := r.withTxRetry(ctx, func(tx *sql.Tx) error {
exists, err := r.agentExists(ctx, tx, agentID)
if err != nil {
return errors.WithStack(err)
@ -166,7 +169,7 @@ func (r *AgentRepository) Query(ctx context.Context, opts ...datastore.AgentQuer
agents := make([]*datastore.Agent, 0)
count := 0
err := r.withTx(ctx, func(tx *sql.Tx) error {
err := r.withTxRetry(ctx, func(tx *sql.Tx) error {
query := `SELECT id, label, thumbprint, status, contacted_at, created_at, updated_at FROM agents`
limit := 10
@ -219,14 +222,15 @@ func (r *AgentRepository) Query(ctx context.Context, opts ...datastore.AgentQuer
logger.Debug(ctx, "executing query", logger.F("query", query), logger.F("args", args))
rows, err := r.db.QueryContext(ctx, query, args...)
rows, err := tx.QueryContext(ctx, query, args...)
if err != nil {
return errors.WithStack(err)
}
defer func() {
if err := rows.Close(); err != nil {
logger.Error(ctx, "could not close rows", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "could not close rows", logger.CapturedE(err))
}
}()
@ -270,7 +274,7 @@ func (r *AgentRepository) Query(ctx context.Context, opts ...datastore.AgentQuer
func (r *AgentRepository) Create(ctx context.Context, thumbprint string, keySet jwk.Set, metadata map[string]any) (*datastore.Agent, error) {
agent := &datastore.Agent{}
err := r.withTx(ctx, func(tx *sql.Tx) error {
err := r.withTxRetry(ctx, func(tx *sql.Tx) error {
query := `SELECT count(id) FROM agents WHERE thumbprint = $1`
row := tx.QueryRowContext(ctx, query, thumbprint)
@ -329,15 +333,15 @@ func (r *AgentRepository) Create(ctx context.Context, thumbprint string, keySet
// Delete implements datastore.AgentRepository
func (r *AgentRepository) Delete(ctx context.Context, id datastore.AgentID) error {
err := r.withTx(ctx, func(tx *sql.Tx) error {
err := r.withTxRetry(ctx, func(tx *sql.Tx) error {
query := `DELETE FROM agents WHERE id = $1`
_, err := r.db.ExecContext(ctx, query, id)
_, err := tx.ExecContext(ctx, query, id)
if err != nil {
return errors.WithStack(err)
}
query = `DELETE FROM specs WHERE agent_id = $1`
_, err = r.db.ExecContext(ctx, query, id)
_, err = tx.ExecContext(ctx, query, id)
if err != nil {
return errors.WithStack(err)
}
@ -357,14 +361,14 @@ func (r *AgentRepository) Get(ctx context.Context, id datastore.AgentID) (*datas
ID: id,
}
err := r.withTx(ctx, func(tx *sql.Tx) error {
err := r.withTxRetry(ctx, func(tx *sql.Tx) error {
query := `
SELECT "id", "label", "thumbprint", "keyset", "metadata", "status", "contacted_at", "created_at", "updated_at"
FROM agents
WHERE id = $1
`
row := r.db.QueryRowContext(ctx, query, id)
row := tx.QueryRowContext(ctx, query, id)
metadata := JSONMap{}
contactedAt := sql.NullTime{}
@ -408,7 +412,7 @@ func (r *AgentRepository) Update(ctx context.Context, id datastore.AgentID, opts
agent := &datastore.Agent{}
err := r.withTx(ctx, func(tx *sql.Tx) error {
err := r.withTxRetry(ctx, func(tx *sql.Tx) error {
query := `
UPDATE agents SET id = $1
`
@ -532,6 +536,59 @@ func (r *AgentRepository) agentExists(ctx context.Context, tx *sql.Tx, agentID d
return true, nil
}
func (r *AgentRepository) withTxRetry(ctx context.Context, fn func(*sql.Tx) error) error {
attempts := 0
max := r.sqliteBusyRetryMaxAttempts
ctx = logger.With(ctx, logger.F("max", max))
var err error
for {
ctx = logger.With(ctx)
if attempts >= max {
logger.Debug(ctx, "transaction retrying failed", logger.F("attempts", attempts))
return errors.Wrapf(err, "transaction failed after %d attempts", max)
}
err = r.withTx(ctx, fn)
if err != nil {
if !strings.Contains(err.Error(), "(5) (SQLITE_BUSY)") {
return errors.WithStack(err)
}
err = errors.WithStack(err)
logger.Warn(ctx, "database is busy", logger.E(err))
wait := time.Duration(8<<(attempts+1)) * time.Millisecond
logger.Debug(
ctx, "database is busy, waiting before retrying transaction",
logger.F("wait", wait.String()),
logger.F("attempts", attempts),
)
timer := time.NewTimer(wait)
select {
case <-timer.C:
attempts++
continue
case <-ctx.Done():
if err := ctx.Err(); err != nil {
return errors.WithStack(err)
}
return nil
}
}
return nil
}
}
func (r *AgentRepository) withTx(ctx context.Context, fn func(*sql.Tx) error) error {
tx, err := r.db.BeginTx(ctx, nil)
if err != nil {
@ -544,7 +601,8 @@ func (r *AgentRepository) withTx(ctx context.Context, fn func(*sql.Tx) error) er
return
}
logger.Error(ctx, "could not rollback transaction", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "could not rollback transaction", logger.CapturedE(err))
}
}()
@ -559,8 +617,8 @@ func (r *AgentRepository) withTx(ctx context.Context, fn func(*sql.Tx) error) er
return nil
}
func NewAgentRepository(db *sql.DB) *AgentRepository {
return &AgentRepository{db}
func NewAgentRepository(db *sql.DB, sqliteBusyRetryMaxAttempts int) *AgentRepository {
return &AgentRepository{db, sqliteBusyRetryMaxAttempts}
}
var _ datastore.AgentRepository = &AgentRepository{}

View File

@ -40,7 +40,7 @@ func TestSQLiteAgentRepository(t *testing.T) {
t.Fatalf("%+v", errors.WithStack(err))
}
repo := NewAgentRepository(db)
repo := NewAgentRepository(db, 5)
testsuite.TestAgentRepository(t, repo)
}

View File

@ -9,7 +9,7 @@ import (
"forge.cadoles.com/Cadoles/emissary/internal/agent/metadata"
"forge.cadoles.com/Cadoles/emissary/internal/datastore"
"forge.cadoles.com/Cadoles/emissary/internal/jwk"
"github.com/go-chi/chi"
"github.com/go-chi/chi/v5"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/api"
"gitlab.com/wpetit/goweb/logger"
@ -39,7 +39,8 @@ func (s *Server) registerAgent(w http.ResponseWriter, r *http.Request) {
keySet, err := jwk.Parse(registerAgentReq.KeySet)
if err != nil {
logger.Error(ctx, "could not parse key set", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "could not parse key set", logger.CapturedE(err))
api.ErrorResponse(w, http.StatusInternalServerError, ErrCodeUnknownError, nil)
return
@ -51,14 +52,15 @@ func (s *Server) registerAgent(w http.ResponseWriter, r *http.Request) {
validSignature, err := jwk.Verify(keySet, registerAgentReq.Signature, registerAgentReq.Thumbprint, registerAgentReq.Metadata)
if err != nil {
logger.Error(ctx, "could not validate signature", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "could not validate signature", logger.CapturedE(err))
api.ErrorResponse(w, http.StatusInternalServerError, ErrCodeUnknownError, nil)
return
}
if !validSignature {
logger.Error(ctx, "conflicting signature", logger.F("signature", registerAgentReq.Signature))
logger.Warn(ctx, "conflicting signature", logger.F("signature", registerAgentReq.Signature))
api.ErrorResponse(w, http.StatusConflict, ErrCodeConflict, nil)
return
@ -74,7 +76,8 @@ func (s *Server) registerAgent(w http.ResponseWriter, r *http.Request) {
)
if err != nil {
if !errors.Is(err, datastore.ErrAlreadyExist) {
logger.Error(ctx, "could not create agent", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "could not create agent", logger.CapturedE(err))
api.ErrorResponse(w, http.StatusInternalServerError, ErrCodeUnknownError, nil)
return
@ -86,15 +89,16 @@ func (s *Server) registerAgent(w http.ResponseWriter, r *http.Request) {
datastore.WithAgentQueryLimit(1),
)
if err != nil {
logger.Error(ctx, "could not retrieve agents", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "could not retrieve agents", logger.CapturedE(err))
api.ErrorResponse(w, http.StatusInternalServerError, ErrCodeUnknownError, nil)
return
}
if len(agents) == 0 {
logger.Error(ctx, "could not retrieve matching agent", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "could not retrieve matching agent", logger.CapturedE(err))
api.ErrorResponse(w, http.StatusInternalServerError, ErrCodeNotFound, nil)
return
@ -104,10 +108,12 @@ func (s *Server) registerAgent(w http.ResponseWriter, r *http.Request) {
agent, err = s.agentRepo.Get(ctx, agentID)
if err != nil {
err = errors.WithStack(err)
logger.Error(
ctx, "could not retrieve agent",
logger.E(errors.WithStack(err)), logger.F("agentID", agentID),
logger.CapturedE(err), logger.F("agentID", agentID),
)
api.ErrorResponse(w, http.StatusInternalServerError, ErrCodeUnknownError, nil)
return
@ -115,7 +121,8 @@ func (s *Server) registerAgent(w http.ResponseWriter, r *http.Request) {
validSignature, err = jwk.Verify(agent.KeySet.Set, registerAgentReq.Signature, registerAgentReq.Thumbprint, registerAgentReq.Metadata)
if err != nil {
logger.Error(ctx, "could not validate signature using previous keyset", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "could not validate signature using previous keyset", logger.CapturedE(err))
api.ErrorResponse(w, http.StatusConflict, ErrCodeConflict, nil)
@ -129,7 +136,9 @@ func (s *Server) registerAgent(w http.ResponseWriter, r *http.Request) {
datastore.WithAgentUpdateThumbprint(registerAgentReq.Thumbprint),
)
if err != nil {
logger.Error(ctx, "could not update agent", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "could not update agent", logger.CapturedE(err))
api.ErrorResponse(w, http.StatusInternalServerError, ErrCodeUnknownError, nil)
return
@ -177,7 +186,8 @@ func (s *Server) updateAgent(w http.ResponseWriter, r *http.Request) {
options...,
)
if err != nil {
logger.Error(ctx, "could not update agent", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "could not update agent", logger.CapturedE(err))
api.ErrorResponse(w, http.StatusInternalServerError, ErrCodeUnknownError, nil)
return
@ -258,7 +268,8 @@ func (s *Server) queryAgents(w http.ResponseWriter, r *http.Request) {
options...,
)
if err != nil {
logger.Error(ctx, "could not list agents", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "could not list agents", logger.CapturedE(err))
api.ErrorResponse(w, http.StatusInternalServerError, ErrCodeUnknownError, nil)
return
@ -292,7 +303,8 @@ func (s *Server) deleteAgent(w http.ResponseWriter, r *http.Request) {
return
}
logger.Error(ctx, "could not delete agent", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "could not delete agent", logger.CapturedE(err))
api.ErrorResponse(w, http.StatusInternalServerError, ErrCodeUnknownError, nil)
return
@ -324,7 +336,8 @@ func (s *Server) getAgent(w http.ResponseWriter, r *http.Request) {
return
}
logger.Error(ctx, "could not get agent", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "could not get agent", logger.CapturedE(err))
api.ErrorResponse(w, http.StatusInternalServerError, ErrCodeUnknownError, nil)
return
@ -342,7 +355,7 @@ func getAgentID(w http.ResponseWriter, r *http.Request) (datastore.AgentID, bool
agentID, err := strconv.ParseInt(rawAgentID, 10, 64)
if err != nil {
logger.Error(r.Context(), "could not parse agent id", logger.E(errors.WithStack(err)))
logger.Error(r.Context(), "could not parse agent id", logger.CapturedE(errors.WithStack(err)))
api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeMalformedRequest, nil)
return 0, false
@ -356,7 +369,8 @@ func getIntQueryParam(w http.ResponseWriter, r *http.Request, param string, defa
if rawValue != "" {
value, err := strconv.ParseInt(rawValue, 10, 64)
if err != nil {
logger.Error(r.Context(), "could not parse int param", logger.F("param", param), logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(r.Context(), "could not parse int param", logger.F("param", param), logger.CapturedE(err))
api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeMalformedRequest, nil)
return 0, false
@ -389,7 +403,8 @@ func getIntSliceValues(w http.ResponseWriter, r *http.Request, param string, def
for _, rv := range rawValues {
value, err := strconv.ParseInt(rv, 10, 64)
if err != nil {
logger.Error(r.Context(), "could not parse int slice param", logger.F("param", param), logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(r.Context(), "could not parse int slice param", logger.F("param", param), logger.CapturedE(err))
api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeMalformedRequest, nil)
return nil, false

View File

@ -124,7 +124,8 @@ func assertRequestUser(w http.ResponseWriter, r *http.Request) (auth.User, bool)
ctx := r.Context()
user, err := auth.CtxUser(ctx)
if err != nil {
logger.Error(ctx, "could not retrieve user", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "could not retrieve user", logger.CapturedE(err))
forbidden(w, r)
@ -147,7 +148,7 @@ func forbidden(w http.ResponseWriter, r *http.Request) {
}
func logUnexpectedUserType(ctx context.Context, user auth.User) {
logger.Error(
logger.Warn(
ctx, "unexpected user type",
logger.F("subject", user.Subject()),
logger.F("type", fmt.Sprintf("%T", user)),

View File

@ -18,8 +18,8 @@ import (
"forge.cadoles.com/Cadoles/emissary/internal/jwk"
"github.com/antonmedv/expr"
"github.com/antonmedv/expr/vm"
"github.com/go-chi/chi"
"github.com/go-chi/chi/middleware"
"github.com/go-chi/chi/v5"
"github.com/go-chi/chi/v5/middleware"
"github.com/go-chi/cors"
"github.com/lestrrat-go/jwx/v2/jwa"
"github.com/lestrrat-go/jwx/v2/jwt"

View File

@ -6,7 +6,7 @@ import (
"forge.cadoles.com/Cadoles/emissary/internal/datastore"
"forge.cadoles.com/Cadoles/emissary/internal/spec"
"github.com/go-chi/chi"
"github.com/go-chi/chi/v5"
"github.com/pkg/errors"
"gitlab.com/wpetit/goweb/api"
"gitlab.com/wpetit/goweb/logger"
@ -44,7 +44,9 @@ func (s *Server) updateSpec(w http.ResponseWriter, r *http.Request) {
data.Message = validationErr.Error()
}
logger.Error(ctx, "could not validate spec", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "could not validate spec", logger.CapturedE(err))
api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeInvalidRequest, data)
return
@ -70,7 +72,9 @@ func (s *Server) updateSpec(w http.ResponseWriter, r *http.Request) {
return
}
logger.Error(ctx, "could not update spec", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "could not update spec", logger.CapturedE(err))
api.ErrorResponse(w, http.StatusInternalServerError, ErrCodeUnknownError, nil)
return
@ -99,7 +103,9 @@ func (s *Server) getAgentSpecs(w http.ResponseWriter, r *http.Request) {
return
}
logger.Error(ctx, "could not list specs", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "could not list specs", logger.CapturedE(err))
api.ErrorResponse(w, http.StatusInternalServerError, ErrCodeUnknownError, nil)
return
@ -141,7 +147,9 @@ func (s *Server) deleteSpec(w http.ResponseWriter, r *http.Request) {
return
}
logger.Error(ctx, "could not delete spec", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(ctx, "could not delete spec", logger.CapturedE(err))
api.ErrorResponse(w, http.StatusInternalServerError, ErrCodeUnknownError, nil)
return
@ -159,7 +167,9 @@ func getSpecID(w http.ResponseWriter, r *http.Request) (datastore.SpecID, bool)
specID, err := strconv.ParseInt(rawSpecID, 10, 64)
if err != nil {
logger.Error(r.Context(), "could not parse spec id", logger.E(errors.WithStack(err)))
err = errors.WithStack(err)
logger.Error(r.Context(), "could not parse spec id", logger.CapturedE(err))
api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeMalformedRequest, nil)
return 0, false

View File

@ -59,7 +59,7 @@ func NewAgentRepository(ctx context.Context, conf config.DatabaseConfig) (datast
return nil, errors.WithStack(err)
}
agentRepository = sqlite.NewAgentRepository(db)
agentRepository = sqlite.NewAgentRepository(db, 5)
default:
return nil, errors.Errorf("unsupported database driver '%s'", driver)

32
misc/docker/agent.yml Normal file
View File

@ -0,0 +1,32 @@
logger:
level: ${EMISSARY_AGENT_LOGGER_LEVEL:-1}
format: ${EMISSARY_AGENT_LOGGER_FORMAT:-human}
sentry:
dsn: ${EMISSARY_AGENT_SENTRY_DSN}
agent:
serverUrl: ${EMISSARY_AGENT_SERVER_URL:-http://127.0.0.1:3000}
privateKeyPath: ${EMISSARY_AGENT_PRIVATE_KEY_PATH:-/data/agent-key.json}
reconciliationInterval: ${EMISSARY_AGENT_RECONCILIATION_INTERVAL:-30}
controllers:
persistence:
enabled: true
stateFile: ${EMISSARY_AGENT_CONTROLLERS_PERSISTENCE_STATE_FILE:-/data/state.json}
spec:
enabled: true
proxy:
enabled: true
uci:
enabled: false
app:
enabled: true
dataDir: ${EMISSARY_AGENT_CONTROLLERS_APP_DATA_DIR:-/data/apps/data}
downloadDir: ${EMISSARY_AGENT_CONTROLLERS_APP_DOWNLOAD_DIR:-/data/apps/bundles}
sysupgrade:
enabled: false
mdns:
enabled: true
collectors:
- name: uname
command: uname
args:
- -a

View File

@ -0,0 +1,10 @@
#!/bin/sh
set -e
# Generate machine id if not exists
if [ ! -f /etc/machine-id ]; then
cat /proc/sys/kernel/random/uuid > /etc/machine-id
fi
exec $@

35
misc/docker/server.yml Normal file
View File

@ -0,0 +1,35 @@
logger:
level: ${EMISSARY_SERVER_LOGGER_LEVEL:-1}
format: ${EMISSARY_SERVER_LOGGER_FORMAT:-human}
sentry:
dsn: ${EMISSARY_SERVER_SENTRY_DSN}
server:
http:
host: ${EMISSARY_SERVER_HTTP_HOST:-0.0.0.0}
port: ${EMISSARY_SERVER_HTTP_HOST:-3000}
database:
driver: ${EMISSARY_SERVER_DATABASE_DRIVER:-sqlite}
dsn: ${EMISSARY_SERVER_DATABASE_DSN:-sqlite:///data/emissary.sqlite?_pragma=foreign_keys(1)&_pragma=busy_timeout=150000&_pragma=journal_mode=WAL}
cors:
allowedOrigins:
- ${EMISSARY_SERVER_CORS_ALLOWED_ORIGINS:-http://localhost:3001}
allowCredentials: ${EMISSARY_SERVER_CORS_ALLOW_CREDENTIALS:-true}
allowMethods:
- POST
- GET
- PUT
- DELETE
allowedHeaders:
- Origin
- Accept
- Content-Type
- Authorization
- Sentry-Trace
debug: ${EMISSARY_SERVER_CORS_DEBUG:-false}
auth:
local:
privateKeyPath: ${EMISSARY_SERVER_AUTH_LOCAL_PRIVATE_KEY_PATH:-/data/server-key.json}
remote:
jwksUrl: "${EMISSARY_SERVER_AUTH_REMOTE_JWKS_URL}"
roleExtractionRules:
- "${EMISSARY_SERVER_AUTH_ROLE_EXTRACTION_RULES_0:-jwt.role != nil ? str(jwt.role) : ''}"

View File

@ -1,6 +1,8 @@
/var/log/emissary/agent.log {
missingok
sharedscripts
compress
rotate 7
postrotate
/etc/init.d/emissary-agent restart
endscript

View File

@ -1,6 +1,8 @@
/var/log/emissary/server.log {
missingok
sharedscripts
compress
rotate 7
postrotate
/etc/init.d/emissary-server restart
endscript

View File

@ -12,8 +12,8 @@
}
},
"edge.sdk.client.test": {
"url": "https://emissary.cadol.es/files/apps/edge.sdk.client.test_v2023.4.20-20c4189.zip",
"sha256sum": "1edeb4aa75c1675db49cf27367b1537234a04526848ea6657931ca63f26e5dae",
"url": "https://emissary.cadol.es/files/apps/edge.sdk.client.test_2023.10.22-stable.847.22a3326.zip",
"sha256sum": "37aa6c4af57b647dc5cae4ec7d36f4289d99c1f090e533997e0d59188a0a04f4",
"address": ":8084",
"format": "zip",
"storage": {
@ -21,13 +21,23 @@
"shareStoreDsn": "sqlite://apps/data/sharestore.sqlite?_pragma=foreign_keys(1)&_pragma=busy_timeout=60000",
"documentStoreDsn": "sqlite://apps/data/edge.sdk.client.test/documentstore.sqlite?_pragma=foreign_keys(1)&_pragma=busy_timeout=60000"
}
},
"arcad.diffusion": {
"url": "https://emissary.cadol.es/files/apps/arcad.diffusion_v2023.10.12-cab0070.zip",
"sha256sum": "db58ec1ed463092fea2ee27cfd33dea5259739f1c6a4c9bf909ffd22392ee449",
"address": ":8085",
"format": "zip",
"storage": {
"blobStoreDsn": "sqlite://apps/data/arcad.diffusion/blobstore.sqlite?_pragma=foreign_keys(1)&_pragma=busy_timeout=60000",
"shareStoreDsn": "sqlite://apps/data/sharestore.sqlite?_pragma=foreign_keys(1)&_pragma=busy_timeout=60000",
"documentStoreDsn": "sqlite://apps/data/arcad.diffusion/documentstore.sqlite?_pragma=foreign_keys(1)&_pragma=busy_timeout=60000"
}
}
},
"config": {
"appUrlResolving": {
"ifaceMappings": {
"eth0": "http://{{ .DeviceIP }}:{{ .AppPort }}",
"eth1": "http://{{ .DeviceIP }}:{{ .AppPort }}"
"lo": "http://{{ .DeviceIP }}:{{ .AppPort }}"
},
"defaultUrlTemplate": "http://{{ last ( splitList \".\" ( toString .Manifest.ID ) ) }}.localhost.arcad.lan:8080"
},

View File

@ -14,6 +14,11 @@
"type": "_http._tcp",
"port": 8080,
"host": "arcad-test"
},
"diffusion": {
"type": "_http._tcp",
"port": 8080,
"host": "arcad-diffusion"
}
}
}

View File

@ -11,6 +11,10 @@
"hostPattern": "test.localhost.arcad.lan:*",
"target": "http://localhost:8084"
},
{
"hostPattern": "diffusion.localhost.arcad.lan:*",
"target": "http://localhost:8085"
},
{
"hostPattern": "arcad-hextris.local:*",
"target": "http://localhost:8083"
@ -19,6 +23,10 @@
"hostPattern": "arcad-test.local:*",
"target": "http://localhost:8084"
},
{
"hostPattern": "arcad-diffusion.local:*",
"target": "http://localhost:8085"
},
{
"hostPattern": "*",
"target": "http://localhost:8084"

View File

@ -2063,10 +2063,5 @@
}
]
},
"postImportCommands": [
{
"args": [],
"command": "reload_config"
}
]
"postImportCommands": []
}