Compare commits
59 Commits
feature/te
...
develop
Author | SHA1 | Date |
---|---|---|
wpetit | 85ccf2e1df | |
wpetit | cec5c783fe | |
wpetit | b5c36f1f17 | |
wpetit | f612721b4e | |
wpetit | 0b34b485da | |
wpetit | ab08d30d2a | |
wpetit | f6ffb68c43 | |
wpetit | 4a1a434556 | |
wpetit | 76718722cc | |
wpetit | 8f2131338d | |
wpetit | 56558d7241 | |
wpetit | eee7e60a86 | |
wpetit | 954597d241 | |
wpetit | e0cde4519f | |
wpetit | 8438c4bc1a | |
wpetit | df1a586d38 | |
wpetit | c851a1f51b | |
wpetit | 15a0bf6ecc | |
wpetit | ca4211daef | |
wpetit | 79f53010a0 | |
wpetit | a5c81dc4b4 | |
wpetit | fefac830fd | |
wpetit | c43d1a5da6 | |
wpetit | 3f200e1674 | |
wpetit | d9f11ac877 | |
wpetit | 16a59fe027 | |
wpetit | 8d42bf0b34 | |
wpetit | 3c3d7fe82d | |
wpetit | ddddbbc895 | |
wpetit | 32ce5a206f | |
wpetit | 6a7945d05c | |
wpetit | 86ddb6a4c1 | |
wpetit | a6da1be3bf | |
wpetit | 5c2d128e8c | |
wpetit | 144fdd8bf3 | |
wpetit | 8b33bacbd5 | |
wpetit | b842dd5263 | |
wpetit | 0c9d86b850 | |
wpetit | b2b839cab4 | |
wpetit | 7fa3011ab2 | |
wpetit | 17e06ce19b | |
wpetit | 0d2aac41a8 | |
wpetit | 38795a9767 | |
wpetit | 327226aa74 | |
wpetit | fbf818e423 | |
wpetit | 46a853a3f7 | |
wpetit | f31a63efdc | |
wpetit | c8a2303ff3 | |
wpetit | ced2658eec | |
wpetit | ce9b3003fe | |
wpetit | b0898eefc3 | |
wpetit | 4da723e908 | |
wpetit | e756a60373 | |
wpetit | 9068203e71 | |
wpetit | a84fa05c27 | |
wpetit | 6c78bc5c7c | |
wpetit | 75cab3264f | |
wpetit | 1a270fa4d8 | |
wpetit | 6318a8b497 |
|
@ -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
|
|
@ -10,6 +10,8 @@ dist/
|
|||
/apps
|
||||
/server-key.json
|
||||
/.emissary-token
|
||||
/.emissary-admin-token
|
||||
/.emissary-tenant
|
||||
/out
|
||||
.mktools/
|
||||
/CHANGELOG.md
|
||||
|
|
|
@ -105,6 +105,9 @@ nfpms:
|
|||
file_info:
|
||||
mode: 0755
|
||||
packager: apk
|
||||
- src: misc/packaging/openrc/emissary-server.logrotate.conf
|
||||
dst: /etc/logrotate.d/emissary-server
|
||||
packager: apk
|
||||
- dst: /var/lib/emissary
|
||||
type: dir
|
||||
file_info:
|
||||
|
@ -147,5 +150,8 @@ nfpms:
|
|||
file_info:
|
||||
mode: 0755
|
||||
packager: apk
|
||||
- src: misc/packaging/openrc/emissary-agent.logrotate.conf
|
||||
dst: /etc/logrotate.d/emissary-agent
|
||||
packager: apk
|
||||
scripts:
|
||||
postinstall: "misc/packaging/common/postinstall-agent.sh"
|
||||
|
|
58
Dockerfile
58
Dockerfile
|
@ -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" ]
|
55
Makefile
55
Makefile
|
@ -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
|
||||
|
@ -16,6 +15,13 @@ OPENWRT_DEVICE ?= 192.168.1.1
|
|||
watch: deps ## Watching updated files - live reload
|
||||
( set -o allexport && source .env && set +o allexport && go run -mod=readonly github.com/cortesi/modd/cmd/modd@latest )
|
||||
|
||||
clean:
|
||||
rm -f .emissary-*
|
||||
rm -f emissary.sqlite*
|
||||
rm -f server-key.json
|
||||
rm -f agent-key.json
|
||||
rm -f state.json
|
||||
|
||||
.PHONY: test
|
||||
test: test-go ## Executing tests
|
||||
|
||||
|
@ -71,17 +77,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
|
||||
|
@ -117,22 +129,33 @@ gitea-release: .mktools tools/gitea-release/bin/gitea-release.sh goreleaser chan
|
|||
GITEA_RELEASE_ATTACHMENTS="$$(find .gitea-release/* -type f)" \
|
||||
tools/gitea-release/bin/gitea-release.sh
|
||||
|
||||
.emissary-token:
|
||||
$(MAKE) run-emissary-server EMISSARY_CMD="--debug --config tmp/server.yml server auth create-token --role writer --output .emissary-token"
|
||||
.emissary-tenant: .emissary-admin-token
|
||||
$(MAKE) run-emissary-server EMISSARY_CMD="--debug --config tmp/server.yml client tenant create --token-file .emissary-admin-token --tenant-label Dev -f json | jq -r '.[0].id' > .emissary-tenant"
|
||||
|
||||
.emissary-admin-token:
|
||||
$(MAKE) run-emissary-server EMISSARY_CMD="--debug --config tmp/server.yml server auth create-token --role admin --output .emissary-admin-token"
|
||||
|
||||
.emissary-token: .emissary-tenant
|
||||
$(MAKE) run-emissary-server EMISSARY_CMD="--debug --config tmp/server.yml server auth create-token --role writer --output .emissary-token --tenant $(shell cat .emissary-tenant)"
|
||||
|
||||
AGENT_ID ?= 1
|
||||
|
||||
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
|
||||
claim-agent: .emissary-token
|
||||
$(MAKE) run-emissary-server EMISSARY_CMD="--debug --config tmp/server.yml client agent claim --agent-thumbprint $(shell go run ./cmd/agent agent show-thumbprint)"
|
||||
|
||||
load-sample-specs: .emissary-token
|
||||
cat misc/spec-samples/app.emissary.cadoles.com.json | $(MAKE) run-emissary-server EMISSARY_CMD="--debug --config tmp/server.yml client 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 | $(MAKE) run-emissary-server EMISSARY_CMD="--debug --config tmp/server.yml client 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 | $(MAKE) run-emissary-server EMISSARY_CMD="--debug --config tmp/server.yml client 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 | $(MAKE) run-emissary-server EMISSARY_CMD="--debug --config tmp/server.yml client 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
|
||||
|
|
34
README.md
34
README.md
|
@ -6,6 +6,40 @@ Control plane for "edge" (and OpenWRT-based) devices.
|
|||
|
||||
> ⚠ Emissary is currently in a very alpha stage ! Expect breaking changes...
|
||||
|
||||
## Quickstart
|
||||
|
||||
**Dependencies**
|
||||
- [Go >= 1.21](https://go.dev/)
|
||||
- `GNU Make`
|
||||
|
||||
```shell
|
||||
# Start server and a local agent
|
||||
make watch
|
||||
|
||||
# In an other terminal
|
||||
|
||||
# Create an admin token
|
||||
make .emissary-admin-token
|
||||
|
||||
# Create a new tenant
|
||||
make .emissary-tenant
|
||||
|
||||
# Create a new writer token for this tenant
|
||||
make .emissary-token
|
||||
|
||||
# Claim the agent for your newly created tenant
|
||||
make claim-agent
|
||||
|
||||
# Query your agents
|
||||
./bin/server client agent query
|
||||
|
||||
# Load sample specs for your agent
|
||||
make load-sample-specs
|
||||
|
||||
## Optional: reset your workspace
|
||||
make clean
|
||||
```
|
||||
|
||||
## Install
|
||||
|
||||
### Manually
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/agent"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/api"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/client"
|
||||
|
||||
_ "forge.cadoles.com/Cadoles/emissary/internal/imports/format"
|
||||
_ "forge.cadoles.com/Cadoles/emissary/internal/imports/spec"
|
||||
|
@ -20,5 +20,5 @@ var (
|
|||
)
|
||||
|
||||
func main() {
|
||||
command.Main(BuildDate, ProjectVersion, GitRef, DefaultConfigPath, agent.Root(), api.Root())
|
||||
command.Main(BuildDate, ProjectVersion, GitRef, DefaultConfigPath, agent.Root(), client.Root())
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ import (
|
|||
"time"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/api"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/client"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/server"
|
||||
|
||||
_ "forge.cadoles.com/Cadoles/emissary/internal/imports/format"
|
||||
|
@ -21,5 +21,5 @@ var (
|
|||
)
|
||||
|
||||
func main() {
|
||||
command.Main(BuildDate, ProjectVersion, GitRef, DefaultConfigPath, server.Root(), api.Root())
|
||||
command.Main(BuildDate, ProjectVersion, GitRef, DefaultConfigPath, server.Root(), client.Root())
|
||||
}
|
||||
|
|
|
@ -1,22 +1,22 @@
|
|||
# Documentation
|
||||
|
||||
- (FR) - [Introduction](./fr/introduction.md)
|
||||
- (FR) - [Vue d'ensemble](./others/fr/overview.md)
|
||||
- (FR) - [Authentification et autorisation](./others/fr/auth.md)
|
||||
|
||||
## Tutorials
|
||||
|
||||
- (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)
|
||||
|
||||
## References
|
||||
- (FR) - [Démarrer un agent avec Docker](./tutorials/fr/docker-agent.md)
|
||||
|
||||
### Specifications
|
||||
|
||||
- [Schéma `app.emissary.cadoles.com`](../internal/agent/controller/app/spec/schema.json)
|
||||
- [Schéma `proxy.emissary.cadoles.com`](../internal/spec/proxy/schema.json)
|
||||
- [Schéma `mdns.emissary.cadoles.com`](../internal/agent/controller/mdns/spec/schema.json)
|
||||
- [Schéma `uci.emissary.cadoles.com`](../internal/spec/uci/schema.json)
|
||||
- [Schéma `sysupgrade.openwrt.emissary.cadoles.com`](../internal/agent/controller/openwrt/spec/sysupgrade/schema.json)
|
||||
- [Schema `app.emissary.cadoles.com`](../internal/agent/controller/app/spec/schema.json)
|
||||
- [Schema `proxy.emissary.cadoles.com`](../internal/spec/proxy/schema.json)
|
||||
- [Schema `mdns.emissary.cadoles.com`](../internal/agent/controller/mdns/spec/schema.json)
|
||||
- [Schema `uci.emissary.cadoles.com`](../internal/spec/uci/schema.json)
|
||||
- [Schema `sysupgrade.openwrt.emissary.cadoles.com`](../internal/agent/controller/openwrt/spec/sysupgrade/schema.json)
|
||||
|
||||
### Configuration
|
||||
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
# Authentification et autorisation
|
||||
|
||||
## Authentification
|
||||
|
||||
Emissary utilise des [**JSON Web Token**](https://fr.wikipedia.org/wiki/JSON_Web_Token) (JWT) afin d'authentifier les appels à son API REST.
|
||||
|
||||
L'implémentation est compatible avec tout serveur d'authentification exposant une URL proposant un [**JSON Web Key Set**](https://www.ory.sh/docs/hydra/jwks#the-role-of-well-knownjwksjson).
|
||||
|
||||
La plupart des serveurs OpenID Connect exposent un point d'entrée du type [`/.well-known/jwks.json`](https://www.ory.sh/docs/hydra/jwks#the-role-of-well-knownjwksjson) remplissant ce rôle.
|
||||
|
||||
Emissary est également en capacité à fonctionner en mode autonome en générant des JWTs signés par une clé privée locale.
|
||||
|
||||
## Ségrégation des ressources
|
||||
|
||||
Emissary suit une stratégie ["multitenant"](https://fr.wikipedia.org/wiki/Multitenant) de séparer les ressources par organisation.
|
||||
|
||||
Un utilisateur est obligatoirement associé à un `tenant`` et ne peut opérer que sur les ressources associées à celui ci.
|
||||
|
||||
## Autorisation
|
||||
|
||||
Au sein d'un `tenant`, un utilisateur peut avoir un des rôles suivants:
|
||||
|
||||
- `writer` - Autorisé à visualiser et modifier les ressources;
|
||||
- `reader` - Autorisé à visualiser les ressources.
|
||||
|
||||
Un rôle spécial `admin` permet la création et la suppression de `tenants`.
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
# Introduction
|
||||
# Vue d'ensemble
|
||||
|
||||
"Emissary" est un programme entrant dans la catégorie des outils de gestion et déploiement de configuration.
|
||||
|
Before Width: | Height: | Size: 21 KiB After Width: | Height: | Size: 21 KiB |
|
@ -80,13 +80,13 @@ Via la spécification [`uci.emissary.cadoles.com`](../../../internal/spec/uci/sc
|
|||
AGENT_THUMBPRINT="<empreinte agent>"
|
||||
|
||||
# Récupérer l'identifiant de l'agent
|
||||
AGENT_ID=$(emissary api agent query -f json | jq -r --arg thumbprint "$AGENT_THUMBPRINT" '.[] | select(.thumbprint == $thumbprint) | .id')
|
||||
AGENT_ID=$(emissary client agent query -f json | jq -r --arg thumbprint "$AGENT_THUMBPRINT" '.[] | select(.thumbprint == $thumbprint) | .id')
|
||||
```
|
||||
|
||||
2. Assigner la spécification à l'agent UCI:
|
||||
|
||||
```bash
|
||||
cat my-uci-spec.json | emissary api agent spec update -a ${AGENT_ID} --no-patch --spec-data - --spec-name uci.emissary.cadoles.com
|
||||
cat my-uci-spec.json | emissary client agent spec update -a ${AGENT_ID} --no-patch --spec-data - --spec-name uci.emissary.cadoles.com
|
||||
```
|
||||
|
||||
**Bravo, vous avez déployé des spécifications UCI sur votre agent !**
|
||||
|
@ -112,7 +112,7 @@ En intervenant directement sur notre spécification, il est possible de modifier
|
|||
2. Mettre à jour la configuration de l'agent:
|
||||
|
||||
```bash
|
||||
cat my-uci-spec.json | emissary api agent spec update -a ${AGENT_ID} --no-patch --spec-data - --spec-name uci.emissary.cadoles.com
|
||||
cat my-uci-spec.json | emissary client agent spec update -a ${AGENT_ID} --no-patch --spec-data - --spec-name uci.emissary.cadoles.com
|
||||
```
|
||||
|
||||
3. Sur l'agent, après quelques secondes (par défaut, la fréquence de mise à jour est de 1 fois par minute) l'agent devrait avoir son `hostname` mis à jour:
|
||||
|
|
|
@ -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
|
||||
```
|
|
@ -80,15 +80,31 @@
|
|||
5. Créer un jeton d'administration:
|
||||
|
||||
```shell
|
||||
sudo emissary --workdir /usr/share/emissary --config /etc/emissary/server.yml server auth create-token --role writer --subject $(whoami)
|
||||
sudo emissary --workdir /usr/share/emissary --config /etc/emissary/server.yml server auth create-token --role admin -o "$HOME/.config/emissary/admin-token"
|
||||
```
|
||||
|
||||
> **Note** Le jeton sera stocké dans le répertoire `$HOME/.config/emissary`.
|
||||
|
||||
6. Vérifier l'authentification sur l'API:
|
||||
6. Créer un nouveau `tenant`:
|
||||
|
||||
```shell
|
||||
emissary api agent query
|
||||
sudo emissary --workdir /usr/share/emissary --config /etc/emissary/server.yml client tenant create --tenant-label "My Tenant" -o wide --token-file "$HOME/.config/emissary/admin-token"
|
||||
```
|
||||
|
||||
Noter la valeur de l'UUID (de la forme `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`) affiché dans la colonne `ID`. Il sera identifié comme `$EMISSARY_TENANT` dans les étapes suivantes.
|
||||
|
||||
7. Créer un jeton d'authentification pour ce nouveau tenant:
|
||||
|
||||
```shell
|
||||
sudo emissary --workdir /usr/share/emissary --config /etc/emissary/server.yml server auth create-token --role writer --tenant $EMISSARY_TENANT
|
||||
```
|
||||
|
||||
> **Note** Le jeton sera stocké dans le fichier `$HOME/.config/emissary/auth-token`. Il sera le jeton utilisé par défaut par le CLI Emissary.
|
||||
|
||||
8. Vérifier l'authentification sur l'API:
|
||||
|
||||
```shell
|
||||
emissary client agent query
|
||||
```
|
||||
|
||||
Une réponse équivalente à la suivante devrait s'afficher:
|
||||
|
@ -128,10 +144,18 @@
|
|||
Thu May 25 18:48:51 2023 daemon.info emissary[2202]: 2023-05-25 18:48:51.680 [INFO] <./internal/agent/controller/openwrt/sysupgrade_controller.go:36> (*SysUpgradeController).Reconcile could not find sysupgrade spec, doing nothing {"controller": "sysupgrade-controller"}
|
||||
```
|
||||
|
||||
3. Sur le serveur, vérifier que l'agent a pu s'enregistrer:
|
||||
2. Récupérer le `thumbprint` de votre agent:
|
||||
|
||||
```
|
||||
emissary agent show-thumbprint
|
||||
```
|
||||
|
||||
Noter la valeur de la chaîne de caractères affichée. Elle sera identifiée comme `$AGENT_THUMBPRINT` dans les étapes suivantes.
|
||||
|
||||
3. Sur le serveur, "réclamer" votre agent:
|
||||
|
||||
```shell
|
||||
emissary api agent query
|
||||
emissary client agent claim --agent-thumbprint $AGENT_THUMBPRINT
|
||||
```
|
||||
|
||||
Un message de ce type devrait s'afficher:
|
||||
|
@ -144,12 +168,12 @@
|
|||
+----+-------+-----------------------------------+--------+-----------------------------------+-----------------------------------+
|
||||
```
|
||||
|
||||
Noter l'identifiant associé à l'agent.
|
||||
Noter la valeur de l'identifiant affiché dans la colonne `ID`. Il sera identifié comme `$AGENT_ID` dans les étapes suivantes.
|
||||
|
||||
4. Mettre à jour le statut de l'agent afin qu'il soit en capacité à récupérer ses spécifications:
|
||||
|
||||
```
|
||||
emissary api agent update --agent-id <agent_id> --status 1
|
||||
emissary client agent update --agent-id $AGENT_ID --status 1
|
||||
```
|
||||
|
||||
**Bravo, vous avez appairé votre premier agent et son serveur Emissary !**
|
||||
|
|
72
go.mod
72
go.mod
|
@ -1,9 +1,11 @@
|
|||
module forge.cadoles.com/Cadoles/emissary
|
||||
|
||||
go 1.19
|
||||
go 1.21.4
|
||||
|
||||
toolchain go1.21.5
|
||||
|
||||
require (
|
||||
forge.cadoles.com/arcad/edge v0.0.0-20230426135323-17808d14c978
|
||||
forge.cadoles.com/arcad/edge v0.0.0-20240112130429-2fbc7186c077
|
||||
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,68 +16,74 @@ 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
|
||||
github.com/jedib0t/go-pretty/v6 v6.4.4
|
||||
github.com/jedib0t/go-pretty/v6 v6.4.9
|
||||
github.com/lestrrat-go/jwx/v2 v2.0.9
|
||||
github.com/lithammer/shortuuid/v4 v4.0.0
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2
|
||||
github.com/mitchellh/mapstructure v1.5.0
|
||||
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
|
||||
github.com/urfave/cli/v2 v2.26.0
|
||||
gitlab.com/wpetit/goweb v0.0.0-20240226160244-6b2826c79f88
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
modernc.org/sqlite v1.21.0
|
||||
)
|
||||
|
||||
require (
|
||||
cloud.google.com/go/compute/metadata v0.2.3 // indirect
|
||||
github.com/Masterminds/goutils v1.1.1 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.2.0 // indirect
|
||||
github.com/barnybug/go-cast v0.0.0-20201201064555-a87ccbc26692 // indirect
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect
|
||||
github.com/charmbracelet/lipgloss v0.7.1 // indirect
|
||||
github.com/dop251/goja_nodejs v0.0.0-20230320130059-dcf93ba651dd // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.1 // indirect
|
||||
github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect
|
||||
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/mdns v1.0.5 // indirect
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.7 // 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/miekg/dns v1.1.53 // indirect
|
||||
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf // indirect
|
||||
github.com/keegancsmith/rpc v1.3.0 // indirect
|
||||
github.com/klauspost/compress v1.16.6 // indirect
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
|
||||
github.com/miekg/dns v1.1.57 // indirect
|
||||
github.com/mitchellh/copystructure v1.0.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.0 // indirect
|
||||
github.com/muesli/reflow v0.3.0 // indirect
|
||||
github.com/muesli/termenv v0.15.2 // indirect
|
||||
github.com/oklog/ulid/v2 v2.1.0 // indirect
|
||||
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
|
||||
google.golang.org/genproto v0.0.0-20220728213248-dd149ef739b9 // indirect
|
||||
github.com/ulikunitz/xz v0.5.11 // indirect
|
||||
go.opentelemetry.io/otel v1.21.0 // indirect
|
||||
go.opentelemetry.io/otel/trace v1.21.0 // indirect
|
||||
golang.org/x/net v0.19.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
||||
|
||||
require (
|
||||
cdr.dev/slog v1.4.2 // indirect
|
||||
github.com/alecthomas/chroma v0.10.0 // indirect
|
||||
cdr.dev/slog v1.6.1 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
|
||||
github.com/decred/dcrd/dcrec/secp256k1/v4 v4.1.0 // indirect
|
||||
github.com/dlclark/regexp2 v1.8.1 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/fatih/color v1.15.0 // indirect
|
||||
github.com/go-chi/chi/v5 v5.0.8
|
||||
github.com/go-chi/chi/v5 v5.0.10
|
||||
github.com/go-playground/locales v0.14.1 // indirect
|
||||
github.com/go-playground/universal-translator v0.18.1 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||
github.com/google/uuid v1.3.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||
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
|
||||
|
@ -84,27 +92,24 @@ require (
|
|||
github.com/lestrrat-go/iter v1.0.2 // indirect
|
||||
github.com/lestrrat-go/option v1.0.1 // indirect
|
||||
github.com/lib/pq v1.10.7 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.17 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||
github.com/qri-io/jsonpointer v0.1.1 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/rivo/uniseg v0.4.4 // indirect
|
||||
github.com/rogpeppe/go-internal v1.9.0 // indirect
|
||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||
github.com/sergi/go-diff v1.3.1 // indirect
|
||||
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/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/tools v0.8.0 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 // indirect
|
||||
google.golang.org/protobuf v1.28.1 // indirect
|
||||
golang.org/x/crypto v0.16.0 // indirect
|
||||
golang.org/x/mod v0.14.0 // indirect
|
||||
golang.org/x/sync v0.5.0 // indirect
|
||||
golang.org/x/sys v0.15.0 // indirect
|
||||
golang.org/x/term v0.15.0 // indirect
|
||||
golang.org/x/text v0.14.0 // indirect
|
||||
golang.org/x/tools v0.16.1 // indirect
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 // 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
|
||||
|
@ -118,3 +123,4 @@ require (
|
|||
)
|
||||
|
||||
// replace forge.cadoles.com/arcad/edge => ../edge
|
||||
// replace gitlab.com/wpetit/goweb => ../goweb
|
||||
|
|
240
go.sum
240
go.sum
|
@ -1,8 +1,7 @@
|
|||
bazil.org/fuse v0.0.0-20160811212531-371fbbdaa898/go.mod h1:Xbm+BRKSBEpa4q4hTSxohYNQpsxXPbPry4JJWOB3LB8=
|
||||
bazil.org/fuse v0.0.0-20200407214033-5883e5a4b512/go.mod h1:FbcW6z/2VytnFDhZfumh8Ss8zxHE6qpMP5sHTRe0EaM=
|
||||
cdr.dev/slog v1.4.0/go.mod h1:C5OL99WyuOK8YHZdYY57dAPN1jK2WJlCdq2VP6xeQns=
|
||||
cdr.dev/slog v1.4.2 h1:fIfiqASYQFJBZiASwL825atyzeA96NsqSxx2aL61P8I=
|
||||
cdr.dev/slog v1.4.2/go.mod h1:0EkH+GkFNxizNR+GAXUEdUHanxUH5t9zqPILmPM/Vn8=
|
||||
cdr.dev/slog v1.6.1 h1:IQjWZD0x6//sfv5n+qEhbu3wBkmtBQY5DILXNvMaIv4=
|
||||
cdr.dev/slog v1.6.1/go.mod h1:eHEYQLaZvxnIAXC+XdTSNLb/kgA/X2RVSF72v5wsxEI=
|
||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
||||
|
@ -10,7 +9,6 @@ cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6A
|
|||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
||||
cloud.google.com/go v0.49.0/go.mod h1:hGvAdzcWNbyuxS3nWhD7H2cIJxjRRTRLQVB0bdputVY=
|
||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
||||
|
@ -40,9 +38,17 @@ cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvf
|
|||
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
|
||||
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
|
||||
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
|
||||
cloud.google.com/go/compute v1.23.0 h1:tP41Zoavr8ptEqaW6j+LQOnyBBhO7OkOMAGrgLopTwY=
|
||||
cloud.google.com/go/compute v1.23.0/go.mod h1:4tCnrn48xsqlwSAiLf1HXMQk8CONslYbdiEZc9FEIbM=
|
||||
cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY=
|
||||
cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA=
|
||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
||||
cloud.google.com/go/firestore v1.1.0/go.mod h1:ulACoGHTpvq5r8rxGJ4ddJZBZqakUQqClKRT5SZwBmk=
|
||||
cloud.google.com/go/logging v1.7.0 h1:CJYxlNNNNAMkHp9em/YEXcfJg+rPDg7YfwoRpMU+t5I=
|
||||
cloud.google.com/go/logging v1.7.0/go.mod h1:3xjP2CjkM3ZkO73aj4ASA5wRPGGCRrPIAeNqVNkzY8M=
|
||||
cloud.google.com/go/longrunning v0.5.1 h1:Fr7TXftcqTudoyRJa113hyaqlGdiBQkp0Gq7tErFDWI=
|
||||
cloud.google.com/go/longrunning v0.5.1/go.mod h1:spvimkwdz6SPWKEt/XBij79E9fiTkHSQl/fRUUQJYJc=
|
||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
||||
|
@ -54,8 +60,10 @@ 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-20230426135323-17808d14c978 h1:fekSRSb8gYcVx8C0B9K6B7+KiFHVixIwvPUkxcnRFp4=
|
||||
forge.cadoles.com/arcad/edge v0.0.0-20230426135323-17808d14c978/go.mod h1:uv3wBa+UbcEUb7IiJCj1T96Xo3cmx1BwNxbBYRZhln8=
|
||||
forge.cadoles.com/arcad/arcast v0.0.0-20231220090835-5d0311b7315d h1:SPDaDDF5StoprDqop8j8zozs8xK32EEWnUHLccWplKM=
|
||||
forge.cadoles.com/arcad/arcast v0.0.0-20231220090835-5d0311b7315d/go.mod h1:QR8p4kUScWBcTQ0dE/gR+2ndpKOx77mIDSYGqSF1gms=
|
||||
forge.cadoles.com/arcad/edge v0.0.0-20240112130429-2fbc7186c077 h1:6bPO5vRqA9pL6rtSXXJya5TPYSW7VEvYL7ZTiVnqstM=
|
||||
forge.cadoles.com/arcad/edge v0.0.0-20240112130429-2fbc7186c077/go.mod h1:kBsyQaw2GmVvNMHLgEpIjOkEAyGUxH987p3qIY5UwHQ=
|
||||
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=
|
||||
|
@ -82,8 +90,6 @@ github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBp
|
|||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/ClickHouse/clickhouse-go v1.4.3/go.mod h1:EaI/sW7Azgz9UATzd5ZdZHRUhHgv5+JMS9NSr2smCJI=
|
||||
github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0=
|
||||
github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0=
|
||||
github.com/Masterminds/goutils v1.1.1 h1:5nUrii3FMTL5diU80unEVvNevw1nH4+ZV4DSLVJLSYI=
|
||||
github.com/Masterminds/goutils v1.1.1/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU=
|
||||
github.com/Masterminds/semver/v3 v3.2.0 h1:3MEsd0SM6jqZojhjLWWeBY+Kcjy9i6MQAeY7YgDP83g=
|
||||
|
@ -124,21 +130,12 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdko
|
|||
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ=
|
||||
github.com/aead/siphash v1.0.1/go.mod h1:Nywa3cDsYNNK3gaciGTWPwHt0wlpNV15vwmswBAUSII=
|
||||
github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw=
|
||||
github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
|
||||
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/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=
|
||||
github.com/alecthomas/colour v0.0.0-20160524082231-60882d9e2721/go.mod h1:QO9JBoKquHd+jz9nshCh40fOfO+JzsoXy8qTHF68zU0=
|
||||
github.com/alecthomas/kong v0.1.17-0.20190424132513-439c674f7ae0/go.mod h1:+inYUSluD+p4L8KdviBSgzcqEjUQOfC5fQDRFuc36lI=
|
||||
github.com/alecthomas/kong v0.2.1-0.20190708041108-0548c6b1afae/go.mod h1:+inYUSluD+p4L8KdviBSgzcqEjUQOfC5fQDRFuc36lI=
|
||||
github.com/alecthomas/kong-hcl v0.1.8-0.20190615233001-b21fea9723c8/go.mod h1:MRgZdU3vrFd05IQ89AxUZ0aYdF39BYoNFa324SodPCA=
|
||||
github.com/alecthomas/assert/v2 v2.0.3/go.mod h1:b/+1DI2Q6NckYi+3mXyH3wFb8qG37K/DuK80n7WefXA=
|
||||
github.com/alecthomas/participle/v2 v2.0.0-beta.5 h1:y6dsSYVb1G5eK6mgmy+BgI3Mw35a3WghArZ/Hbebrjo=
|
||||
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=
|
||||
|
@ -186,6 +183,8 @@ github.com/aws/aws-sdk-go-v2/service/sts v1.6.1/go.mod h1:hLZ/AnkIKHLuPGjEiyghNE
|
|||
github.com/aws/aws-sdk-go-v2/service/sts v1.7.2/go.mod h1:8EzeIqfWt2wWT4rJVu3f21TfrhJ8AEMzVybRNSb/b4g=
|
||||
github.com/aws/smithy-go v1.7.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
|
||||
github.com/aws/smithy-go v1.8.0/go.mod h1:SObp3lf9smib00L/v3U2eAKG8FyQ7iLrJnQiAmR5n+E=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k=
|
||||
github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8=
|
||||
github.com/barnybug/go-cast v0.0.0-20201201064555-a87ccbc26692 h1:JW4WZlqyaNWUUahfr7MigeDW6jmtam5cTzzo1lwsFhE=
|
||||
github.com/barnybug/go-cast v0.0.0-20201201064555-a87ccbc26692/go.mod h1:Au0ipPuCBA7zsOC61SnyrYetm8VT3vo1UJtwHeYke44=
|
||||
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
|
||||
|
@ -231,6 +230,8 @@ github.com/buger/jsonparser v1.1.1/go.mod h1:6RYKKt7H4d4+iWqouImQ9R2FZql3VbhNgx2
|
|||
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd/go.mod h1:2oa8nejYd4cQ/b0hMIopN0lCRxU0bueqREvZLWFrtK8=
|
||||
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b/go.mod h1:obH5gd0BsqsP2LwDJ9aOkm/6J86V6lyAXCoQWGw3K50=
|
||||
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0/go.mod h1:D/8v3kj0zr8ZAKg1AQ6crr+5VwKN5eIywRkfhyM/+dE=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible h1:tNowT99t7UNflLxfYYSlKYsBpXdEet03Pg2g16Swow4=
|
||||
github.com/cenkalti/backoff v2.2.1+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
|
||||
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
||||
github.com/cenkalti/backoff/v4 v4.1.2/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||
|
@ -240,6 +241,8 @@ github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6
|
|||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/charmbracelet/lipgloss v0.7.1 h1:17WMwi7N1b1rVWOjMT+rCh7sQkvDU75B2hbZpc5Kc1E=
|
||||
github.com/charmbracelet/lipgloss v0.7.1/go.mod h1:yG0k3giv8Qj8edTCbbg6AlQ5e8KNWpFujkNawKNhE2c=
|
||||
github.com/checkpoint-restore/go-criu/v4 v4.1.0/go.mod h1:xUQBLp4RLc5zJtWY++yjOoMoB5lihDt7fai+75m+rGw=
|
||||
github.com/checkpoint-restore/go-criu/v5 v5.0.0/go.mod h1:cfwC0EG7HMUenopBsUf9d89JlCLQIfgVcNsNN0t6T2M=
|
||||
github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E=
|
||||
|
@ -402,10 +405,7 @@ github.com/d2g/dhcp4 v0.0.0-20170904100407-a1d1b6c41b1c/go.mod h1:Ct2BUK8SB0YC1S
|
|||
github.com/d2g/dhcp4client v1.0.0/go.mod h1:j0hNfjhrt2SxUOw55nL0ATM/z4Yt3t2Kd1mW34z5W5s=
|
||||
github.com/d2g/dhcp4server v0.0.0-20181031114812-7d4a0a7f59a5/go.mod h1:Eo87+Kg/IX2hfWJfwxMzLyuSZyxSoAug2nGa1G2QAi8=
|
||||
github.com/d2g/hardwareaddr v0.0.0-20190221164911-e7d9fbe030e4/go.mod h1:bMl4RjIciD2oAxI7DmWRx6gbeqrkoLqv3MV0vzNad+I=
|
||||
github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E=
|
||||
github.com/danwakefield/fnmatch v0.0.0-20160403171240-cbb64ac3d964/go.mod h1:Xd9hchkHSWYkEqJwUGisez3G1QY8Ryz0sdWrLPMGjLk=
|
||||
github.com/davecgh/go-spew v0.0.0-20171005155431-ecdeabc65495/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.0.1-0.20160907170601-6d212800a42e/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
|
@ -423,9 +423,6 @@ github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZm
|
|||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/dhui/dktest v0.3.10 h1:0frpeeoM9pHouHjhLeZDuDTJ0PqjDTrycaHaMmkJAo8=
|
||||
github.com/dhui/dktest v0.3.10/go.mod h1:h5Enh0nG3Qbo9WjNFRrwmKUaePEBhXMOygbz3Ww7Sz0=
|
||||
github.com/dlclark/regexp2 v1.1.6/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||
github.com/dlclark/regexp2 v1.2.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||
github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||
github.com/dlclark/regexp2 v1.4.1-0.20201116162257-a2a8dda75c91/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc=
|
||||
github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8=
|
||||
github.com/dlclark/regexp2 v1.8.1 h1:6Lcdwya6GjPUNsBct8Lg/yRPwMhABj269AAzdGSiR+0=
|
||||
|
@ -484,9 +481,6 @@ github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQL
|
|||
github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww=
|
||||
github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
|
||||
github.com/fatih/color v1.15.0 h1:kOqh6YHBtK8aywxGerMG2Eq3H6Qgoqeo13Bk2Mv/nBs=
|
||||
github.com/fatih/color v1.15.0/go.mod h1:0h5ZqXfHYED7Bhv2ZJamyIOUej9KtShiJESRwBDUSsw=
|
||||
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||
github.com/fogleman/gg v1.3.0/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||
|
@ -504,15 +498,16 @@ 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/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk=
|
||||
github.com/go-chi/chi/v5 v5.0.10/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=
|
||||
|
@ -534,7 +529,10 @@ github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTg
|
|||
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.1/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY=
|
||||
github.com/go-logr/logr v1.3.0/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||
github.com/go-logr/stdr v1.2.0/go.mod h1:YkVgnZu1ZjjL7xTxrfm/LLZBfkhTqSR1ydtm6jTKKwI=
|
||||
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||
github.com/go-openapi/jsonpointer v0.0.0-20160704185906-46af16f9f7b1/go.mod h1:+35s3my2LFTysnkMfxsJBAMHj/DoqoB9knIWoYG/Vk0=
|
||||
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
|
||||
|
@ -550,10 +548,8 @@ 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.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.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=
|
||||
|
@ -600,7 +596,6 @@ github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRx
|
|||
github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/gogo/googleapis v1.2.0/go.mod h1:Njal3psf3qN6dwBtQfUmBZh2ybovJ0tlu3o/AC7HYjU=
|
||||
github.com/gogo/googleapis v1.4.0/go.mod h1:5YRNX2z1oM5gXdAkurHa942MDgEJyk02w4OecKY87+c=
|
||||
github.com/gogo/protobuf v0.0.0-20161014173244-50d1bd39ce4e/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||
github.com/gogo/protobuf v1.2.2-0.20190723190241-65acae22fc9d/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
||||
|
@ -618,10 +613,8 @@ github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfU
|
|||
github.com/golang/groupcache v0.0.0-20160516000752-02826c3e7903/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191027212112-611e8accdfc9/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||
|
@ -649,8 +642,9 @@ github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw
|
|||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
|
||||
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||
github.com/golang/snappy v0.0.0-20170215233205-553a64147049/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
|
||||
|
@ -662,7 +656,6 @@ github.com/google/flatbuffers v2.0.0+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6
|
|||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||
github.com/google/go-cmp v0.3.2-0.20191216170541-340f1ebe299e/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
|
@ -672,7 +665,8 @@ github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
|||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
|
||||
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
|
||||
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
|
||||
github.com/google/go-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=
|
||||
|
@ -708,6 +702,8 @@ github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
|
|||
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
||||
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
|
||||
|
@ -716,20 +712,18 @@ github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3i
|
|||
github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
|
||||
github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
|
||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||
github.com/gorilla/csrf v1.6.0/go.mod h1:7tSf8kmjNYr7IWDCYhd3U8Ck34iQ/Yw5CJu7bAkHEGI=
|
||||
github.com/gorilla/handlers v0.0.0-20150720190736-60c7bfde3e33/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
||||
github.com/gorilla/handlers v1.4.1/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
||||
github.com/gorilla/handlers v1.4.2/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ=
|
||||
github.com/gorilla/mux v1.7.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/mux v1.7.4/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||
github.com/gorilla/websocket v0.0.0-20170926233335-4201258b820c/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
|
||||
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grandcat/zeroconf v1.0.1-0.20230119201135-e4f60f8407b1 h1:cNb52t5fkWv8ZiicKWnc2eZnhsCCoH7WmRBMIbMp04Q=
|
||||
github.com/grandcat/zeroconf v1.0.1-0.20230119201135-e4f60f8407b1/go.mod h1:I6CSXU4zCGL08JOk9NbcT0ofAgnIkS/fVXbYzfSoDic=
|
||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.1-0.20190118093823-f849b5445de4/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
|
@ -757,19 +751,20 @@ github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerX
|
|||
github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4=
|
||||
github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro=
|
||||
github.com/hashicorp/go.net v0.0.0-20151006203346-104dcad90073/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||
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=
|
||||
github.com/hashicorp/mdns v1.0.0/go.mod h1:tL+uN++7HEJ6SQLQ2/p+z2pH24WQKWjBPkE0mNTz8vQ=
|
||||
github.com/hashicorp/mdns v1.0.5 h1:1M5hW1cunYeoXOqHwEb/GBDDHAFo0Yqb/uz/beC6LbE=
|
||||
github.com/hashicorp/mdns v1.0.5/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc=
|
||||
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=
|
||||
|
@ -786,6 +781,8 @@ github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH
|
|||
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf h1:FtEj8sfIcaaBfAKrE1Cwb61YDtYq9JxChK1c7AKce7s=
|
||||
github.com/inhies/go-bytesize v0.0.0-20220417184213-4913239db9cf/go.mod h1:yrqSXGoD/4EKfF26AOGzscPOgTTJcyAwM2rpixWT+t4=
|
||||
github.com/intel/goresctrl v0.2.0/go.mod h1:+CZdzouYFn5EsxgqAQTEzMfwKwuc0fVdMrT9FCCAVRQ=
|
||||
github.com/j-keck/arping v0.0.0-20160618110441-2cf9dc699c56/go.mod h1:ymszkNOg6tORTn+6F6j+Jc8TOr5osrynvN6ivFWZ2GA=
|
||||
github.com/j-keck/arping v1.0.2/go.mod h1:aJbELhR92bSk7tp79AWM/ftfc90EfEi2bQJrbBFOsPw=
|
||||
|
@ -837,10 +834,12 @@ 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/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/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk=
|
||||
github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
github.com/jaevor/go-nanoid v1.3.0 h1:nD+iepesZS6pr3uOVf20vR9GdGgJW1HPaR46gtrxzkg=
|
||||
github.com/jaevor/go-nanoid v1.3.0/go.mod h1:SI+jFaPuddYkqkVQoNGHs81navCtH388TcrH0RqFKgY=
|
||||
github.com/jedib0t/go-pretty/v6 v6.4.9 h1:vZ6bjGg2eBSrJn365qlxGcaWu09Id+LHtrfDWlB2Usc=
|
||||
github.com/jedib0t/go-pretty/v6 v6.4.9/go.mod h1:Ndk3ase2CkQbXLLNf5QDHoYb6J9WtVfmHZu9n8rk2xs=
|
||||
github.com/jessevdk/go-flags v0.0.0-20141203071132-1679536dcc89/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||
|
@ -878,6 +877,8 @@ github.com/karrick/godirwalk v1.8.0/go.mod h1:H5KPZjojv4lE+QYImBI8xVtrBRgYrIVsaR
|
|||
github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/keegancsmith/rpc v1.3.0 h1:wGWOpjcNrZaY8GDYZJfvyxmlLljm3YQWF+p918DXtDk=
|
||||
github.com/keegancsmith/rpc v1.3.0/go.mod h1:6O2xnOGjPyvIPbvp0MdrOe5r6cu1GZ4JoTzpzDhWeo0=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
|
@ -889,6 +890,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=
|
||||
|
@ -906,7 +909,6 @@ 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.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=
|
||||
|
@ -933,6 +935,8 @@ github.com/lib/pq v1.10.7/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
|
|||
github.com/linuxkit/virtsock v0.0.0-20201010232012-f8cee7dfc7a3/go.mod h1:3r6x7q95whyfWQpmGZTu3gk3v2YkMi05HEzl7Tf7YEo=
|
||||
github.com/lithammer/shortuuid/v4 v4.0.0 h1:QRbbVkfgNippHOS8PXDkti4NaWeyYfcBTHtw7k08o4c=
|
||||
github.com/lithammer/shortuuid/v4 v4.0.0/go.mod h1:Zs8puNcrvf2rV9rTH51ZLLcj7ZXqQI3lv67aw4KiB1Y=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY=
|
||||
github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0=
|
||||
github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
|
@ -948,11 +952,7 @@ github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHef
|
|||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
|
||||
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
|
||||
github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
|
||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
|
||||
github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E=
|
||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
|
@ -960,15 +960,14 @@ github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hd
|
|||
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
|
||||
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
|
||||
github.com/mattn/go-isatty v0.0.11/go.mod h1:PhnuNfih5lzO57/f3n+odYbM4JtupLOxQOAqxQCu2WE=
|
||||
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
|
||||
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
|
||||
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
|
||||
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
|
||||
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||
github.com/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
|
||||
github.com/mattn/go-runewidth v0.0.12/go.mod h1:RAqKPSqVFrSLVXbA8x7dzmKdmGzieGRCM46jaSJTDAk=
|
||||
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||
github.com/mattn/go-shellwords v1.0.3/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
|
||||
github.com/mattn/go-shellwords v1.0.6/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o=
|
||||
github.com/mattn/go-shellwords v1.0.12/go.mod h1:EZzvwXDESEeg03EKmM+RmDnNOPKG4lLtQsUlTZDWQ8Y=
|
||||
|
@ -976,15 +975,14 @@ 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=
|
||||
github.com/miekg/dns v0.0.0-20161006100029-fc4e1e2843d8/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJysuI=
|
||||
github.com/miekg/dns v1.1.50/go.mod h1:e3IlAVfNqAllflbibAZEWOXOQ+Ynzk/dDozDxY7XnME=
|
||||
github.com/miekg/dns v1.1.53 h1:ZBkuHr5dxHtB1caEOlZTLPo7D3L3TWckgUUs/RHfDxw=
|
||||
github.com/miekg/dns v1.1.53/go.mod h1:uInx36IzPl7FYnDcMeVWxj9byh7DutNykX4G9Sj60FY=
|
||||
github.com/miekg/dns v1.1.57 h1:Jzi7ApEIzwEPLHWRcafCN9LZSBbqQpxjt/wpgvg7wcM=
|
||||
github.com/miekg/dns v1.1.57/go.mod h1:uqRjCRUuEAA6qsOiJvDd+CFo/vW+y5WR6SNmHE55hZk=
|
||||
github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs=
|
||||
github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
|
@ -1026,6 +1024,10 @@ github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJ
|
|||
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
|
||||
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
|
||||
github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
|
||||
github.com/muesli/reflow v0.3.0 h1:IFsN6K9NfGtjeggFP+68I4chLZV2yIKsXJFNZ+eWh6s=
|
||||
github.com/muesli/reflow v0.3.0/go.mod h1:pbwTDkVPibjO2kyvBQRBxTWEEGDGq0FlB1BIKtnHY/8=
|
||||
github.com/muesli/termenv v0.15.2 h1:GohcuySI0QmI3wN8Ok9PtKGkgkFIk7y6Vpb5PvrY+Wo=
|
||||
github.com/muesli/termenv v0.15.2/go.mod h1:Epx+iuz8sNs7mNKhxzH4fWXGNpZwUaJKRS1noLXviQ8=
|
||||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||
github.com/mutecomm/go-sqlcipher/v4 v4.4.0/go.mod h1:PyN04SaWalavxRGH9E8ZftG6Ju7rsPrGmQRjrEaVpiY=
|
||||
|
@ -1036,7 +1038,6 @@ github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8/go.mod h1:86w
|
|||
github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM=
|
||||
github.com/neo4j/neo4j-go-driver v1.8.1-0.20200803113522-b626aa943eba/go.mod h1:ncO5VaFWh0Nrt+4KT4mOZboaczBZcLuHrG+/sUeP8gI=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E=
|
||||
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
|
||||
github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
|
@ -1099,7 +1100,6 @@ github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuh
|
|||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/orcaman/concurrent-map v1.0.0 h1:I/2A2XPCb4IuQWcQhBhSwGfiuybl/J0ev9HDbW65HOY=
|
||||
github.com/orcaman/concurrent-map v1.0.0/go.mod h1:Lu3tH6HLW3feq74c2GC+jIMS/K2CFcDWnWD9XkenwhI=
|
||||
github.com/oxtoacart/bpool v0.0.0-20190530202638-03653db5a59c/go.mod h1:X07ZCGwUbLaax7L0S3Tw4hpejzu63ZrrQiUe6W0hcy0=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
|
@ -1111,6 +1111,8 @@ 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/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
|
@ -1120,7 +1122,6 @@ 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.6.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
|
||||
github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
|
||||
github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
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/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndrE9hABlRI=
|
||||
|
@ -1166,8 +1167,10 @@ github.com/remyoudompheng/bigfft v0.0.0-20190728182440-6a916e37a237/go.mod h1:qq
|
|||
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||
github.com/rivo/uniseg v0.1.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
|
||||
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
|
||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
|
@ -1209,8 +1212,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=
|
||||
|
@ -1246,7 +1250,6 @@ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoH
|
|||
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
||||
github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
github.com/stretchr/testify v1.1.5-0.20160925220609-976c720a22c8/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
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=
|
||||
|
@ -1256,9 +1259,9 @@ github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.4/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
|
||||
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
||||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
|
||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||
github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||
|
@ -1271,14 +1274,14 @@ 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=
|
||||
github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||
github.com/urfave/cli/v2 v2.24.4 h1:0gyJJEBYtCV87zI/x2nZCPyDxD51K6xM8SkwjHFCNEU=
|
||||
github.com/urfave/cli/v2 v2.24.4/go.mod h1:GHupkWPMM0M/sj1a2b4wUrWBPzazNrIjouW6fmdJLxc=
|
||||
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
|
||||
github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8=
|
||||
github.com/urfave/cli/v2 v2.26.0 h1:3f3AMg3HpThFNT4I++TKOejZO8yU55t3JnnSr4S4QEI=
|
||||
github.com/urfave/cli/v2 v2.26.0/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
|
||||
github.com/vishvananda/netlink v0.0.0-20181108222139-023a6dafdcdf/go.mod h1:+SR5DhBJrl6ZM7CoCKvpw5BKroDKQ+PJqOg65H/2ktk=
|
||||
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
|
||||
github.com/vishvananda/netlink v1.1.1-0.20201029203352-d40f9887b852/go.mod h1:twkDnbuQxJYemMlGd4JFIcuhgX83tXhKS2B/PRMpOho=
|
||||
|
@ -1289,6 +1292,8 @@ github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1
|
|||
github.com/vishvananda/netns v0.0.0-20210104183010-2eb08e3e575f/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||
github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4=
|
||||
github.com/willf/bitset v1.1.11/go.mod h1:83CECat5yLh5zVOf4P1ErAgKA5UDvKtgyUABdr3+MjI=
|
||||
github.com/wlynxg/anet v0.0.1 h1:VbkEEgHxPSrRQSiyRd0pmrbcEQAEU2TTb8fb4DmSYoQ=
|
||||
github.com/wlynxg/anet v0.0.1/go.mod h1:eay5PRQr7fIVAMbTbchTnO9gG65Hg/uYGdc7mguHxoA=
|
||||
github.com/xanzy/go-gitlab v0.15.0/go.mod h1:8zdQa/ri1dfn8eS3Ir1SyfvOKlw7WBJ8DVThkpGiXrs=
|
||||
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
|
||||
github.com/xdg-go/scram v1.0.2/go.mod h1:1WAq6h33pAW+iRreB34OORO2Nf7qel3VV3fjBj+hCSs=
|
||||
|
@ -1312,8 +1317,10 @@ 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-20231215190137-4a8add1d3d07 h1:0V95X1cBpdj5zyOe6oGtn/BQHlRpV8WlL3eTs3jaxiA=
|
||||
gitlab.com/wpetit/goweb v0.0.0-20231215190137-4a8add1d3d07/go.mod h1:Nfr7aZPiSN6biFumhiHbh9k8A3rKQRzR+o0bVtv78UY=
|
||||
gitlab.com/wpetit/goweb v0.0.0-20240226160244-6b2826c79f88 h1:dsyRrmhp7fl/YaY1YIzz7lm9qfIFI5KpKNbXwuhTULA=
|
||||
gitlab.com/wpetit/goweb v0.0.0-20240226160244-6b2826c79f88/go.mod h1:bg+TN16Rq2ygLQbB4VDSHQFNouAEzcy3AAutStehllA=
|
||||
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=
|
||||
|
@ -1335,27 +1342,33 @@ go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
|||
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
||||
go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk=
|
||||
go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
|
||||
go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0=
|
||||
go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo=
|
||||
go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E=
|
||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.28.0/go.mod h1:vEhqr0m4eTc+DWxfsXoXue2GBgV2uUwVznkGIHW/e5w=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4=
|
||||
go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo=
|
||||
go.opentelemetry.io/otel v1.3.0/go.mod h1:PWIKzi6JCp7sM0k9yZ43VX+T345uNbAkDKwHVjb2PTs=
|
||||
go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc=
|
||||
go.opentelemetry.io/otel v1.21.0/go.mod h1:QZzNPQPm1zLX4gZK4cMi+71eaorMSGT3A4znnUvNNEo=
|
||||
go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM=
|
||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.3.0/go.mod h1:VpP4/RMn8bv8gNo9uK7/IMY4mtWLELsS+JIP0inH0h4=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.3.0/go.mod h1:hO1KLR7jcKaDDKDkvI9dP/FIhpmna5lkqPUQdEjFAM8=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.3.0/go.mod h1:keUU7UfnwWTWpJ+FWnyqmogPa82nuU5VUANFq49hlMY=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.3.0/go.mod h1:QNX1aly8ehqqX1LEa6YniTU7VY9I6R3X/oPxhGdTceE=
|
||||
go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU=
|
||||
go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4=
|
||||
go.opentelemetry.io/otel/metric v1.21.0/go.mod h1:o1p3CA8nNHW8j5yuQLdc1eeqEaPfzug24uvsyIEJRWM=
|
||||
go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw=
|
||||
go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc=
|
||||
go.opentelemetry.io/otel/sdk v1.3.0/go.mod h1:rIo4suHNhQwBIPg9axF8V9CA72Wz2mKF1teNrup8yzs=
|
||||
go.opentelemetry.io/otel/sdk v1.16.0 h1:Z1Ok1YsijYL0CSJpHt4cS3wDDh7p572grzNrBMiMWgE=
|
||||
go.opentelemetry.io/otel/sdk v1.16.0/go.mod h1:tMsIuKXuuIWPBAOrH+eHtvhTL+SntFtXF9QD68aP6p4=
|
||||
go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE=
|
||||
go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE=
|
||||
go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
|
||||
go.opentelemetry.io/otel/trace v1.3.0/go.mod h1:c/VDhno8888bvQYmbYLqe41/Ldmr/KKunbvWM4/fEjk=
|
||||
go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc=
|
||||
go.opentelemetry.io/otel/trace v1.21.0/go.mod h1:LGbsEB0f9LGjN+OZaQQ26sohbOmiMR+BaslueVtS/qQ=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.opentelemetry.io/proto/otlp v0.11.0/go.mod h1:QpEjXPrNQzrFDZgoTo49dgHR9RYRSrg3NAKnUGl9YpQ=
|
||||
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
|
@ -1366,7 +1379,8 @@ go.uber.org/atomic v1.10.0 h1:9qC72Qh0+3MqyJbAn8YU5xVq1frD8bn3JtD2oXtafVQ=
|
|||
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=
|
||||
|
@ -1390,7 +1404,6 @@ golang.org/x/crypto v0.0.0-20190701094942-4def268fd1a4/go.mod h1:yigFU9vqHzYiE8U
|
|||
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||
golang.org/x/crypto v0.0.0-20191206172530-e9b2fee46413/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||
|
@ -1401,8 +1414,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.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY=
|
||||
golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
|
||||
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=
|
||||
|
@ -1452,9 +1466,8 @@ golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|||
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.10.0 h1:lFO9qtOdlre5W1jxS3r/4szv2/6iXxScdzjoBMXNhYk=
|
||||
golang.org/x/mod v0.10.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/net v0.0.0-20161013035702-8b4af36cd21a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/mod v0.14.0 h1:dGoOF9QVLYng8IHTm7BAyWqCqSheQ5pYWGhzW00YJr0=
|
||||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180719180050-a680a1efc54d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
|
@ -1511,7 +1524,6 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v
|
|||
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20210410081132-afb366fc7cd1/go.mod h1:9tjilg8BloeKEkVJvy7fQ90B1CfIiPueXVOjqfkSzI8=
|
||||
golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
|
||||
golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/net v0.0.0-20210505024714-0287a6fb4125/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
|
@ -1531,8 +1543,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.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c=
|
||||
golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U=
|
||||
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=
|
||||
|
@ -1564,8 +1576,9 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
|
|||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.1.0 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
|
||||
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
|
||||
golang.org/x/sync v0.5.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180224232135-f6cff0780e54/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
|
@ -1574,7 +1587,6 @@ golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5h
|
|||
golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35/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-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -1654,7 +1666,6 @@ golang.org/x/sys v0.0.0-20210112080510-489259a85091/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210304124612-50617c2ba197/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
@ -1692,13 +1703,13 @@ golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20220317061510-51cd9980dadf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
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.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
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=
|
||||
|
@ -1708,8 +1719,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.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
|
||||
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
|
||||
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=
|
||||
|
@ -1724,8 +1735,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.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.0.0-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=
|
||||
|
@ -1816,16 +1827,16 @@ golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
|||
golang.org/x/tools v0.1.6-0.20210726203631-07bc1bf47fb2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.8.0 h1:vSDcovVPld282ceKgDimkRSC8kpaH1dgyc9UMzlt84Y=
|
||||
golang.org/x/tools v0.8.0/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4=
|
||||
golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA=
|
||||
golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
|
||||
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2 h1:H2TDz8ibqkAF6YGhCdN3jS9O0/s90v0rJh3X/OLHEUk=
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2/go.mod h1:K8+ghG5WaK9qNqU5K3HdILfMLy1f3aNYFI/wnl100a8=
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028 h1:+cNy6SZtPcJQH3LJVLOSmiC7MMxXNOb3PU/VUEz+EhU=
|
||||
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028/go.mod h1:NDW/Ps6MPRej6fsCIbMTohpP40sJ/P/vI1MoTEGwX90=
|
||||
gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo=
|
||||
gonum.org/v1/gonum v0.8.2/go.mod h1:oe/vMfY3deqTw+1EZJhuvEW2iwGF1bW9wwu7XCu0+v0=
|
||||
gonum.org/v1/gonum v0.9.3/go.mod h1:TZumC3NeyVQskjXqmyWt4S3bINhy7B4eYwW69EbyX+0=
|
||||
|
@ -1944,8 +1955,12 @@ google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ6
|
|||
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20220111164026-67b88f271998/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
|
||||
google.golang.org/genproto v0.0.0-20220314164441-57ef72a4c106/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E=
|
||||
google.golang.org/genproto v0.0.0-20220728213248-dd149ef739b9 h1:d3fKQZK+1rWQMg3xLKQbPMirUCo29I/NRdI2WarSzTg=
|
||||
google.golang.org/genproto v0.0.0-20220728213248-dd149ef739b9/go.mod h1:iHe1svFLAZg9VWz891+QbRMwUv9O/1Ww+/mngYeThbc=
|
||||
google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e h1:xIXmWJ303kJCuogpj0bHq+dcjcZHU+XFyc1I0Yl9cRg=
|
||||
google.golang.org/genproto v0.0.0-20230726155614-23370e0ffb3e/go.mod h1:0ggbjUrZYpy1q+ANUS30SEoGZ53cdfwtbuG7Ptgy108=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130 h1:XVeBY8d/FaK4848myy41HBqnDwvxeV3zMZhwN1TvAMU=
|
||||
google.golang.org/genproto/googleapis/api v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:mPBs5jNgx2GuQGvFwUvVKqtn6HsUw9nP64BedgvqEsQ=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130 h1:2FZP5XuJY9zQyGM5N0rtovnoXjiMUEIUMvw0m9wlpLc=
|
||||
google.golang.org/genproto/googleapis/rpc v0.0.0-20230706204954-ccb25ca9f130/go.mod h1:8mL13HKkDa+IuJ8yruA3ci0q+0vsUz4m//+ottjwS5o=
|
||||
google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
|
||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||
|
@ -1979,7 +1994,8 @@ google.golang.org/grpc v1.40.1/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9K
|
|||
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
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.57.0 h1:kfzNeI/klCGD2YPMUlaGNT3pxvYfga7smW3Vth8Zsiw=
|
||||
google.golang.org/grpc v1.57.0/go.mod h1:Sd+9RMTACXwmub0zcNY2c4arhtrbBYD1AUHI/dt16Mo=
|
||||
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=
|
||||
|
@ -1994,8 +2010,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.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
|
||||
google.golang.org/protobuf v1.31.0/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=
|
||||
|
@ -2011,7 +2027,6 @@ gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMy
|
|||
gopkg.in/gemnasium/logrus-airbrake-hook.v2 v2.1.2/go.mod h1:Xk6kEKp8OKb+X14hQBKWaSkCsqBpgog8nAV2xsGOxlo=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM=
|
||||
gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE=
|
||||
gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
||||
gopkg.in/go-playground/validator.v9 v9.31.0 h1:bmXmP2RSNtFES+bn4uYuHT7iJFJv7Vj+an+ZQdDaD1M=
|
||||
gopkg.in/go-playground/validator.v9 v9.31.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
|
||||
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
|
||||
|
@ -2106,6 +2121,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=
|
||||
|
@ -2139,12 +2155,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=
|
||||
|
|
|
@ -38,18 +38,21 @@ func (a *Agent) Run(ctx context.Context) error {
|
|||
client := client.New(a.serverURL, client.WithToken(token))
|
||||
|
||||
ctx = withClient(ctx, client)
|
||||
ctx = withThumbprint(ctx, a.thumbprint)
|
||||
|
||||
tick := func() {
|
||||
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 +82,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 +114,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
|
||||
|
|
|
@ -10,7 +10,8 @@ import (
|
|||
type contextKey string
|
||||
|
||||
const (
|
||||
contextKeyClient contextKey = "client"
|
||||
contextKeyClient contextKey = "client"
|
||||
contextKeyThumbprint contextKey = "thumbprint"
|
||||
)
|
||||
|
||||
func withClient(ctx context.Context, client *client.Client) context.Context {
|
||||
|
@ -25,3 +26,16 @@ func Client(ctx context.Context) *client.Client {
|
|||
|
||||
return client
|
||||
}
|
||||
|
||||
func withThumbprint(ctx context.Context, thumbprint string) context.Context {
|
||||
return context.WithValue(ctx, contextKeyThumbprint, thumbprint)
|
||||
}
|
||||
|
||||
func Thumbprint(ctx context.Context) string {
|
||||
thumbprint, ok := ctx.Value(contextKeyThumbprint).(string)
|
||||
if !ok {
|
||||
panic(errors.New("could not retrieve thumbprint from context"))
|
||||
}
|
||||
|
||||
return thumbprint
|
||||
}
|
||||
|
|
|
@ -4,7 +4,6 @@ import (
|
|||
"bytes"
|
||||
"context"
|
||||
"net"
|
||||
"path/filepath"
|
||||
"text/template"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/app/spec"
|
||||
|
@ -17,47 +16,60 @@ 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"
|
||||
shareSqlite "forge.cadoles.com/arcad/edge/pkg/module/share/sqlite"
|
||||
"forge.cadoles.com/arcad/edge/pkg/storage"
|
||||
"forge.cadoles.com/arcad/edge/pkg/storage/sqlite"
|
||||
"forge.cadoles.com/arcad/edge/pkg/storage/driver"
|
||||
"forge.cadoles.com/arcad/edge/pkg/storage/share"
|
||||
"github.com/Masterminds/sprig/v3"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/lestrrat-go/jwx/v2/jwa"
|
||||
"github.com/pkg/errors"
|
||||
"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"
|
||||
)
|
||||
|
||||
type Dependencies struct {
|
||||
Bus bus.Bus
|
||||
DocumentStore storage.DocumentStore
|
||||
BlobStore storage.BlobStore
|
||||
KeySet jwk.Set
|
||||
AppRepository appModule.Repository
|
||||
AppID app.ID
|
||||
ShareRepository shareModule.Repository
|
||||
Bus bus.Bus
|
||||
DocumentStore storage.DocumentStore
|
||||
BlobStore storage.BlobStore
|
||||
ShareStore share.Store
|
||||
KeySet jwk.Set
|
||||
AppRepository appModule.Repository
|
||||
AppID app.ID
|
||||
}
|
||||
|
||||
const defaultSQLiteParams = "?_pragma=foreign_keys(1)&_pragma=busy_timeout=60000"
|
||||
|
||||
func (c *Controller) getHandlerOptions(ctx context.Context, appKey string, specs *spec.Spec) ([]edgeHTTP.HandlerOptionFunc, error) {
|
||||
dataDir, err := c.ensureAppDataDir(ctx, appKey)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not retrieve app data dir")
|
||||
appEntry, exists := specs.Apps[appKey]
|
||||
if !exists {
|
||||
return nil, errors.Errorf("could not find app entry '%s'", appKey)
|
||||
}
|
||||
|
||||
dbFile := filepath.Join(dataDir, appKey+".sqlite")
|
||||
db, err := sqlite.Open(dbFile + defaultSQLiteParams)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not open database file '%s'", dbFile)
|
||||
storage := appEntry.Storage
|
||||
if storage == nil {
|
||||
return nil, errors.Errorf("could not find app entry '%s' storage configuration", appKey)
|
||||
}
|
||||
|
||||
shareDBFile := filepath.Join(dataDir, "shared.sqlite")
|
||||
shareDB, err := sqlite.Open(shareDBFile + defaultSQLiteParams)
|
||||
documentStore, err := driver.NewDocumentStore(appEntry.Storage.DocumentStoreDSN)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not open database file '%s'", shareDBFile)
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
blobStore, err := driver.NewBlobStore(appEntry.Storage.BlobStoreDSN)
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
shareStore, err := driver.NewShareStore(appEntry.Storage.ShareStoreDSN)
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
keySet, err := getAuthKeySet(specs.Config)
|
||||
|
@ -76,24 +88,37 @@ 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(),
|
||||
DocumentStore: sqlite.NewDocumentStoreWithDB(db),
|
||||
BlobStore: sqlite.NewBlobStoreWithDB(db),
|
||||
KeySet: keySet,
|
||||
AppRepository: c.appRepository,
|
||||
AppID: app.ID(appKey),
|
||||
ShareRepository: shareSqlite.NewRepositoryWithDB(shareDB),
|
||||
Bus: memory.NewBus(),
|
||||
DocumentStore: documentStore,
|
||||
BlobStore: blobStore,
|
||||
ShareStore: shareStore,
|
||||
KeySet: keySet,
|
||||
AppRepository: c.appRepository,
|
||||
AppID: app.ID(appKey),
|
||||
}
|
||||
|
||||
modules := c.getAppModules(deps)
|
||||
|
||||
anonymousUserMiddleware, err := getAnonymousUserMiddleware(specs.Config.Auth)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get anonymous user middleware")
|
||||
}
|
||||
|
||||
options := []edgeHTTP.HandlerOptionFunc{
|
||||
edgeHTTP.WithBus(deps.Bus),
|
||||
edgeHTTP.WithServerModules(modules...),
|
||||
edgeHTTP.WithHTTPMounts(mounts...),
|
||||
edgeHTTP.WithHTTPMiddlewares(
|
||||
anonymousUserMiddleware,
|
||||
),
|
||||
}
|
||||
|
||||
return options, nil
|
||||
|
@ -180,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
|
||||
|
@ -190,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),
|
||||
)
|
||||
|
||||
|
@ -202,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),
|
||||
)
|
||||
|
||||
|
@ -279,12 +307,12 @@ 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),
|
||||
appModule.ModuleFactory(deps.AppRepository),
|
||||
fetchModule.ModuleFactory(deps.Bus),
|
||||
shareModule.ModuleFactory(deps.AppID, deps.ShareRepository),
|
||||
shareModule.ModuleFactory(deps.AppID, deps.ShareStore),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
package app
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/app/spec"
|
||||
appSpec "forge.cadoles.com/Cadoles/emissary/internal/agent/controller/app/spec"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/jwk"
|
||||
"forge.cadoles.com/arcad/edge/pkg/app"
|
||||
"forge.cadoles.com/arcad/edge/pkg/module"
|
||||
"forge.cadoles.com/arcad/edge/pkg/module/auth"
|
||||
authModule "forge.cadoles.com/arcad/edge/pkg/module/auth"
|
||||
authHTTP "forge.cadoles.com/arcad/edge/pkg/module/auth/http"
|
||||
authModuleMiddleware "forge.cadoles.com/arcad/edge/pkg/module/auth/middleware"
|
||||
|
||||
"github.com/dop251/goja"
|
||||
"github.com/lestrrat-go/jwx/v2/jwa"
|
||||
"github.com/pkg/errors"
|
||||
|
@ -54,7 +57,7 @@ func authModuleFactory(keySet jwk.Set) app.ServerModuleFactory {
|
|||
)
|
||||
}
|
||||
|
||||
func getAuthMount(auth *spec.Auth, keySet jwk.Set) (auth.MountFunc, error) {
|
||||
func getAuthMount(auth *appSpec.Auth, keySet jwk.Set) (auth.MountFunc, error) {
|
||||
switch {
|
||||
case auth.Local != nil:
|
||||
var rawKey any = auth.Local.Key
|
||||
|
@ -77,7 +80,8 @@ func getAuthMount(auth *spec.Auth, keySet jwk.Set) (auth.MountFunc, error) {
|
|||
|
||||
return authModule.Mount(
|
||||
authHTTP.NewLocalHandler(
|
||||
jwa.HS256, key,
|
||||
key,
|
||||
jwa.HS256,
|
||||
authHTTP.WithRoutePrefix("/auth"),
|
||||
authHTTP.WithAccounts(auth.Local.Accounts...),
|
||||
authHTTP.WithCookieOptions(getCookieDomain, cookieDuration),
|
||||
|
@ -91,3 +95,72 @@ func getAuthMount(auth *spec.Auth, keySet jwk.Set) (auth.MountFunc, error) {
|
|||
return nil, nil
|
||||
}
|
||||
}
|
||||
|
||||
func getAnonymousUserMiddleware(auth *appSpec.Auth) (func(http.Handler) http.Handler, error) {
|
||||
anonymousUserSigningKey, err := getAnonymousUserSigningKey(auth)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get anonymous user signing key")
|
||||
}
|
||||
|
||||
cookieDuration := defaultCookieDuration
|
||||
if auth.Local.CookieDuration != "" {
|
||||
cookieDuration, err = time.ParseDuration(auth.Local.CookieDuration)
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
}
|
||||
|
||||
middleware := authModuleMiddleware.AnonymousUser(
|
||||
anonymousUserSigningKey,
|
||||
auth.Local.SigningAlgorithm,
|
||||
authModuleMiddleware.WithCookieOptions(getCookieDomain, cookieDuration),
|
||||
)
|
||||
|
||||
return middleware, nil
|
||||
}
|
||||
|
||||
func getAnonymousUserSigningKey(auth *appSpec.Auth) (jwk.Key, error) {
|
||||
var (
|
||||
key jwk.Key
|
||||
err error
|
||||
)
|
||||
|
||||
generateNewKey := func() (jwk.Key, error) {
|
||||
key, err := jwk.Generate(2048)
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
return key, nil
|
||||
}
|
||||
|
||||
switch {
|
||||
default:
|
||||
fallthrough
|
||||
case auth == nil:
|
||||
key, err = generateNewKey()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not generate anonymous user signing key")
|
||||
}
|
||||
|
||||
return key, nil
|
||||
|
||||
case auth.Local != nil:
|
||||
switch typedKey := auth.Local.Key.(type) {
|
||||
case string:
|
||||
key, err = jwk.FromRaw([]byte(typedKey))
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not parse local auth key")
|
||||
}
|
||||
|
||||
if err := key.Set(jwk.AlgorithmKey, jwa.HS256); err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
}
|
||||
|
||||
default:
|
||||
return nil, errors.Errorf("unexpected key type '%T'", auth.Local.Key)
|
||||
}
|
||||
}
|
||||
|
||||
return key, nil
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ func (c *Controller) Name() string {
|
|||
func (c *Controller) Reconcile(ctx context.Context, state *agent.State) error {
|
||||
appSpec := spec.NewSpec()
|
||||
|
||||
if err := state.GetSpec(spec.Name, appSpec); err != nil {
|
||||
if err := state.GetSpec(spec.Name, spec.Version, appSpec); err != nil {
|
||||
if errors.Is(err, agent.ErrSpecNotFound) {
|
||||
logger.Info(ctx, "could not find app spec")
|
||||
|
||||
|
@ -50,7 +50,12 @@ func (c *Controller) Reconcile(ctx context.Context, state *agent.State) error {
|
|||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
logger.Info(ctx, "retrieved spec", logger.F("spec", appSpec.SpecName()), logger.F("revision", appSpec.SpecRevision()))
|
||||
logger.Info(
|
||||
ctx, "retrieved spec",
|
||||
logger.F("name", appSpec.SpecDefinitionName()),
|
||||
logger.F("version", appSpec.SpecDefinitionVersion()),
|
||||
logger.F("revision", appSpec.SpecRevision()),
|
||||
)
|
||||
|
||||
c.updateApps(ctx, appSpec)
|
||||
|
||||
|
@ -66,10 +71,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 +93,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 +105,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 +119,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 +209,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 +228,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 {
|
||||
|
|
|
@ -8,15 +8,14 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/app/spec"
|
||||
appSpec "forge.cadoles.com/Cadoles/emissary/internal/agent/controller/app/spec"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/proxy/wildcard"
|
||||
edgeHTTP "forge.cadoles.com/arcad/edge/pkg/http"
|
||||
"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"
|
||||
|
@ -49,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")
|
||||
}
|
||||
|
||||
|
@ -73,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
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ func (s *Server) Stop() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func NewServer(bundle bundle.Bundle, config *spec.Config, handlerOptions ...edgeHTTP.HandlerOptionFunc) *Server {
|
||||
func NewServer(bundle bundle.Bundle, config *appSpec.Config, handlerOptions ...edgeHTTP.HandlerOptionFunc) *Server {
|
||||
return &Server{
|
||||
bundle: bundle,
|
||||
config: config,
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
var schema []byte
|
||||
|
||||
func init() {
|
||||
if err := spec.Register(Name, schema); err != nil {
|
||||
if err := spec.Register(string(Name), Version, schema); err != nil {
|
||||
panic(errors.WithStack(err))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$schema": "https://json-schema.org/draft/2019-09/schema",
|
||||
"$id": "https://app.edge.emissary.cadoles.com/spec.json",
|
||||
"title": "AppSpec",
|
||||
"description": "Emissary 'App' specification",
|
||||
|
@ -24,15 +24,37 @@
|
|||
"type": "string",
|
||||
"enum": [
|
||||
"zip",
|
||||
"tar.gz"
|
||||
"tar.gz",
|
||||
"zim"
|
||||
]
|
||||
},
|
||||
"storage": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"blobStoreDsn": {
|
||||
"type": "string"
|
||||
},
|
||||
"documentStoreDsn": {
|
||||
"type": "string"
|
||||
},
|
||||
"shareStoreDsn": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"blobStoreDsn",
|
||||
"documentStoreDsn",
|
||||
"shareStoreDsn"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"url",
|
||||
"sha256sum",
|
||||
"address",
|
||||
"format"
|
||||
"format",
|
||||
"storage"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
|
@ -56,7 +78,9 @@
|
|||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["defaultUrlTemplate"],
|
||||
"required": [
|
||||
"defaultUrlTemplate"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"unexpectedHostRedirect": {
|
||||
|
@ -72,7 +96,10 @@
|
|||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["acceptedHostPatterns", "hostTarget"],
|
||||
"required": [
|
||||
"acceptedHostPatterns",
|
||||
"hostTarget"
|
||||
],
|
||||
"additionalProperties": false
|
||||
},
|
||||
"auth": {
|
||||
|
@ -82,7 +109,13 @@
|
|||
"type": "object",
|
||||
"properties": {
|
||||
"key": {
|
||||
"type": ["object", "string"]
|
||||
"type": [
|
||||
"object",
|
||||
"string"
|
||||
]
|
||||
},
|
||||
"signingAlgorithm": {
|
||||
"type": "string"
|
||||
},
|
||||
"accounts": {
|
||||
"type": "array",
|
||||
|
@ -117,7 +150,8 @@
|
|||
}
|
||||
},
|
||||
"required": [
|
||||
"key"
|
||||
"key",
|
||||
"signingAlgorithm"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
||||
|
|
|
@ -3,9 +3,13 @@ package spec
|
|||
import (
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/spec"
|
||||
edgeAuth "forge.cadoles.com/arcad/edge/pkg/module/auth/http"
|
||||
"github.com/lestrrat-go/jwx/v2/jwa"
|
||||
)
|
||||
|
||||
const Name spec.Name = "app.emissary.cadoles.com"
|
||||
const (
|
||||
Name string = "app.emissary.cadoles.com"
|
||||
Version string = "0.0.0"
|
||||
)
|
||||
|
||||
type Spec struct {
|
||||
Revision int `json:"revision"`
|
||||
|
@ -14,10 +18,17 @@ type Spec struct {
|
|||
}
|
||||
|
||||
type AppEntry struct {
|
||||
URL string `json:"url"`
|
||||
SHA256Sum string `json:"sha256sum"`
|
||||
Address string `json:"address"`
|
||||
Format string `json:"format"`
|
||||
URL string `json:"url"`
|
||||
SHA256Sum string `json:"sha256sum"`
|
||||
Address string `json:"address"`
|
||||
Format string `json:"format"`
|
||||
Storage *AppStorage `json:"storage"`
|
||||
}
|
||||
|
||||
type AppStorage struct {
|
||||
ShareStoreDSN string `json:"shareStoreDsn"`
|
||||
DocumentStoreDSN string `json:"documentStoreDsn"`
|
||||
BlobStoreDSN string `json:"blobStoreDsn"`
|
||||
}
|
||||
|
||||
type Auth struct {
|
||||
|
@ -25,10 +36,11 @@ type Auth struct {
|
|||
}
|
||||
|
||||
type LocalAuth struct {
|
||||
Key any `json:"key"`
|
||||
Accounts []edgeAuth.LocalAccount `json:"accounts"`
|
||||
CookieDomain string `json:"cookieDomain"`
|
||||
CookieDuration string `json:"cookieDuration"`
|
||||
Key any `json:"key"`
|
||||
SigningAlgorithm jwa.SignatureAlgorithm `json:"signingAlgorithm"`
|
||||
Accounts []edgeAuth.LocalAccount `json:"accounts"`
|
||||
CookieDomain string `json:"cookieDomain"`
|
||||
CookieDuration string `json:"cookieDuration"`
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
|
@ -47,10 +59,14 @@ type AppURLResolving struct {
|
|||
DefaultURLTemplate string `json:"defaultUrlTemplate"`
|
||||
}
|
||||
|
||||
func (s *Spec) SpecName() spec.Name {
|
||||
func (s *Spec) SpecDefinitionName() string {
|
||||
return Name
|
||||
}
|
||||
|
||||
func (s *Spec) SpecDefinitionVersion() string {
|
||||
return Version
|
||||
}
|
||||
|
||||
func (s *Spec) SpecRevision() int {
|
||||
return s.Revision
|
||||
}
|
||||
|
|
|
@ -6,7 +6,12 @@
|
|||
"url": "http://example.com/edge.sdk.client.test_0.0.0.zip",
|
||||
"sha256sum": "58019192dacdae17755707719707db007e26dac856102280583fbd18427dd352",
|
||||
"address": ":8081",
|
||||
"format": "zip"
|
||||
"format": "zip",
|
||||
"storage": {
|
||||
"blobStoreDsn": "sqlite://apps/data/edge.sdk.client.test/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/edge.sdk.client.test/documentstore.sqlite?_pragma=foreign_keys(1)&_pragma=busy_timeout=60000"
|
||||
}
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
|
@ -23,6 +28,7 @@
|
|||
"q": "yJJLNc9w6O4y2icME8k99FugV9E7ObwUxF3v5JN3y1cmAT0h2njyE3iAGqaDZwcY1_jGCisjwoqX6i5E8xqhxX3Gcy3J7SmUAf8fhY8wU3zv9DK7skg2IdvanDb8Y1OM6GchbYZAOVPEg2IvVio8zI-Ih3DDwDk8Df0ufzoHRb8",
|
||||
"qi": "zOE-4R3cjPesm3MX-4PdwmsaF9QZLUVRUvvHJ08pKs6kAXP18hzjctAoOjhQDxlTYqNYNePfKzKwost3OJoPgRIc9w9qwUCK1gNOS4Z_xozCIaXgMddNFhkoAfZ4JaKjNCiinzjGfqG99Lf-yzmmREuuhRv7SdS3ST4VQjiJQew"
|
||||
},
|
||||
"signingAlgorithm": "RS256",
|
||||
"accounts": [
|
||||
{
|
||||
"username": "foo",
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/datastore/memory"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/spec"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
@ -27,11 +28,15 @@ var validatorTestCases = []validatorTestCase{
|
|||
func TestValidator(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
validator := spec.NewValidator()
|
||||
if err := validator.Register(Name, schema); err != nil {
|
||||
ctx := context.Background()
|
||||
|
||||
repo := memory.NewSpecDefinitionRepository()
|
||||
if _, err := repo.Upsert(ctx, Name, Version, schema); err != nil {
|
||||
t.Fatalf("+%v", errors.WithStack(err))
|
||||
}
|
||||
|
||||
validator := spec.NewValidator(repo)
|
||||
|
||||
for _, tc := range validatorTestCases {
|
||||
func(tc validatorTestCase) {
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
|
|
|
@ -33,7 +33,7 @@ func (c *Controller) Name() string {
|
|||
func (c *Controller) Reconcile(ctx context.Context, state *agent.State) error {
|
||||
mdnsSpec := mdns.NewSpec()
|
||||
|
||||
if err := state.GetSpec(mdns.Name, mdnsSpec); err != nil {
|
||||
if err := state.GetSpec(mdns.Name, mdns.Version, mdnsSpec); err != nil {
|
||||
if errors.Is(err, agent.ErrSpecNotFound) {
|
||||
logger.Info(ctx, "could not find mdns spec")
|
||||
|
||||
|
@ -45,7 +45,11 @@ func (c *Controller) Reconcile(ctx context.Context, state *agent.State) error {
|
|||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
logger.Info(ctx, "retrieved spec", logger.F("spec", mdnsSpec.SpecName()), logger.F("revision", mdnsSpec.SpecRevision()))
|
||||
logger.Info(ctx, "retrieved spec",
|
||||
logger.F("name", mdnsSpec.SpecDefinitionName()),
|
||||
logger.F("version", mdnsSpec.SpecDefinitionVersion()),
|
||||
logger.F("revision", mdnsSpec.SpecRevision()),
|
||||
)
|
||||
|
||||
if err := c.updateResponder(ctx, mdnsSpec); err != nil {
|
||||
return errors.Wrap(err, "could not update responder")
|
||||
|
@ -117,7 +121,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 +137,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 +154,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))
|
||||
}
|
||||
}()
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
var schema []byte
|
||||
|
||||
func init() {
|
||||
if err := spec.Register(Name, schema); err != nil {
|
||||
if err := spec.Register(string(Name), Version, schema); err != nil {
|
||||
panic(errors.WithStack(err))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$schema": "https://json-schema.org/draft/2019-09/schema",
|
||||
"$id": "https://mdns.edge.emissary.cadoles.com/spec.json",
|
||||
"title": "MDNSSpec",
|
||||
"description": "Emissary 'MDNS' specification",
|
||||
|
|
|
@ -4,7 +4,10 @@ import (
|
|||
"forge.cadoles.com/Cadoles/emissary/internal/spec"
|
||||
)
|
||||
|
||||
const Name spec.Name = "mdns.emissary.cadoles.com"
|
||||
const (
|
||||
Name string = "mdns.emissary.cadoles.com"
|
||||
Version string = "0.0.0"
|
||||
)
|
||||
|
||||
type Spec struct {
|
||||
Revision int `json:"revision"`
|
||||
|
@ -19,10 +22,14 @@ type Service struct {
|
|||
Port int `json:"port"`
|
||||
}
|
||||
|
||||
func (s *Spec) SpecName() spec.Name {
|
||||
func (s *Spec) SpecDefinitionName() string {
|
||||
return Name
|
||||
}
|
||||
|
||||
func (s *Spec) SpecDefinitionVersion() string {
|
||||
return Version
|
||||
}
|
||||
|
||||
func (s *Spec) SpecRevision() int {
|
||||
return s.Revision
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/datastore/memory"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/spec"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
@ -27,11 +28,15 @@ var validatorTestCases = []validatorTestCase{
|
|||
func TestValidator(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
validator := spec.NewValidator()
|
||||
if err := validator.Register(Name, schema); err != nil {
|
||||
ctx := context.Background()
|
||||
|
||||
repo := memory.NewSpecDefinitionRepository()
|
||||
if _, err := repo.Upsert(ctx, Name, Version, schema); err != nil {
|
||||
t.Fatalf("+%v", errors.WithStack(err))
|
||||
}
|
||||
|
||||
validator := spec.NewValidator(repo)
|
||||
|
||||
for _, tc := range validatorTestCases {
|
||||
func(tc validatorTestCase) {
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
|
|
|
@ -11,7 +11,7 @@ import (
|
|||
var schema []byte
|
||||
|
||||
func init() {
|
||||
if err := spec.Register(Name, schema); err != nil {
|
||||
if err := spec.Register(string(Name), Version, schema); err != nil {
|
||||
panic(errors.WithStack(err))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"$schema": "https://json-schema.org/draft/2019-09/schema",
|
||||
"$id": "https://sysupgrade.openwrt.emissary.cadoles.com/spec.json",
|
||||
"title": "SysUpgradeSpec",
|
||||
"description": "Emissary 'SysUpgrade' specification",
|
||||
|
@ -15,6 +15,10 @@
|
|||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["url", "sha256sum", "version"],
|
||||
"required": [
|
||||
"url",
|
||||
"sha256sum",
|
||||
"version"
|
||||
],
|
||||
"additionalProperties": false
|
||||
}
|
|
@ -4,7 +4,10 @@ import (
|
|||
"forge.cadoles.com/Cadoles/emissary/internal/spec"
|
||||
)
|
||||
|
||||
const Name spec.Name = "sysupgrade.openwrt.emissary.cadoles.com"
|
||||
const (
|
||||
Name string = "sysupgrade.openwrt.emissary.cadoles.com"
|
||||
Version string = "0.0.0"
|
||||
)
|
||||
|
||||
type Spec struct {
|
||||
Revision int `json:"revision"`
|
||||
|
@ -13,10 +16,14 @@ type Spec struct {
|
|||
Version string `json:"version"`
|
||||
}
|
||||
|
||||
func (s *Spec) SpecName() spec.Name {
|
||||
func (s *Spec) SpecDefinitionName() string {
|
||||
return Name
|
||||
}
|
||||
|
||||
func (s *Spec) SpecDefinitionVersion() string {
|
||||
return Version
|
||||
}
|
||||
|
||||
func (s *Spec) SpecRevision() int {
|
||||
return s.Revision
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import (
|
|||
"io/ioutil"
|
||||
"testing"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/datastore/memory"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/spec"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
@ -27,11 +28,15 @@ var validatorTestCases = []validatorTestCase{
|
|||
func TestValidator(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
validator := spec.NewValidator()
|
||||
if err := validator.Register(Name, schema); err != nil {
|
||||
ctx := context.Background()
|
||||
|
||||
repo := memory.NewSpecDefinitionRepository()
|
||||
if _, err := repo.Upsert(ctx, Name, Version, schema); err != nil {
|
||||
t.Fatalf("+%v", errors.WithStack(err))
|
||||
}
|
||||
|
||||
validator := spec.NewValidator(repo)
|
||||
|
||||
for _, tc := range validatorTestCases {
|
||||
func(tc validatorTestCase) {
|
||||
t.Run(tc.Name, func(t *testing.T) {
|
||||
|
|
|
@ -31,7 +31,7 @@ func (*SysUpgradeController) Name() string {
|
|||
func (c *SysUpgradeController) Reconcile(ctx context.Context, state *agent.State) error {
|
||||
sysSpec := sysupgrade.NewSpec()
|
||||
|
||||
if err := state.GetSpec(sysupgrade.Name, sysSpec); err != nil {
|
||||
if err := state.GetSpec(sysupgrade.Name, sysupgrade.Version, sysSpec); err != nil {
|
||||
if errors.Is(err, agent.ErrSpecNotFound) {
|
||||
logger.Info(ctx, "could not find sysupgrade spec, doing nothing")
|
||||
|
||||
|
@ -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),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -27,7 +27,7 @@ func (*UCIController) Name() string {
|
|||
func (c *UCIController) Reconcile(ctx context.Context, state *agent.State) error {
|
||||
uciSpec := ucispec.NewSpec()
|
||||
|
||||
if err := state.GetSpec(ucispec.NameUCI, uciSpec); err != nil {
|
||||
if err := state.GetSpec(ucispec.Name, ucispec.Version, uciSpec); err != nil {
|
||||
if errors.Is(err, agent.ErrSpecNotFound) {
|
||||
logger.Info(ctx, "could not find uci spec, doing nothing")
|
||||
|
||||
|
@ -37,7 +37,11 @@ func (c *UCIController) Reconcile(ctx context.Context, state *agent.State) error
|
|||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
logger.Info(ctx, "retrieved spec", logger.F("spec", uciSpec.SpecName()), logger.F("revision", uciSpec.SpecRevision()))
|
||||
logger.Info(ctx, "retrieved spec",
|
||||
logger.F("name", uciSpec.SpecDefinitionName()),
|
||||
logger.F("version", uciSpec.SpecDefinitionVersion()),
|
||||
logger.F("revision", uciSpec.SpecRevision()),
|
||||
)
|
||||
|
||||
if c.currentSpecRevision == uciSpec.SpecRevision() {
|
||||
logger.Info(ctx, "spec revision did not change, doing nothing")
|
||||
|
@ -46,7 +50,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
|
||||
}
|
||||
|
|
|
@ -9,13 +9,12 @@ import (
|
|||
"path/filepath"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/agent"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/spec"
|
||||
"github.com/pkg/errors"
|
||||
"gitlab.com/wpetit/goweb/logger"
|
||||
)
|
||||
|
||||
type Controller struct {
|
||||
trackedSpecRevisions map[spec.Name]int
|
||||
trackedSpecRevisions map[string]map[string]int
|
||||
filename string
|
||||
loaded bool
|
||||
}
|
||||
|
@ -78,36 +77,39 @@ func (c *Controller) specChanged(specs agent.Specs) bool {
|
|||
return true
|
||||
}
|
||||
|
||||
for name, spec := range specs {
|
||||
trackedRevision, exists := c.trackedSpecRevisions[name]
|
||||
for name, specVersions := range specs {
|
||||
trackedSpecs, exists := c.trackedSpecRevisions[name]
|
||||
if !exists {
|
||||
return true
|
||||
}
|
||||
|
||||
if trackedRevision != spec.SpecRevision() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
for version, spec := range specVersions {
|
||||
trackedRevision, exists := trackedSpecs[version]
|
||||
if !exists {
|
||||
return true
|
||||
}
|
||||
|
||||
for trackedSpecName, trackedRevision := range c.trackedSpecRevisions {
|
||||
spec, exists := specs[trackedSpecName]
|
||||
if !exists {
|
||||
return true
|
||||
if trackedRevision != spec.SpecRevision() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
if trackedRevision != spec.SpecRevision() {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
func (c *Controller) trackSpecsRevisions(specs agent.Specs) {
|
||||
c.trackedSpecRevisions = make(map[spec.Name]int)
|
||||
c.trackedSpecRevisions = make(map[string]map[string]int)
|
||||
|
||||
for name, spec := range specs {
|
||||
c.trackedSpecRevisions[name] = spec.SpecRevision()
|
||||
for name, specVersions := range specs {
|
||||
if _, exists := c.trackedSpecRevisions[name]; !exists {
|
||||
c.trackedSpecRevisions[name] = make(map[string]int)
|
||||
}
|
||||
|
||||
for version, spec := range specVersions {
|
||||
c.trackedSpecRevisions[name][version] = spec.SpecRevision()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -145,7 +147,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 +158,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))
|
||||
}
|
||||
}()
|
||||
|
||||
|
@ -165,7 +169,7 @@ func (c *Controller) writeState(ctx context.Context, state *agent.State) error {
|
|||
}
|
||||
|
||||
name := f.Name()
|
||||
if err := ioutil.WriteFile(name, data, os.ModePerm); err != nil {
|
||||
if err := os.WriteFile(name, data, os.ModePerm); err != nil {
|
||||
return errors.Errorf("cannot write data to temporary file %q: %v", name, err)
|
||||
}
|
||||
|
||||
|
@ -211,7 +215,7 @@ func (c *Controller) writeState(ctx context.Context, state *agent.State) error {
|
|||
func NewController(filename string) *Controller {
|
||||
return &Controller{
|
||||
filename: filename,
|
||||
trackedSpecRevisions: make(map[spec.Name]int),
|
||||
trackedSpecRevisions: make(map[string]map[string]int),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,7 @@ func (c *Controller) Name() string {
|
|||
func (c *Controller) Reconcile(ctx context.Context, state *agent.State) error {
|
||||
proxySpec := spec.NewSpec()
|
||||
|
||||
if err := state.GetSpec(spec.NameProxy, proxySpec); err != nil {
|
||||
if err := state.GetSpec(spec.Name, spec.Version, proxySpec); err != nil {
|
||||
if errors.Is(err, agent.ErrSpecNotFound) {
|
||||
logger.Info(ctx, "could not find proxy spec")
|
||||
|
||||
|
@ -42,7 +42,12 @@ func (c *Controller) Reconcile(ctx context.Context, state *agent.State) error {
|
|||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
logger.Info(ctx, "retrieved spec", logger.F("spec", proxySpec.SpecName()), logger.F("revision", proxySpec.SpecRevision()))
|
||||
logger.Info(
|
||||
ctx, "retrieved spec",
|
||||
logger.F("name", proxySpec.SpecDefinitionName()),
|
||||
logger.F("version", proxySpec.SpecDefinitionVersion()),
|
||||
logger.F("revision", proxySpec.SpecRevision()),
|
||||
)
|
||||
|
||||
c.updateProxies(ctx, proxySpec)
|
||||
|
||||
|
@ -58,10 +63,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 +85,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 +101,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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}()
|
||||
|
||||
|
|
|
@ -40,21 +40,34 @@ 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)
|
||||
specHeaders, err := client.QueryAgentSpecs(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 query agent specs", logger.CapturedE(err))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
state.ClearSpecs()
|
||||
|
||||
for _, spec := range specs {
|
||||
for _, sh := range specHeaders {
|
||||
spec, err := client.GetAgentSpec(ctx, agent.ID, sh.DefinitionName, sh.DefinitionVersion)
|
||||
if err != nil {
|
||||
logger.Error(
|
||||
ctx, "could not retrieve agent spec",
|
||||
logger.F("specName", sh.DefinitionName),
|
||||
logger.F("specVersion", sh.DefinitionVersion),
|
||||
logger.CapturedE(errors.WithStack(err)),
|
||||
)
|
||||
|
||||
continue
|
||||
}
|
||||
|
||||
state.SetSpec(spec)
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,138 @@
|
|||
package status
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"sync/atomic"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/agent"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/datastore"
|
||||
"github.com/pkg/errors"
|
||||
"gitlab.com/wpetit/goweb/api"
|
||||
"gitlab.com/wpetit/goweb/logger"
|
||||
)
|
||||
|
||||
type Status struct {
|
||||
Agent *datastore.Agent
|
||||
Connected bool
|
||||
Claimed bool
|
||||
Thumbprint string
|
||||
ServerURL string
|
||||
ClaimURL string
|
||||
AgentURL string
|
||||
AgentVersion string
|
||||
}
|
||||
|
||||
type Controller struct {
|
||||
status *atomic.Value
|
||||
server *atomic.Value
|
||||
addr string
|
||||
claimURL string
|
||||
agentURL string
|
||||
agentVersion string
|
||||
}
|
||||
|
||||
// Name implements node.Controller.
|
||||
func (c *Controller) Name() string {
|
||||
return "status-controller"
|
||||
}
|
||||
|
||||
// Reconcile implements node.Controller.
|
||||
func (c *Controller) Reconcile(ctx context.Context, state *agent.State) error {
|
||||
cl := agent.Client(ctx)
|
||||
thumbprint := agent.Thumbprint(ctx)
|
||||
|
||||
connected := true
|
||||
|
||||
agent, err := cl.GetAgent(ctx, state.AgentID())
|
||||
if err != nil {
|
||||
logger.Error(ctx, "could not get agent", logger.E(errors.WithStack(err)))
|
||||
var apiErr *api.Error
|
||||
if errors.As(err, &apiErr) {
|
||||
switch apiErr.Code {
|
||||
case api.ErrCodeForbidden:
|
||||
// Contact is ok but agent may be not claimed yet
|
||||
default:
|
||||
connected = false
|
||||
}
|
||||
} else {
|
||||
connected = false
|
||||
}
|
||||
}
|
||||
|
||||
claimed := agent != nil && agent.TenantID != nil
|
||||
var agentID datastore.AgentID
|
||||
if agent != nil {
|
||||
agentID = agent.ID
|
||||
}
|
||||
|
||||
c.status.Store(Status{
|
||||
Agent: agent,
|
||||
Connected: connected,
|
||||
Claimed: claimed,
|
||||
Thumbprint: thumbprint,
|
||||
ServerURL: cl.ServerURL(),
|
||||
ClaimURL: fmt.Sprintf(c.claimURL, thumbprint),
|
||||
AgentURL: fmt.Sprintf(c.agentURL, agentID),
|
||||
AgentVersion: c.agentVersion,
|
||||
})
|
||||
|
||||
if err := c.startServer(ctx); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Controller) startServer(ctx context.Context) error {
|
||||
server := c.getServer()
|
||||
if server != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
server = &http.Server{
|
||||
Addr: c.addr,
|
||||
Handler: &Handler{
|
||||
status: c.status,
|
||||
},
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer c.setServer(nil)
|
||||
|
||||
if err := server.ListenAndServe(); err != nil {
|
||||
logger.Error(ctx, "could not start server", logger.E(errors.WithStack(err)))
|
||||
}
|
||||
}()
|
||||
|
||||
c.setServer(server)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Controller) setServer(s *http.Server) {
|
||||
c.server.Store(s)
|
||||
}
|
||||
|
||||
func (c *Controller) getServer() *http.Server {
|
||||
server, ok := c.server.Load().(*http.Server)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
func NewController(addr string, claimURL string, agentURL string, agentVersion string) *Controller {
|
||||
return &Controller{
|
||||
addr: addr,
|
||||
claimURL: claimURL,
|
||||
agentURL: agentURL,
|
||||
agentVersion: agentVersion,
|
||||
status: &atomic.Value{},
|
||||
server: &atomic.Value{},
|
||||
}
|
||||
}
|
||||
|
||||
var _ agent.Controller = &Controller{}
|
|
@ -0,0 +1,74 @@
|
|||
package status
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"html/template"
|
||||
"io/fs"
|
||||
"net/http"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"gitlab.com/wpetit/goweb/logger"
|
||||
)
|
||||
|
||||
//go:embed templates/*.gotpl
|
||||
var templates embed.FS
|
||||
|
||||
//go:embed public/*
|
||||
var public embed.FS
|
||||
|
||||
type Handler struct {
|
||||
status *atomic.Value
|
||||
|
||||
public http.Handler
|
||||
templates *template.Template
|
||||
|
||||
init sync.Once
|
||||
initErr error
|
||||
}
|
||||
|
||||
// ServeHTTP implements http.Handler.
|
||||
func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
h.init.Do(func() {
|
||||
root, err := fs.Sub(public, "public")
|
||||
if err != nil {
|
||||
h.initErr = errors.WithStack(err)
|
||||
return
|
||||
}
|
||||
|
||||
h.public = http.FileServer(http.FS(root))
|
||||
|
||||
tmpl, err := template.ParseFS(templates, "templates/*.gotpl")
|
||||
if err != nil {
|
||||
h.initErr = errors.WithStack(err)
|
||||
return
|
||||
}
|
||||
|
||||
h.templates = tmpl
|
||||
})
|
||||
if h.initErr != nil {
|
||||
logger.Error(r.Context(), "could not initialize handler", logger.E(h.initErr))
|
||||
http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
switch r.URL.Path {
|
||||
case "/":
|
||||
h.serveIndex(w, r)
|
||||
default:
|
||||
h.public.ServeHTTP(w, r)
|
||||
}
|
||||
}
|
||||
|
||||
func (h *Handler) serveIndex(w http.ResponseWriter, r *http.Request) {
|
||||
data := h.status.Load()
|
||||
|
||||
if err := h.templates.ExecuteTemplate(w, "index.html.gotpl", data); err != nil {
|
||||
logger.Error(r.Context(), "could not render template", logger.E(errors.WithStack(err)))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
var _ http.Handler = &Handler{}
|
File diff suppressed because one or more lines are too long
Binary file not shown.
After Width: | Height: | Size: 36 KiB |
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,145 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="icon" type="image/x-icon" href="logo.png">
|
||||
<title>Status | Emissary Agent</title>
|
||||
<link rel="stylesheet" href="bulma-0.9.4.min.css">
|
||||
<style>
|
||||
body {
|
||||
background-color: #f7f7f7f7;
|
||||
}
|
||||
.logo {
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
margin-left: -40px;
|
||||
width: 100px;
|
||||
margin-top: -120px
|
||||
}
|
||||
.card {
|
||||
position:relative;
|
||||
padding-top: 70px;
|
||||
margin-top: 70px;
|
||||
}
|
||||
#qrcode {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
}
|
||||
</style>
|
||||
{{if or .Connected ( not .Claimed ) }}
|
||||
<script type="text/javascript" src="qrcode.min.js"></script>
|
||||
{{ end }}
|
||||
</head>
|
||||
<body>
|
||||
<section class="section">
|
||||
<div class="container">
|
||||
<div class="column">
|
||||
<div class="has-text-centered">
|
||||
<h1 class="title is-size-1 ">Emissary</h1>
|
||||
<h2 class="subtitle is-size-4">Agent Status</h2>
|
||||
</div>
|
||||
<div class="box card">
|
||||
<img class="logo" src="logo.png" />
|
||||
<div class="overflow:hidden">
|
||||
<div class="level is-mobile" style="margin-top:-50px">
|
||||
<div class="level-left">
|
||||
<div class="level-item is-size-4-tablet is-size-7-mobile">
|
||||
<strong class="mr-2">Connected:</strong>{{if .Connected }}<span class="has-text-success">✔</span>{{ else }}<span class="has-text-danger">✕</span>{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="level-right">
|
||||
<div class="level-item is-size-4-tablet is-size-7-mobile">
|
||||
<strong class="mr-2">Claimed:</strong>{{if .Claimed }}<span class="has-text-success">✔</span>{{ else }}<span class="has-text-warning">✕</span>{{ end }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{ if and .Connected ( not .Claimed ) }}
|
||||
<h3 class="is-size-3 mt-4">Claim your agent</h3>
|
||||
<p class="has-text-centered">
|
||||
You can claim your agent by clicking the following link:<br />
|
||||
<a class="button is-link is-medium mt-3" href="{{ .ClaimURL }}" target="_blank" rel="nofollow">Claim me</a><br />
|
||||
</p>
|
||||
<p class="has-text-centered mt-3">
|
||||
You can also scan the following QRCode:
|
||||
<div id="qrcode" class="mt-3" data-claim-url="{{ .ClaimURL }}"></div>
|
||||
<script type="text/javascript">
|
||||
(function() {
|
||||
const qrCodeElement = document.getElementById("qrcode");
|
||||
const claimUrl = qrCodeElement.dataset.claimUrl;
|
||||
new QRCode(qrCodeElement, claimUrl);
|
||||
}())
|
||||
</script>
|
||||
</p>
|
||||
{{ end }}
|
||||
{{ if and .Connected .Claimed }}
|
||||
<h3 class="is-size-3 mt-4">Manage your agent</h3>
|
||||
<p class="has-text-centered">
|
||||
You can manage your agent by clicking the following link:<br />
|
||||
<a class="button is-link is-medium mt-3" href="{{ .AgentURL }}" target="_blank" rel="nofollow">Manage me</a><br />
|
||||
</p>
|
||||
<p class="has-text-centered mt-3">
|
||||
You can also scan the following QRCode:
|
||||
<div id="qrcode" class="mt-3" data-agent-url="{{ .AgentURL }}"></div>
|
||||
<script type="text/javascript">
|
||||
(function() {
|
||||
const qrCodeElement = document.getElementById("qrcode");
|
||||
const agentUrl = qrCodeElement.dataset.agentUrl;
|
||||
new QRCode(qrCodeElement, agentUrl);
|
||||
}())
|
||||
</script>
|
||||
</p>
|
||||
{{ end }}
|
||||
<h3 class="is-size-3 mt-4">Informations</h3>
|
||||
<div class="table-container">
|
||||
<table class="table is-fullwidth">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Attribute</th>
|
||||
<th>Value</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Thumbprint</td>
|
||||
<td><code>{{ .Thumbprint }}</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Agent ID</td>
|
||||
<td><code>{{ if .Agent }}{{ .Agent.ID }}{{ else }}unknown{{end}}</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Agent Label</td>
|
||||
<td><code>{{ with .Agent }}{{ if .Label }}{{ .Label }}{{ else }}empty{{end}}{{ else }}unknown{{end}}</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Last server contact</td>
|
||||
<td><code>{{ if .Agent }}{{ .Agent.ContactedAt }}{{ else }}unknown{{end}}</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Server URL</td>
|
||||
<td><code>{{ .ServerURL }}</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Claim URL</td>
|
||||
<td><code>{{ .ClaimURL }}</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Agent URL</td>
|
||||
<td><code>{{ if .Agent }}{{ .AgentURL }}{{ else }}unknown{{end}}</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Agent version</td>
|
||||
<td><code>{{ .AgentVersion }}</code></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
|
@ -11,7 +11,7 @@ import (
|
|||
|
||||
var ErrSpecNotFound = errors.New("spec not found")
|
||||
|
||||
type Specs map[spec.Name]spec.Spec
|
||||
type Specs map[string]map[string]spec.Spec
|
||||
|
||||
type State struct {
|
||||
agentID datastore.AgentID
|
||||
|
@ -20,25 +20,33 @@ type State struct {
|
|||
|
||||
func NewState() *State {
|
||||
return &State{
|
||||
specs: make(map[spec.Name]spec.Spec),
|
||||
specs: make(map[string]map[string]spec.Spec),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *State) MarshalJSON() ([]byte, error) {
|
||||
state := struct {
|
||||
ID datastore.AgentID `json:"agentId"`
|
||||
Specs map[spec.Name]*spec.RawSpec `json:"specs"`
|
||||
ID datastore.AgentID `json:"agentId"`
|
||||
Specs map[string]map[string]*spec.RawSpec `json:"specs"`
|
||||
}{
|
||||
ID: s.agentID,
|
||||
Specs: func(specs map[spec.Name]spec.Spec) map[spec.Name]*spec.RawSpec {
|
||||
rawSpecs := make(map[spec.Name]*spec.RawSpec)
|
||||
Specs: func(specs map[string]map[string]spec.Spec) map[string]map[string]*spec.RawSpec {
|
||||
rawSpecs := make(map[string]map[string]*spec.RawSpec)
|
||||
|
||||
for name, sp := range specs {
|
||||
rawSpecs[name] = &spec.RawSpec{
|
||||
Name: sp.SpecName(),
|
||||
Revision: sp.SpecRevision(),
|
||||
Data: sp.SpecData(),
|
||||
for name, versions := range specs {
|
||||
if _, exists := rawSpecs[name]; !exists {
|
||||
rawSpecs[name] = make(map[string]*spec.RawSpec)
|
||||
}
|
||||
|
||||
for version, sp := range versions {
|
||||
rawSpecs[name][version] = &spec.RawSpec{
|
||||
DefinitionName: sp.SpecDefinitionName(),
|
||||
DefinitionVersion: sp.SpecDefinitionVersion(),
|
||||
Revision: sp.SpecRevision(),
|
||||
Data: sp.SpecData(),
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return rawSpecs
|
||||
|
@ -55,19 +63,24 @@ func (s *State) MarshalJSON() ([]byte, error) {
|
|||
|
||||
func (s *State) UnmarshalJSON(data []byte) error {
|
||||
state := struct {
|
||||
AgentID datastore.AgentID `json:"agentId"`
|
||||
Specs map[spec.Name]*spec.RawSpec `json:"specs"`
|
||||
AgentID datastore.AgentID `json:"agentId"`
|
||||
Specs map[string]map[string]*spec.RawSpec `json:"specs"`
|
||||
}{}
|
||||
|
||||
if err := json.Unmarshal(data, &state); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
s.specs = func(rawSpecs map[spec.Name]*spec.RawSpec) Specs {
|
||||
s.specs = func(rawSpecs map[string]map[string]*spec.RawSpec) Specs {
|
||||
specs := make(Specs)
|
||||
|
||||
for name, raw := range rawSpecs {
|
||||
specs[name] = spec.Spec(raw)
|
||||
for name, versions := range rawSpecs {
|
||||
if _, exists := specs[name]; !exists {
|
||||
specs[name] = make(map[string]spec.Spec)
|
||||
}
|
||||
for version, raw := range versions {
|
||||
specs[name][version] = spec.Spec(raw)
|
||||
}
|
||||
}
|
||||
|
||||
return specs
|
||||
|
@ -85,23 +98,36 @@ func (s *State) Specs() Specs {
|
|||
}
|
||||
|
||||
func (s *State) ClearSpecs() *State {
|
||||
s.specs = make(map[spec.Name]spec.Spec)
|
||||
s.specs = make(map[string]map[string]spec.Spec)
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *State) SetSpec(sp spec.Spec) *State {
|
||||
if s.specs == nil {
|
||||
s.specs = make(map[spec.Name]spec.Spec)
|
||||
s.specs = make(map[string]map[string]spec.Spec)
|
||||
}
|
||||
|
||||
s.specs[sp.SpecName()] = sp
|
||||
name := sp.SpecDefinitionName()
|
||||
|
||||
if _, exists := s.specs[name]; !exists {
|
||||
s.specs[name] = make(map[string]spec.Spec)
|
||||
}
|
||||
|
||||
version := sp.SpecDefinitionVersion()
|
||||
|
||||
s.specs[name][version] = sp
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func (s *State) GetSpec(name spec.Name, dest any) error {
|
||||
spec, exists := s.specs[name]
|
||||
func (s *State) GetSpec(name string, version string, dest any) error {
|
||||
versions, exists := s.specs[name]
|
||||
if !exists {
|
||||
return errors.WithStack(ErrSpecNotFound)
|
||||
}
|
||||
|
||||
spec, exists := versions[version]
|
||||
if !exists {
|
||||
return errors.WithStack(ErrSpecNotFound)
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ import (
|
|||
"github.com/lestrrat-go/jwx/v2/jws"
|
||||
"github.com/lestrrat-go/jwx/v2/jwt"
|
||||
"github.com/pkg/errors"
|
||||
"gitlab.com/wpetit/goweb/logger"
|
||||
)
|
||||
|
||||
const DefaultAcceptableSkew = 5 * time.Minute
|
||||
|
@ -34,17 +35,19 @@ func (a *Authenticator) Authenticate(ctx context.Context, r *http.Request) (auth
|
|||
|
||||
token, err := jwt.Parse([]byte(rawToken), jwt.WithVerify(false))
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
logger.Debug(ctx, "could not parse jwt token", logger.CapturedE(errors.WithStack(err)))
|
||||
return nil, errors.WithStack(auth.ErrUnauthenticated)
|
||||
}
|
||||
|
||||
rawThumbprint, exists := token.Get(keyThumbprint)
|
||||
if !exists {
|
||||
return nil, errors.Errorf("could not find '%s' claim", keyThumbprint)
|
||||
return nil, errors.WithStack(auth.ErrUnauthenticated)
|
||||
}
|
||||
|
||||
thumbrint, ok := rawThumbprint.(string)
|
||||
if !ok {
|
||||
return nil, errors.Errorf("unexpected '%s' claim value: '%v'", keyThumbprint, rawThumbprint)
|
||||
logger.Debug(ctx, "unexpected claim value", logger.F("claim", rawThumbprint), logger.F("value", rawThumbprint))
|
||||
return nil, errors.WithStack(auth.ErrUnauthenticated)
|
||||
}
|
||||
|
||||
agents, _, err := a.repo.Query(
|
||||
|
@ -57,7 +60,8 @@ func (a *Authenticator) Authenticate(ctx context.Context, r *http.Request) (auth
|
|||
}
|
||||
|
||||
if len(agents) != 1 {
|
||||
return nil, errors.Errorf("unexpected number of found agents: '%d'", len(agents))
|
||||
logger.Debug(ctx, "unexpected number of found agents", logger.F("total", len(agents)))
|
||||
return nil, errors.WithStack(auth.ErrUnauthenticated)
|
||||
}
|
||||
|
||||
agent, err := a.repo.Get(
|
||||
|
@ -75,14 +79,15 @@ func (a *Authenticator) Authenticate(ctx context.Context, r *http.Request) (auth
|
|||
jwt.WithAcceptableSkew(a.acceptableSkew),
|
||||
)
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
logger.Error(ctx, "could not parse jwt", logger.CapturedE(errors.WithStack(err)))
|
||||
return nil, errors.WithStack(auth.ErrUnauthenticated)
|
||||
}
|
||||
|
||||
contactedAt := time.Now()
|
||||
contactedAt := time.Now().UTC()
|
||||
|
||||
agent, err = a.repo.Update(ctx, agent.ID, datastore.WithAgentUpdateContactedAt(contactedAt))
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
return nil, errors.WithStack(auth.ErrUnauthenticated)
|
||||
}
|
||||
|
||||
user := &User{
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package agent
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/auth"
|
||||
|
@ -16,8 +17,31 @@ func (u *User) Subject() string {
|
|||
return fmt.Sprintf("agent-%d", u.agent.ID)
|
||||
}
|
||||
|
||||
// Subject implements auth.User
|
||||
func (u *User) Tenant() datastore.TenantID {
|
||||
if u.agent.TenantID == nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
return *u.agent.TenantID
|
||||
}
|
||||
|
||||
func (u *User) Agent() *datastore.Agent {
|
||||
return u.agent
|
||||
}
|
||||
|
||||
func (u *User) MarshalJSON() ([]byte, error) {
|
||||
type user struct {
|
||||
Subject string `json:"subject"`
|
||||
Tenant string `json:"tenant"`
|
||||
}
|
||||
|
||||
jsonUser := user{
|
||||
Subject: u.Subject(),
|
||||
Tenant: string(u.Tenant()),
|
||||
}
|
||||
|
||||
return json.Marshal(jsonUser)
|
||||
}
|
||||
|
||||
var _ auth.User = &User{}
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
package auth
|
||||
|
||||
import "github.com/pkg/errors"
|
||||
|
||||
var (
|
||||
ErrUnauthenticated = errors.New("unauthenticated")
|
||||
ErrUnauthorized = errors.New(("unauthorized"))
|
||||
)
|
|
@ -4,6 +4,7 @@ import (
|
|||
"context"
|
||||
"net/http"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/datastore"
|
||||
"github.com/pkg/errors"
|
||||
"gitlab.com/wpetit/goweb/api"
|
||||
"gitlab.com/wpetit/goweb/logger"
|
||||
|
@ -29,10 +30,9 @@ func CtxUser(ctx context.Context) (User, error) {
|
|||
return user, nil
|
||||
}
|
||||
|
||||
var ErrUnauthenticated = errors.New("unauthenticated")
|
||||
|
||||
type User interface {
|
||||
Subject() string
|
||||
Tenant() datastore.TenantID
|
||||
}
|
||||
|
||||
type Authenticator interface {
|
||||
|
@ -49,11 +49,12 @@ func Middleware(authenticators ...Authenticator) func(http.Handler) http.Handler
|
|||
err error
|
||||
)
|
||||
|
||||
var errs []error
|
||||
|
||||
for _, auth := range authenticators {
|
||||
user, err = auth.Authenticate(ctx, r)
|
||||
if err != nil {
|
||||
logger.Debug(ctx, "could not authenticate request", logger.E(errors.WithStack(err)))
|
||||
|
||||
errs = append(errs, errors.WithStack(err))
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -63,9 +64,22 @@ func Middleware(authenticators ...Authenticator) func(http.Handler) http.Handler
|
|||
}
|
||||
|
||||
if user == nil {
|
||||
api.ErrorResponse(w, http.StatusUnauthorized, ErrCodeUnauthorized, nil)
|
||||
hasUnauthorized, hasUnauthenticated, hasUnknown := checkErrors(errs)
|
||||
|
||||
return
|
||||
switch {
|
||||
case hasUnauthorized && !hasUnknown:
|
||||
api.ErrorResponse(w, http.StatusForbidden, api.ErrCodeForbidden, nil)
|
||||
return
|
||||
case hasUnauthenticated && !hasUnknown:
|
||||
api.ErrorResponse(w, http.StatusUnauthorized, api.ErrCodeUnauthorized, nil)
|
||||
return
|
||||
case hasUnknown:
|
||||
api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil)
|
||||
return
|
||||
default:
|
||||
api.ErrorResponse(w, http.StatusUnauthorized, ErrCodeUnauthorized, nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
ctx = logger.With(ctx, logger.F("user", user.Subject()))
|
||||
|
@ -77,3 +91,22 @@ func Middleware(authenticators ...Authenticator) func(http.Handler) http.Handler
|
|||
return http.HandlerFunc(fn)
|
||||
}
|
||||
}
|
||||
|
||||
func checkErrors(errs []error) (isUnauthorized bool, isUnauthenticated bool, isUnknown bool) {
|
||||
isUnauthenticated = false
|
||||
isUnauthorized = false
|
||||
isUnknown = false
|
||||
|
||||
for _, e := range errs {
|
||||
switch {
|
||||
case errors.Is(e, ErrUnauthorized):
|
||||
isUnauthorized = true
|
||||
case errors.Is(e, ErrUnauthenticated):
|
||||
isUnauthenticated = true
|
||||
default:
|
||||
isUnknown = true
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
@ -1,32 +0,0 @@
|
|||
package thirdparty
|
||||
|
||||
import "forge.cadoles.com/Cadoles/emissary/internal/auth"
|
||||
|
||||
type Role string
|
||||
|
||||
const (
|
||||
RoleWriter Role = "writer"
|
||||
RoleReader Role = "reader"
|
||||
)
|
||||
|
||||
func isValidRole(r string) bool {
|
||||
rr := Role(r)
|
||||
|
||||
return rr == RoleWriter || rr == RoleReader
|
||||
}
|
||||
|
||||
type User struct {
|
||||
subject string
|
||||
role Role
|
||||
}
|
||||
|
||||
// Subject implements auth.User
|
||||
func (u *User) Subject() string {
|
||||
return u.subject
|
||||
}
|
||||
|
||||
func (u *User) Role() Role {
|
||||
return u.role
|
||||
}
|
||||
|
||||
var _ auth.User = &User{}
|
|
@ -1,4 +1,4 @@
|
|||
package thirdparty
|
||||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@ -7,21 +7,25 @@ import (
|
|||
"time"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/auth"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/datastore"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/jwk"
|
||||
"github.com/lestrrat-go/jwx/v2/jwt"
|
||||
"github.com/pkg/errors"
|
||||
"gitlab.com/wpetit/goweb/logger"
|
||||
)
|
||||
|
||||
const DefaultAcceptableSkew = 5 * time.Minute
|
||||
|
||||
type (
|
||||
GetKeySet func(context.Context) (jwk.Set, error)
|
||||
GetTokenRole func(context.Context, jwt.Token) (string, error)
|
||||
GetKeySet func(context.Context) (jwk.Set, error)
|
||||
GetTokenRole func(context.Context, jwt.Token) (string, error)
|
||||
GetTokenTenant func(context.Context, jwt.Token) (string, error)
|
||||
)
|
||||
|
||||
type Authenticator struct {
|
||||
getKeySet GetKeySet
|
||||
getTokenRole GetTokenRole
|
||||
getTokenTenant GetTokenTenant
|
||||
acceptableSkew time.Duration
|
||||
}
|
||||
|
||||
|
@ -44,29 +48,45 @@ func (a *Authenticator) Authenticate(ctx context.Context, r *http.Request) (auth
|
|||
|
||||
token, err := parseToken(ctx, keys, rawToken, a.acceptableSkew)
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
logger.Debug(ctx, "could not parse jwt token", logger.CapturedE(errors.WithStack(err)))
|
||||
return nil, errors.WithStack(auth.ErrUnauthenticated)
|
||||
}
|
||||
|
||||
rawRole, err := a.getTokenRole(ctx, token)
|
||||
if err != nil {
|
||||
return nil, errors.WithStack(err)
|
||||
logger.Debug(ctx, "could not retrieve token role", logger.CapturedE(errors.WithStack(err)))
|
||||
return nil, errors.WithStack(auth.ErrUnauthenticated)
|
||||
}
|
||||
|
||||
if !isValidRole(rawRole) {
|
||||
return nil, errors.Errorf("invalid role '%s'", rawRole)
|
||||
return nil, errors.WithStack(auth.ErrUnauthorized)
|
||||
}
|
||||
|
||||
rawTenantID, err := a.getTokenTenant(ctx, token)
|
||||
if err != nil {
|
||||
logger.Debug(ctx, "could not retrieve token tenant", logger.CapturedE(errors.WithStack(err)))
|
||||
return nil, errors.WithStack(auth.ErrUnauthenticated)
|
||||
}
|
||||
|
||||
tenantID, err := datastore.ParseTenantID(rawTenantID)
|
||||
if err != nil {
|
||||
logger.Debug(ctx, "could not retrieve token tenant", logger.CapturedE(errors.WithStack(err)))
|
||||
return nil, errors.WithStack(auth.ErrUnauthenticated)
|
||||
}
|
||||
|
||||
user := &User{
|
||||
subject: token.Subject(),
|
||||
role: Role(rawRole),
|
||||
subject: token.Subject(),
|
||||
role: Role(rawRole),
|
||||
tenantID: tenantID,
|
||||
}
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func NewAuthenticator(getKeySet GetKeySet, getTokenRole GetTokenRole, acceptableSkew time.Duration) *Authenticator {
|
||||
func NewAuthenticator(getKeySet GetKeySet, getTokenRole GetTokenRole, getTokenTenant GetTokenTenant, acceptableSkew time.Duration) *Authenticator {
|
||||
return &Authenticator{
|
||||
getTokenRole: getTokenRole,
|
||||
getTokenTenant: getTokenTenant,
|
||||
getKeySet: getKeySet,
|
||||
acceptableSkew: acceptableSkew,
|
||||
}
|
|
@ -1,9 +1,10 @@
|
|||
package thirdparty
|
||||
package user
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/datastore"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/jwk"
|
||||
"github.com/lestrrat-go/jwx/v2/jwa"
|
||||
"github.com/lestrrat-go/jwx/v2/jws"
|
||||
|
@ -26,9 +27,12 @@ func parseToken(ctx context.Context, keys jwk.Set, rawToken string, acceptableSk
|
|||
return token, nil
|
||||
}
|
||||
|
||||
const DefaultRoleKey string = "role"
|
||||
const (
|
||||
DefaultRoleKey string = "role"
|
||||
DefaultTenantKey string = "tenant"
|
||||
)
|
||||
|
||||
func GenerateToken(ctx context.Context, key jwk.Key, subject string, role Role) (string, error) {
|
||||
func GenerateToken(ctx context.Context, key jwk.Key, tenant datastore.TenantID, subject string, role Role) (string, error) {
|
||||
token := jwt.New()
|
||||
|
||||
if err := token.Set(jwt.SubjectKey, subject); err != nil {
|
||||
|
@ -39,6 +43,10 @@ func GenerateToken(ctx context.Context, key jwk.Key, subject string, role Role)
|
|||
return "", errors.WithStack(err)
|
||||
}
|
||||
|
||||
if err := token.Set(DefaultTenantKey, tenant); err != nil {
|
||||
return "", errors.WithStack(err)
|
||||
}
|
||||
|
||||
now := time.Now().UTC()
|
||||
|
||||
if err := token.Set(jwt.NotBeforeKey, now); err != nil {
|
|
@ -0,0 +1,60 @@
|
|||
package user
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/auth"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/datastore"
|
||||
)
|
||||
|
||||
type Role string
|
||||
|
||||
const (
|
||||
RoleWriter Role = "writer"
|
||||
RoleReader Role = "reader"
|
||||
RoleAdmin Role = "admin"
|
||||
)
|
||||
|
||||
func isValidRole(r string) bool {
|
||||
rr := Role(r)
|
||||
|
||||
return rr == RoleWriter || rr == RoleReader || rr == RoleAdmin
|
||||
}
|
||||
|
||||
type User struct {
|
||||
subject string
|
||||
tenantID datastore.TenantID
|
||||
role Role
|
||||
}
|
||||
|
||||
// Subject implements auth.User
|
||||
func (u *User) Subject() string {
|
||||
return u.subject
|
||||
}
|
||||
|
||||
// Tenant implements auth.User
|
||||
func (u *User) Tenant() datastore.TenantID {
|
||||
return u.tenantID
|
||||
}
|
||||
|
||||
func (u *User) Role() Role {
|
||||
return u.role
|
||||
}
|
||||
|
||||
func (u *User) MarshalJSON() ([]byte, error) {
|
||||
type user struct {
|
||||
Subject string `json:"subject"`
|
||||
Tenant string `json:"tenant"`
|
||||
Role string `json:"role"`
|
||||
}
|
||||
|
||||
jsonUser := user{
|
||||
Subject: u.Subject(),
|
||||
Tenant: string(u.Tenant()),
|
||||
Role: string(u.Role()),
|
||||
}
|
||||
|
||||
return json.Marshal(jsonUser)
|
||||
}
|
||||
|
||||
var _ auth.User = &User{}
|
|
@ -10,6 +10,7 @@ import (
|
|||
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/persistence"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/proxy"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/spec"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/controller/status"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/metadata"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/metadata/collector/buildinfo"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/agent/metadata/collector/shell"
|
||||
|
@ -94,6 +95,15 @@ func RunCommand() *cli.Command {
|
|||
))
|
||||
}
|
||||
|
||||
if ctrlConf.Status.Enabled {
|
||||
controllers = append(controllers, status.NewController(
|
||||
string(ctrlConf.Status.Address),
|
||||
string(ctrlConf.Status.ClaimURL),
|
||||
string(ctrlConf.Status.AgentURL),
|
||||
string(ctx.String("projectVersion")),
|
||||
))
|
||||
}
|
||||
|
||||
key, err := jwk.LoadOrGenerate(string(conf.Agent.PrivateKeyPath), jwk.DefaultKeySize)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
|
@ -104,6 +114,10 @@ func RunCommand() *cli.Command {
|
|||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
logger.SetLevel(logger.LevelInfo)
|
||||
logger.Info(ctx.Context, "agent thumbprint", logger.F("thumbprint", thumbprint))
|
||||
logger.SetLevel(logger.Level(conf.Logger.Level))
|
||||
|
||||
collectors := createShellCollectors(&conf.Agent)
|
||||
collectors = append(collectors, buildinfo.NewCollector())
|
||||
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
package api
|
||||
|
||||
import (
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/api/agent"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func Root() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "api",
|
||||
Usage: "API related commands",
|
||||
Subcommands: []*cli.Command{
|
||||
agent.Root(),
|
||||
},
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package agent
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/client/apierr"
|
||||
clientFlag "forge.cadoles.com/Cadoles/emissary/internal/command/client/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/pkg/client"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli/v2"
|
||||
"gitlab.com/wpetit/goweb/cli/format"
|
||||
)
|
||||
|
||||
func ClaimCommand() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "claim",
|
||||
Usage: "Claim agent",
|
||||
Flags: clientFlag.ComposeFlags(
|
||||
&cli.StringFlag{
|
||||
Name: "agent-thumbprint",
|
||||
Value: "",
|
||||
Required: true,
|
||||
},
|
||||
),
|
||||
Action: func(ctx *cli.Context) error {
|
||||
baseFlags := clientFlag.GetBaseFlags(ctx)
|
||||
|
||||
token, err := clientFlag.GetToken(baseFlags)
|
||||
if err != nil {
|
||||
return errors.WithStack(apierr.Wrap(err))
|
||||
}
|
||||
|
||||
agentThumbprint := ctx.String("agent-thumbprint")
|
||||
|
||||
client := client.New(baseFlags.ServerURL, client.WithToken(token))
|
||||
|
||||
agent, err := client.ClaimAgent(ctx.Context, agentThumbprint)
|
||||
if err != nil {
|
||||
return errors.WithStack(apierr.Wrap(err))
|
||||
}
|
||||
|
||||
hints := agentHints(baseFlags.OutputMode)
|
||||
|
||||
if err := format.Write(baseFlags.Format, os.Stdout, hints, agent); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
|
@ -3,12 +3,12 @@ package agent
|
|||
import (
|
||||
"os"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/api/apierr"
|
||||
clientFlag "forge.cadoles.com/Cadoles/emissary/internal/command/api/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/format"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/client/apierr"
|
||||
clientFlag "forge.cadoles.com/Cadoles/emissary/internal/command/client/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/pkg/client"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli/v2"
|
||||
"gitlab.com/wpetit/goweb/cli/format"
|
||||
)
|
||||
|
||||
func CountCommand() *cli.Command {
|
|
@ -3,14 +3,14 @@ package agent
|
|||
import (
|
||||
"os"
|
||||
|
||||
agentFlag "forge.cadoles.com/Cadoles/emissary/internal/command/api/agent/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/api/apierr"
|
||||
clientFlag "forge.cadoles.com/Cadoles/emissary/internal/command/api/flag"
|
||||
agentFlag "forge.cadoles.com/Cadoles/emissary/internal/command/client/agent/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/client/apierr"
|
||||
clientFlag "forge.cadoles.com/Cadoles/emissary/internal/command/client/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/datastore"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/format"
|
||||
"forge.cadoles.com/Cadoles/emissary/pkg/client"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli/v2"
|
||||
"gitlab.com/wpetit/goweb/cli/format"
|
||||
)
|
||||
|
||||
func DeleteCommand() *cli.Command {
|
|
@ -3,7 +3,7 @@ package flag
|
|||
import (
|
||||
"errors"
|
||||
|
||||
clientFlag "forge.cadoles.com/Cadoles/emissary/internal/command/api/flag"
|
||||
clientFlag "forge.cadoles.com/Cadoles/emissary/internal/command/client/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/datastore"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
|
@ -3,13 +3,13 @@ package agent
|
|||
import (
|
||||
"os"
|
||||
|
||||
agentFlag "forge.cadoles.com/Cadoles/emissary/internal/command/api/agent/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/api/apierr"
|
||||
clientFlag "forge.cadoles.com/Cadoles/emissary/internal/command/api/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/format"
|
||||
agentFlag "forge.cadoles.com/Cadoles/emissary/internal/command/client/agent/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/client/apierr"
|
||||
clientFlag "forge.cadoles.com/Cadoles/emissary/internal/command/client/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/pkg/client"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli/v2"
|
||||
"gitlab.com/wpetit/goweb/cli/format"
|
||||
)
|
||||
|
||||
func GetCommand() *cli.Command {
|
|
@ -1,6 +1,9 @@
|
|||
package agent
|
||||
|
||||
import "forge.cadoles.com/Cadoles/emissary/internal/format"
|
||||
import (
|
||||
"gitlab.com/wpetit/goweb/cli/format"
|
||||
"gitlab.com/wpetit/goweb/cli/format/table"
|
||||
)
|
||||
|
||||
func agentHints(outputMode format.OutputMode) format.Hints {
|
||||
return format.Hints{
|
||||
|
@ -10,8 +13,8 @@ func agentHints(outputMode format.OutputMode) format.Hints {
|
|||
format.NewProp("Label", "Label"),
|
||||
format.NewProp("Thumbprint", "Thumbprint"),
|
||||
format.NewProp("Status", "Status"),
|
||||
format.NewProp("ContactedAt", "ContactedAt"),
|
||||
format.NewProp("UpdatedAt", "UpdatedAt"),
|
||||
format.NewProp("ContactedAt", "ContactedAt", table.WithCompactModeMaxColumnWidth(20)),
|
||||
format.NewProp("UpdatedAt", "UpdatedAt", table.WithCompactModeMaxColumnWidth(20)),
|
||||
},
|
||||
}
|
||||
}
|
|
@ -3,13 +3,13 @@ package agent
|
|||
import (
|
||||
"os"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/api/apierr"
|
||||
clientFlag "forge.cadoles.com/Cadoles/emissary/internal/command/api/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/client/apierr"
|
||||
clientFlag "forge.cadoles.com/Cadoles/emissary/internal/command/client/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/datastore"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/format"
|
||||
"forge.cadoles.com/Cadoles/emissary/pkg/client"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli/v2"
|
||||
"gitlab.com/wpetit/goweb/cli/format"
|
||||
)
|
||||
|
||||
func QueryCommand() *cli.Command {
|
|
@ -1,7 +1,7 @@
|
|||
package agent
|
||||
|
||||
import (
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/api/agent/spec"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/client/agent/spec"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
|
@ -15,6 +15,7 @@ func Root() *cli.Command {
|
|||
UpdateCommand(),
|
||||
GetCommand(),
|
||||
DeleteCommand(),
|
||||
ClaimCommand(),
|
||||
spec.Root(),
|
||||
},
|
||||
}
|
|
@ -3,14 +3,13 @@ package spec
|
|||
import (
|
||||
"os"
|
||||
|
||||
agentFlag "forge.cadoles.com/Cadoles/emissary/internal/command/api/agent/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/api/apierr"
|
||||
clientFlag "forge.cadoles.com/Cadoles/emissary/internal/command/api/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/format"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/spec"
|
||||
agentFlag "forge.cadoles.com/Cadoles/emissary/internal/command/client/agent/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/client/apierr"
|
||||
clientFlag "forge.cadoles.com/Cadoles/emissary/internal/command/client/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/pkg/client"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli/v2"
|
||||
"gitlab.com/wpetit/goweb/cli/format"
|
||||
)
|
||||
|
||||
func DeleteCommand() *cli.Command {
|
||||
|
@ -23,6 +22,11 @@ func DeleteCommand() *cli.Command {
|
|||
Name: "spec-name",
|
||||
Usage: "use `NAME` as specification's name",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "spec-version",
|
||||
Usage: "use `VERSION` as specification's version",
|
||||
Value: "0.0.0",
|
||||
},
|
||||
),
|
||||
Action: func(ctx *cli.Context) error {
|
||||
baseFlags := clientFlag.GetBaseFlags(ctx)
|
||||
|
@ -37,14 +41,19 @@ func DeleteCommand() *cli.Command {
|
|||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
specName, err := assertSpecName(ctx)
|
||||
specDefName, err := assertSpecDefName(ctx)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
specDefVersion, err := assertSpecDefVersion(ctx)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
client := client.New(baseFlags.ServerURL, client.WithToken(token))
|
||||
|
||||
specName, err = client.DeleteAgentSpec(ctx.Context, agentID, specName)
|
||||
specDefName, specDefVersion, err = client.DeleteAgentSpec(ctx.Context, agentID, specDefName, specDefVersion)
|
||||
if err != nil {
|
||||
return errors.WithStack(apierr.Wrap(err))
|
||||
}
|
||||
|
@ -54,9 +63,11 @@ func DeleteCommand() *cli.Command {
|
|||
}
|
||||
|
||||
if err := format.Write(baseFlags.Format, os.Stdout, hints, struct {
|
||||
Name spec.Name `json:"name"`
|
||||
Name string `json:"name"`
|
||||
Version string `json:"version"`
|
||||
}{
|
||||
Name: specName,
|
||||
Name: specDefName,
|
||||
Version: specDefVersion,
|
||||
}); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package spec
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
agentFlag "forge.cadoles.com/Cadoles/emissary/internal/command/client/agent/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/client/apierr"
|
||||
clientFlag "forge.cadoles.com/Cadoles/emissary/internal/command/client/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/pkg/client"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli/v2"
|
||||
"gitlab.com/wpetit/goweb/cli/format"
|
||||
)
|
||||
|
||||
func GetCommand() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "get",
|
||||
Usage: "Get agent specification",
|
||||
Flags: agentFlag.WithAgentFlags(
|
||||
&cli.StringFlag{
|
||||
Name: "spec-name",
|
||||
Usage: "use `NAME` as specification's name",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "spec-version",
|
||||
Usage: "use `VERSION` as specification's version",
|
||||
Value: "0.0.0",
|
||||
},
|
||||
),
|
||||
Action: func(ctx *cli.Context) error {
|
||||
baseFlags := clientFlag.GetBaseFlags(ctx)
|
||||
agentID, err := agentFlag.AssertAgentID(ctx)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
token, err := clientFlag.GetToken(baseFlags)
|
||||
if err != nil {
|
||||
return errors.WithStack(apierr.Wrap(err))
|
||||
}
|
||||
|
||||
specDefName, err := assertSpecDefName(ctx)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
specDefVersion, err := assertSpecDefVersion(ctx)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
client := client.New(baseFlags.ServerURL, client.WithToken(token))
|
||||
|
||||
spec, err := client.GetAgentSpec(ctx.Context, agentID, specDefName, specDefVersion)
|
||||
if err != nil {
|
||||
return errors.WithStack(apierr.Wrap(err))
|
||||
}
|
||||
|
||||
hints := specHints(baseFlags.OutputMode)
|
||||
|
||||
if err := format.Write(baseFlags.Format, os.Stdout, hints, spec); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package spec
|
||||
|
||||
import (
|
||||
"gitlab.com/wpetit/goweb/cli/format"
|
||||
"gitlab.com/wpetit/goweb/cli/format/table"
|
||||
)
|
||||
|
||||
func specHeaderHints(outputMode format.OutputMode) format.Hints {
|
||||
return format.Hints{
|
||||
OutputMode: outputMode,
|
||||
Props: []format.Prop{
|
||||
format.NewProp("ID", "ID"),
|
||||
format.NewProp("DefinitionName", "Def. Name"),
|
||||
format.NewProp("DefinitionVersion", "Def. Version"),
|
||||
format.NewProp("Revision", "Revision"),
|
||||
format.NewProp("CreatedAt", "CreatedAt", table.WithCompactModeMaxColumnWidth(20)),
|
||||
format.NewProp("UpdatedAt", "UpdatedAt", table.WithCompactModeMaxColumnWidth(20)),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func specHints(outputMode format.OutputMode) format.Hints {
|
||||
return format.Hints{
|
||||
OutputMode: outputMode,
|
||||
Props: []format.Prop{
|
||||
format.NewProp("ID", "ID"),
|
||||
format.NewProp("DefinitionName", "Def. Name"),
|
||||
format.NewProp("DefinitionVersion", "Def. Version"),
|
||||
format.NewProp("Revision", "Revision"),
|
||||
format.NewProp("Data", "Data"),
|
||||
format.NewProp("CreatedAt", "CreatedAt", table.WithCompactModeMaxColumnWidth(20)),
|
||||
format.NewProp("UpdatedAt", "UpdatedAt", table.WithCompactModeMaxColumnWidth(20)),
|
||||
},
|
||||
}
|
||||
}
|
|
@ -3,19 +3,19 @@ package spec
|
|||
import (
|
||||
"os"
|
||||
|
||||
agentFlag "forge.cadoles.com/Cadoles/emissary/internal/command/api/agent/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/api/apierr"
|
||||
clientFlag "forge.cadoles.com/Cadoles/emissary/internal/command/api/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/format"
|
||||
agentFlag "forge.cadoles.com/Cadoles/emissary/internal/command/client/agent/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/client/apierr"
|
||||
clientFlag "forge.cadoles.com/Cadoles/emissary/internal/command/client/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/pkg/client"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli/v2"
|
||||
"gitlab.com/wpetit/goweb/cli/format"
|
||||
)
|
||||
|
||||
func GetCommand() *cli.Command {
|
||||
func QueryCommand() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "get",
|
||||
Usage: "Get agent specifications",
|
||||
Name: "query",
|
||||
Usage: "Query agent specifications",
|
||||
Flags: agentFlag.WithAgentFlags(),
|
||||
Action: func(ctx *cli.Context) error {
|
||||
baseFlags := clientFlag.GetBaseFlags(ctx)
|
||||
|
@ -31,14 +31,12 @@ func GetCommand() *cli.Command {
|
|||
|
||||
client := client.New(baseFlags.ServerURL, client.WithToken(token))
|
||||
|
||||
specs, err := client.GetAgentSpecs(ctx.Context, agentID)
|
||||
specs, err := client.QueryAgentSpecs(ctx.Context, agentID)
|
||||
if err != nil {
|
||||
return errors.WithStack(apierr.Wrap(err))
|
||||
}
|
||||
|
||||
hints := format.Hints{
|
||||
OutputMode: baseFlags.OutputMode,
|
||||
}
|
||||
hints := specHeaderHints(baseFlags.OutputMode)
|
||||
|
||||
if err := format.Write(baseFlags.Format, os.Stdout, hints, clientFlag.AsAnySlice(specs)...); err != nil {
|
||||
return errors.WithStack(err)
|
|
@ -10,6 +10,7 @@ func Root() *cli.Command {
|
|||
Usage: "Specifications related commands",
|
||||
Subcommands: []*cli.Command{
|
||||
GetCommand(),
|
||||
QueryCommand(),
|
||||
UpdateCommand(),
|
||||
DeleteCommand(),
|
||||
},
|
|
@ -4,15 +4,16 @@ import (
|
|||
"encoding/json"
|
||||
"os"
|
||||
|
||||
agentFlag "forge.cadoles.com/Cadoles/emissary/internal/command/api/agent/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/api/apierr"
|
||||
clientFlag "forge.cadoles.com/Cadoles/emissary/internal/command/api/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/format"
|
||||
agentFlag "forge.cadoles.com/Cadoles/emissary/internal/command/client/agent/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/client/apierr"
|
||||
clientFlag "forge.cadoles.com/Cadoles/emissary/internal/command/client/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/spec"
|
||||
"forge.cadoles.com/Cadoles/emissary/pkg/client"
|
||||
jsonpatch "github.com/evanphx/json-patch/v5"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli/v2"
|
||||
"gitlab.com/wpetit/goweb/api"
|
||||
"gitlab.com/wpetit/goweb/cli/format"
|
||||
)
|
||||
|
||||
func UpdateCommand() *cli.Command {
|
||||
|
@ -24,6 +25,11 @@ func UpdateCommand() *cli.Command {
|
|||
Name: "spec-name",
|
||||
Usage: "use `NAME` as specification's name",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "spec-version",
|
||||
Usage: "use `VERSION` as specification's version",
|
||||
Value: "0.0.0",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "spec-data",
|
||||
Usage: "use `DATA` as specification's data, '-' to read from STDIN",
|
||||
|
@ -44,7 +50,12 @@ func UpdateCommand() *cli.Command {
|
|||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
specName, err := assertSpecName(ctx)
|
||||
specDefName, err := assertSpecDefName(ctx)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
specDefVersion, err := assertSpecDefVersion(ctx)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
@ -63,21 +74,12 @@ func UpdateCommand() *cli.Command {
|
|||
|
||||
client := client.New(baseFlags.ServerURL, client.WithToken(token))
|
||||
|
||||
specs, err := client.GetAgentSpecs(ctx.Context, agentID)
|
||||
existingSpec, err := client.GetAgentSpec(ctx.Context, agentID, specDefName, specDefVersion)
|
||||
if err != nil {
|
||||
return errors.WithStack(apierr.Wrap(err))
|
||||
}
|
||||
|
||||
var existingSpec spec.Spec
|
||||
|
||||
for _, s := range specs {
|
||||
if s.SpecName() != specName {
|
||||
continue
|
||||
var apiErr api.Error
|
||||
if !errors.As(err, &apiErr) || apiErr.Code != api.ErrCodeNotFound {
|
||||
return errors.WithStack(apierr.Wrap(err))
|
||||
}
|
||||
|
||||
existingSpec = s
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
revision := 0
|
||||
|
@ -100,13 +102,10 @@ func UpdateCommand() *cli.Command {
|
|||
}
|
||||
|
||||
rawSpec := &spec.RawSpec{
|
||||
Name: specName,
|
||||
Revision: revision,
|
||||
Data: specData,
|
||||
}
|
||||
|
||||
if err := spec.Validate(ctx.Context, rawSpec); err != nil {
|
||||
return errors.WithStack(apierr.Wrap(err))
|
||||
DefinitionName: specDefName,
|
||||
DefinitionVersion: specDefVersion,
|
||||
Revision: revision,
|
||||
Data: specData,
|
||||
}
|
||||
|
||||
spec, err := client.UpdateAgentSpec(ctx.Context, agentID, rawSpec)
|
||||
|
@ -114,9 +113,7 @@ func UpdateCommand() *cli.Command {
|
|||
return errors.WithStack(apierr.Wrap(err))
|
||||
}
|
||||
|
||||
hints := format.Hints{
|
||||
OutputMode: baseFlags.OutputMode,
|
||||
}
|
||||
hints := specHints(baseFlags.OutputMode)
|
||||
|
||||
if err := format.Write(baseFlags.Format, os.Stdout, hints, spec); err != nil {
|
||||
return errors.WithStack(err)
|
||||
|
@ -127,14 +124,24 @@ func UpdateCommand() *cli.Command {
|
|||
}
|
||||
}
|
||||
|
||||
func assertSpecName(ctx *cli.Context) (spec.Name, error) {
|
||||
specName := ctx.String("spec-name")
|
||||
func assertSpecDefName(ctx *cli.Context) (string, error) {
|
||||
specDefName := ctx.String("spec-name")
|
||||
|
||||
if specName == "" {
|
||||
if specDefName == "" {
|
||||
return "", errors.New("flag 'spec-name' is required")
|
||||
}
|
||||
|
||||
return spec.Name(specName), nil
|
||||
return specDefName, nil
|
||||
}
|
||||
|
||||
func assertSpecDefVersion(ctx *cli.Context) (string, error) {
|
||||
specDefVersion := ctx.String("spec-version")
|
||||
|
||||
if specDefVersion == "" {
|
||||
return "", errors.New("flag 'spec-name' is required")
|
||||
}
|
||||
|
||||
return specDefVersion, nil
|
||||
}
|
||||
|
||||
func assertSpecData(ctx *cli.Context) (map[string]any, error) {
|
|
@ -3,13 +3,13 @@ package agent
|
|||
import (
|
||||
"os"
|
||||
|
||||
agentFlag "forge.cadoles.com/Cadoles/emissary/internal/command/api/agent/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/api/apierr"
|
||||
clientFlag "forge.cadoles.com/Cadoles/emissary/internal/command/api/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/format"
|
||||
agentFlag "forge.cadoles.com/Cadoles/emissary/internal/command/client/agent/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/client/apierr"
|
||||
clientFlag "forge.cadoles.com/Cadoles/emissary/internal/command/client/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/pkg/client"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli/v2"
|
||||
"gitlab.com/wpetit/goweb/cli/format"
|
||||
)
|
||||
|
||||
func UpdateCommand() *cli.Command {
|
|
@ -5,10 +5,10 @@ import (
|
|||
"os"
|
||||
"strings"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/format"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/format/table"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli/v2"
|
||||
"gitlab.com/wpetit/goweb/cli/format"
|
||||
"gitlab.com/wpetit/goweb/cli/format/table"
|
||||
)
|
||||
|
||||
const (
|
|
@ -0,0 +1,18 @@
|
|||
package client
|
||||
|
||||
import (
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/client/agent"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/client/tenant"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func Root() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "client",
|
||||
Usage: "API client related commands",
|
||||
Subcommands: []*cli.Command{
|
||||
agent.Root(),
|
||||
tenant.Root(),
|
||||
},
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package tenant
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/client/apierr"
|
||||
clientFlag "forge.cadoles.com/Cadoles/emissary/internal/command/client/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/pkg/client"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli/v2"
|
||||
"gitlab.com/wpetit/goweb/cli/format"
|
||||
)
|
||||
|
||||
func CreateCommand() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "create",
|
||||
Usage: "Create tenant",
|
||||
Flags: clientFlag.ComposeFlags(
|
||||
&cli.StringFlag{
|
||||
Name: "tenant-label",
|
||||
Usage: "Set `TENANT_LABEL` to targeted tenant",
|
||||
Value: "",
|
||||
},
|
||||
),
|
||||
Action: func(ctx *cli.Context) error {
|
||||
baseFlags := clientFlag.GetBaseFlags(ctx)
|
||||
|
||||
token, err := clientFlag.GetToken(baseFlags)
|
||||
if err != nil {
|
||||
return errors.WithStack(apierr.Wrap(err))
|
||||
}
|
||||
|
||||
tenantLabel := ctx.String("tenant-label")
|
||||
|
||||
client := client.New(baseFlags.ServerURL, client.WithToken(token))
|
||||
|
||||
agent, err := client.CreateTenant(ctx.Context, tenantLabel)
|
||||
if err != nil {
|
||||
return errors.WithStack(apierr.Wrap(err))
|
||||
}
|
||||
|
||||
hints := tenantHints(baseFlags.OutputMode)
|
||||
|
||||
if err := format.Write(baseFlags.Format, os.Stdout, hints, agent); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package tenant
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/client/apierr"
|
||||
clientFlag "forge.cadoles.com/Cadoles/emissary/internal/command/client/flag"
|
||||
tenantFlag "forge.cadoles.com/Cadoles/emissary/internal/command/client/tenant/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/datastore"
|
||||
"forge.cadoles.com/Cadoles/emissary/pkg/client"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli/v2"
|
||||
"gitlab.com/wpetit/goweb/cli/format"
|
||||
)
|
||||
|
||||
func DeleteCommand() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "delete",
|
||||
Usage: "Delete tenant",
|
||||
Flags: tenantFlag.WithTenantFlags(),
|
||||
Action: func(ctx *cli.Context) error {
|
||||
baseFlags := clientFlag.GetBaseFlags(ctx)
|
||||
|
||||
token, err := clientFlag.GetToken(baseFlags)
|
||||
if err != nil {
|
||||
return errors.WithStack(apierr.Wrap(err))
|
||||
}
|
||||
|
||||
tenantID, err := tenantFlag.AssertTenantID(ctx)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
client := client.New(baseFlags.ServerURL, client.WithToken(token))
|
||||
|
||||
tenantID, err = client.DeleteTenant(ctx.Context, tenantID)
|
||||
if err != nil {
|
||||
return errors.WithStack(apierr.Wrap(err))
|
||||
}
|
||||
|
||||
hints := format.Hints{
|
||||
OutputMode: baseFlags.OutputMode,
|
||||
}
|
||||
|
||||
if err := format.Write(baseFlags.Format, os.Stdout, hints, struct {
|
||||
ID datastore.TenantID `json:"id"`
|
||||
}{
|
||||
ID: tenantID,
|
||||
}); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
package flag
|
||||
|
||||
import (
|
||||
clientFlag "forge.cadoles.com/Cadoles/emissary/internal/command/client/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/datastore"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func WithTenantFlags(flags ...cli.Flag) []cli.Flag {
|
||||
baseFlags := clientFlag.ComposeFlags(
|
||||
&cli.StringFlag{
|
||||
Name: "tenant-id",
|
||||
Usage: "use `TENANT_ID` as targeted tenant",
|
||||
Value: "",
|
||||
},
|
||||
)
|
||||
|
||||
flags = append(flags, baseFlags...)
|
||||
|
||||
return flags
|
||||
}
|
||||
|
||||
func AssertTenantID(ctx *cli.Context) (datastore.TenantID, error) {
|
||||
rawTenantID := ctx.String("tenant-id")
|
||||
|
||||
if rawTenantID == "" {
|
||||
return "", errors.New("flag 'tenant-id' is required")
|
||||
}
|
||||
|
||||
tenantID, err := datastore.ParseTenantID(rawTenantID)
|
||||
if err != nil {
|
||||
return "", errors.WithStack(err)
|
||||
}
|
||||
|
||||
return tenantID, nil
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package tenant
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/client/apierr"
|
||||
clientFlag "forge.cadoles.com/Cadoles/emissary/internal/command/client/flag"
|
||||
tenantFlag "forge.cadoles.com/Cadoles/emissary/internal/command/client/tenant/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/pkg/client"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli/v2"
|
||||
"gitlab.com/wpetit/goweb/cli/format"
|
||||
)
|
||||
|
||||
func GetCommand() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "get",
|
||||
Usage: "Get tenant",
|
||||
Flags: tenantFlag.WithTenantFlags(),
|
||||
Action: func(ctx *cli.Context) error {
|
||||
baseFlags := clientFlag.GetBaseFlags(ctx)
|
||||
|
||||
token, err := clientFlag.GetToken(baseFlags)
|
||||
if err != nil {
|
||||
return errors.WithStack(apierr.Wrap(err))
|
||||
}
|
||||
|
||||
tenantID, err := tenantFlag.AssertTenantID(ctx)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
client := client.New(baseFlags.ServerURL, client.WithToken(token))
|
||||
|
||||
agent, err := client.GetTenant(ctx.Context, tenantID)
|
||||
if err != nil {
|
||||
return errors.WithStack(apierr.Wrap(err))
|
||||
}
|
||||
|
||||
hints := tenantHints(baseFlags.OutputMode)
|
||||
|
||||
if err := format.Write(baseFlags.Format, os.Stdout, hints, agent); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
package tenant
|
||||
|
||||
import (
|
||||
"gitlab.com/wpetit/goweb/cli/format"
|
||||
"gitlab.com/wpetit/goweb/cli/format/table"
|
||||
)
|
||||
|
||||
func tenantHints(outputMode format.OutputMode) format.Hints {
|
||||
return format.Hints{
|
||||
OutputMode: outputMode,
|
||||
Props: []format.Prop{
|
||||
format.NewProp("ID", "ID", table.WithCompactModeMaxColumnWidth(8)),
|
||||
format.NewProp("Label", "Label"),
|
||||
format.NewProp("CreatedAt", "CreatedAt", table.WithCompactModeMaxColumnWidth(20)),
|
||||
format.NewProp("UpdatedAt", "UpdatedAt", table.WithCompactModeMaxColumnWidth(20)),
|
||||
},
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
package tenant
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/client/apierr"
|
||||
clientFlag "forge.cadoles.com/Cadoles/emissary/internal/command/client/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/datastore"
|
||||
"forge.cadoles.com/Cadoles/emissary/pkg/client"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli/v2"
|
||||
"gitlab.com/wpetit/goweb/cli/format"
|
||||
)
|
||||
|
||||
func QueryCommand() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "query",
|
||||
Usage: "Query tenants",
|
||||
Flags: clientFlag.ComposeFlags(
|
||||
&cli.Int64SliceFlag{
|
||||
Name: "ids",
|
||||
Usage: "use `IDS` as query filter",
|
||||
},
|
||||
),
|
||||
Action: func(ctx *cli.Context) error {
|
||||
baseFlags := clientFlag.GetBaseFlags(ctx)
|
||||
|
||||
token, err := clientFlag.GetToken(baseFlags)
|
||||
if err != nil {
|
||||
return errors.WithStack(apierr.Wrap(err))
|
||||
}
|
||||
|
||||
options := make([]client.QueryTenantsOptionFunc, 0)
|
||||
|
||||
rawIDs := ctx.StringSlice("ids")
|
||||
if rawIDs != nil {
|
||||
tenantIDs := func(ids []string) []datastore.TenantID {
|
||||
tenantIDs := make([]datastore.TenantID, len(ids))
|
||||
for i, id := range ids {
|
||||
tenantIDs[i] = datastore.TenantID(id)
|
||||
}
|
||||
return tenantIDs
|
||||
}(rawIDs)
|
||||
options = append(options, client.WithQueryTenantsID(tenantIDs...))
|
||||
}
|
||||
|
||||
client := client.New(baseFlags.ServerURL, client.WithToken(token))
|
||||
|
||||
tenants, _, err := client.QueryTenants(ctx.Context, options...)
|
||||
if err != nil {
|
||||
return errors.WithStack(apierr.Wrap(err))
|
||||
}
|
||||
|
||||
hints := tenantHints(baseFlags.OutputMode)
|
||||
|
||||
if err := format.Write(baseFlags.Format, os.Stdout, hints, clientFlag.AsAnySlice(tenants)...); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
package tenant
|
||||
|
||||
import (
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func Root() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "tenant",
|
||||
Usage: "Tenants related commands",
|
||||
Subcommands: []*cli.Command{
|
||||
CreateCommand(),
|
||||
GetCommand(),
|
||||
UpdateCommand(),
|
||||
DeleteCommand(),
|
||||
QueryCommand(),
|
||||
},
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package tenant
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/client/apierr"
|
||||
clientFlag "forge.cadoles.com/Cadoles/emissary/internal/command/client/flag"
|
||||
tenantFlag "forge.cadoles.com/Cadoles/emissary/internal/command/client/tenant/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/pkg/client"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli/v2"
|
||||
"gitlab.com/wpetit/goweb/cli/format"
|
||||
)
|
||||
|
||||
func UpdateCommand() *cli.Command {
|
||||
return &cli.Command{
|
||||
Name: "update",
|
||||
Usage: "Update tenant",
|
||||
Flags: tenantFlag.WithTenantFlags(
|
||||
&cli.StringFlag{
|
||||
Name: "tenant-label",
|
||||
Usage: "Set `TENANT_LABEL` to targeted tenant",
|
||||
Value: "",
|
||||
},
|
||||
),
|
||||
Action: func(ctx *cli.Context) error {
|
||||
baseFlags := clientFlag.GetBaseFlags(ctx)
|
||||
|
||||
token, err := clientFlag.GetToken(baseFlags)
|
||||
if err != nil {
|
||||
return errors.WithStack(apierr.Wrap(err))
|
||||
}
|
||||
|
||||
tenantID, err := tenantFlag.AssertTenantID(ctx)
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
options := make([]client.UpdateTenantOptionFunc, 0)
|
||||
|
||||
label := ctx.String("tenant-label")
|
||||
if label != "" {
|
||||
options = append(options, client.WithTenantLabel(label))
|
||||
}
|
||||
|
||||
client := client.New(baseFlags.ServerURL, client.WithToken(token))
|
||||
|
||||
agent, err := client.UpdateTenant(ctx.Context, tenantID, options...)
|
||||
if err != nil {
|
||||
return errors.WithStack(apierr.Wrap(err))
|
||||
}
|
||||
|
||||
hints := tenantHints(baseFlags.OutputMode)
|
||||
|
||||
if err := format.Write(baseFlags.Format, os.Stdout, hints, agent); err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
},
|
||||
}
|
||||
}
|
|
@ -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 {
|
||||
|
|
|
@ -5,11 +5,12 @@ import (
|
|||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/auth/thirdparty"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/api/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/auth/user"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/client/flag"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/command/common"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/datastore"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/jwk"
|
||||
"github.com/lithammer/shortuuid/v4"
|
||||
"github.com/google/uuid"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
@ -21,13 +22,18 @@ func CreateTokenCommand() *cli.Command {
|
|||
Flags: []cli.Flag{
|
||||
&cli.StringFlag{
|
||||
Name: "role",
|
||||
Usage: fmt.Sprintf("associate `ROLE` to the token (available: %v)", []thirdparty.Role{thirdparty.RoleReader, thirdparty.RoleWriter}),
|
||||
Value: string(thirdparty.RoleReader),
|
||||
Usage: fmt.Sprintf("associate `ROLE` to the token (available: %v)", []user.Role{user.RoleReader, user.RoleWriter, user.RoleAdmin}),
|
||||
Value: string(user.RoleReader),
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "subject",
|
||||
Usage: "associate `SUBJECT` to the token",
|
||||
Value: fmt.Sprintf("user-%s", shortuuid.New()),
|
||||
Value: fmt.Sprintf("user-%s", uuid.New().String()),
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "tenant",
|
||||
Usage: "associate `TENANT` to the token",
|
||||
Value: "00000000-0000-0000-0000-000000000000",
|
||||
},
|
||||
&cli.StringFlag{
|
||||
Name: "output",
|
||||
|
@ -44,6 +50,7 @@ func CreateTokenCommand() *cli.Command {
|
|||
}
|
||||
|
||||
subject := ctx.String("subject")
|
||||
tenant := ctx.String("tenant")
|
||||
role := ctx.String("role")
|
||||
output := ctx.String("output")
|
||||
|
||||
|
@ -57,7 +64,7 @@ func CreateTokenCommand() *cli.Command {
|
|||
return errors.WithStack(err)
|
||||
}
|
||||
|
||||
token, err := thirdparty.GenerateToken(ctx.Context, key, subject, thirdparty.Role(role))
|
||||
token, err := user.GenerateToken(ctx.Context, key, datastore.TenantID(tenant), subject, user.Role(role))
|
||||
if err != nil {
|
||||
return errors.WithStack(err)
|
||||
}
|
||||
|
|
|
@ -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))
|
||||
}
|
||||
}()
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ type ControllersConfig struct {
|
|||
App AppControllerConfig `yaml:"app"`
|
||||
SysUpgrade SysUpgradeControllerConfig `yaml:"sysupgrade"`
|
||||
MDNS MDNSControllerConfig `yaml:"mdns"`
|
||||
Status StatusControllerConfig `yaml:"status"`
|
||||
}
|
||||
|
||||
type PersistenceControllerConfig struct {
|
||||
|
@ -60,6 +61,13 @@ type MDNSControllerConfig struct {
|
|||
Enabled InterpolatedBool `yaml:"enabled"`
|
||||
}
|
||||
|
||||
type StatusControllerConfig struct {
|
||||
Enabled InterpolatedBool `yaml:"enabled"`
|
||||
Address InterpolatedString `yaml:"address"`
|
||||
ClaimURL InterpolatedString `yaml:"claimURL"`
|
||||
AgentURL InterpolatedString `yaml:"agentURL"`
|
||||
}
|
||||
|
||||
func NewDefaultAgentConfig() AgentConfig {
|
||||
return AgentConfig{
|
||||
ServerURL: "http://127.0.0.1:3000",
|
||||
|
@ -94,6 +102,12 @@ func NewDefaultAgentConfig() AgentConfig {
|
|||
MDNS: MDNSControllerConfig{
|
||||
Enabled: true,
|
||||
},
|
||||
Status: StatusControllerConfig{
|
||||
Enabled: true,
|
||||
Address: ":42521",
|
||||
ClaimURL: "http://localhost:3001/claim/%s",
|
||||
AgentURL: "http://localhost:3001/agents/%v",
|
||||
},
|
||||
},
|
||||
Collectors: []ShellCollectorConfig{
|
||||
{
|
||||
|
|
|
@ -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(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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",
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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),
|
||||
}
|
||||
}
|
|
@ -3,7 +3,7 @@ package config
|
|||
import (
|
||||
"fmt"
|
||||
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/auth/thirdparty"
|
||||
"forge.cadoles.com/Cadoles/emissary/internal/auth/user"
|
||||
)
|
||||
|
||||
type ServerConfig struct {
|
||||
|
@ -23,9 +23,10 @@ func NewDefaultServerConfig() ServerConfig {
|
|||
}
|
||||
|
||||
type AuthConfig struct {
|
||||
Local *LocalAuthConfig `yaml:"local"`
|
||||
Remote *RemoteAuthConfig `yaml:"remote"`
|
||||
RoleExtractionRules []string `yaml:"roleExtractionRules"`
|
||||
Local *LocalAuthConfig `yaml:"local"`
|
||||
Remote *RemoteAuthConfig `yaml:"remote"`
|
||||
RoleExtractionRules []string `yaml:"roleExtractionRules"`
|
||||
TenantExtractionRules []string `yaml:"tenantExtractionRules"`
|
||||
}
|
||||
|
||||
func NewDefaultAuthConfig() AuthConfig {
|
||||
|
@ -35,7 +36,10 @@ func NewDefaultAuthConfig() AuthConfig {
|
|||
},
|
||||
Remote: nil,
|
||||
RoleExtractionRules: []string{
|
||||
fmt.Sprintf("jwt.%s != nil ? str(jwt.%s) : ''", thirdparty.DefaultRoleKey, thirdparty.DefaultRoleKey),
|
||||
fmt.Sprintf("jwt.%s != nil ? str(jwt.%s) : ''", user.DefaultRoleKey, user.DefaultRoleKey),
|
||||
},
|
||||
TenantExtractionRules: []string{
|
||||
fmt.Sprintf("jwt.%s != nil ? str(jwt.%s) : ''", user.DefaultTenantKey, user.DefaultTenantKey),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ type Agent struct {
|
|||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
ContactedAt *time.Time `json:"contactedAt,omitempty"`
|
||||
TenantID *TenantID `json:"tenantId"`
|
||||
}
|
||||
|
||||
type SerializableKeySet struct {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue