mirror of
https://github.com/stefanprodan/podinfo.git
synced 2026-04-08 20:16:51 +00:00
Compare commits
46 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b891025365 | ||
|
|
3c3f2a2e60 | ||
|
|
06b5e969db | ||
|
|
8508550ee6 | ||
|
|
5c1032c578 | ||
|
|
9febc66b98 | ||
|
|
59dc738b25 | ||
|
|
8524be7240 | ||
|
|
065a18c258 | ||
|
|
79279ccb31 | ||
|
|
7e1ef7457e | ||
|
|
af4919172a | ||
|
|
532e8f85b5 | ||
|
|
7c90501b8b | ||
|
|
5f1fb66f6f | ||
|
|
be80733cea | ||
|
|
8572a390f7 | ||
|
|
b2a41c64de | ||
|
|
11cf36d838 | ||
|
|
5d440e41da | ||
|
|
170b912d25 | ||
|
|
38a7952407 | ||
|
|
de90d92697 | ||
|
|
22ee79fcb8 | ||
|
|
03ffc8bc34 | ||
|
|
c4f2a6c5e6 | ||
|
|
ab9f7410c2 | ||
|
|
2c85a72737 | ||
|
|
3970a3a323 | ||
|
|
61d6ed42f5 | ||
|
|
bb11285c6f | ||
|
|
132f4e7192 | ||
|
|
6c596bf19b | ||
|
|
ea292aa958 | ||
|
|
33fa856b63 | ||
|
|
6065c5aa79 | ||
|
|
0771a597e6 | ||
|
|
693ffa9d28 | ||
|
|
1c39c04ac9 | ||
|
|
a27ef20cb7 | ||
|
|
5e2089eafb | ||
|
|
68fd4e245a | ||
|
|
b718809f3b | ||
|
|
26379a5589 | ||
|
|
8d37bcfa32 | ||
|
|
f168e1909b |
39
.cosign/README.md
Normal file
39
.cosign/README.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# Podinfo signed releases
|
||||
|
||||
Podinfo deployment manifests are published to GitHub Container Registry as OCI artifacts
|
||||
and are signed using [cosign](https://github.com/sigstore/cosign).
|
||||
|
||||
## Verify the artifacts with cosign
|
||||
|
||||
Install the [cosign](https://github.com/sigstore/cosign) CLI:
|
||||
|
||||
```sh
|
||||
brew install sigstore/tap/cosign
|
||||
```
|
||||
|
||||
Verify a podinfo release with cosign CLI:
|
||||
|
||||
```sh
|
||||
cosign verify -key https://raw.githubusercontent.com/stefanprodan/podinfo/master/cosign/cosign.pub \
|
||||
ghcr.io/stefanprodan/podinfo-deploy:latest
|
||||
```
|
||||
|
||||
## Download the artifacts with crane
|
||||
|
||||
Install the [crane](https://github.com/google/go-containerregistry/tree/main/cmd/crane) CLI:
|
||||
|
||||
```sh
|
||||
brew install crane
|
||||
```
|
||||
|
||||
Download the podinfo deployment manifests with crane CLI:
|
||||
|
||||
```console
|
||||
$ crane export ghcr.io/stefanprodan/podinfo-deploy:latest -| tar -xf -
|
||||
|
||||
$ ls -1
|
||||
deployment.yaml
|
||||
hpa.yaml
|
||||
kustomization.yaml
|
||||
service.yaml
|
||||
```
|
||||
4
.cosign/cosign.pub
Normal file
4
.cosign/cosign.pub
Normal file
@@ -0,0 +1,4 @@
|
||||
-----BEGIN PUBLIC KEY-----
|
||||
MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEST+BqQ1XZhhVYx0YWQjdUJYIG5Lt
|
||||
iz2+UxRIqmKBqNmce2T+l45qyqOs99qfD7gLNGmkVZ4vtJ9bM7FxChFczg==
|
||||
-----END PUBLIC KEY-----
|
||||
11
.github/workflows/cve-scan.yml
vendored
11
.github/workflows/cve-scan.yml
vendored
@@ -17,7 +17,12 @@ jobs:
|
||||
IMAGE=test/podinfo:${GITHUB_SHA}
|
||||
docker build -t ${IMAGE} .
|
||||
echo "::set-output name=image::$IMAGE"
|
||||
- name: Scan image
|
||||
uses: docker://docker.io/aquasec/trivy:latest
|
||||
- name: Run Trivy vulnerability scanner
|
||||
uses: aquasecurity/trivy-action@master
|
||||
with:
|
||||
args: --cache-dir /var/lib/trivy --no-progress --exit-code 1 --severity MEDIUM,HIGH,CRITICAL ${{ steps.build.outputs.image }}
|
||||
image-ref: ${{ steps.build.outputs.image }}
|
||||
format: table
|
||||
exit-code: "1"
|
||||
ignore-unfixed: true
|
||||
vuln-type: os,library
|
||||
severity: CRITICAL,HIGH
|
||||
|
||||
4
.github/workflows/e2e.yml
vendored
4
.github/workflows/e2e.yml
vendored
@@ -11,7 +11,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
helm-version:
|
||||
- 3.6.0
|
||||
- 3.8.1
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
- name: Setup Kubernetes
|
||||
uses: engineerd/setup-kind@v0.5.0
|
||||
with:
|
||||
image: kindest/node:v1.19.11
|
||||
version: v0.11.1
|
||||
- name: Build container image
|
||||
run: |
|
||||
./test/build.sh
|
||||
|
||||
48
.github/workflows/release.yml
vendored
48
.github/workflows/release.yml
vendored
@@ -2,13 +2,25 @@ name: release
|
||||
|
||||
on:
|
||||
push:
|
||||
tags: '*'
|
||||
tags:
|
||||
- '*'
|
||||
|
||||
permissions:
|
||||
contents: write # needed to write releases
|
||||
id-token: write # needed for keyless signing
|
||||
packages: write # needed for ghcr access
|
||||
|
||||
jobs:
|
||||
release:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: imjasonh/setup-crane@v0.1
|
||||
- uses: sigstore/cosign-installer@main
|
||||
- name: Setup Helm
|
||||
uses: ./.github/actions/helm
|
||||
with:
|
||||
version: 3.8.1
|
||||
- name: Setup QEMU
|
||||
uses: docker/setup-qemu-action@v1
|
||||
with:
|
||||
@@ -16,8 +28,6 @@ jobs:
|
||||
- name: Setup Docker Buildx
|
||||
id: buildx
|
||||
uses: docker/setup-buildx-action@v1
|
||||
with:
|
||||
buildkitd-flags: "--debug"
|
||||
- name: Login to GitHub Container Registry
|
||||
uses: docker/login-action@v1
|
||||
with:
|
||||
@@ -44,7 +54,7 @@ jobs:
|
||||
push: true
|
||||
builder: ${{ steps.buildx.outputs.name }}
|
||||
context: .
|
||||
file: ./Dockerfile
|
||||
file: ./Dockerfile.xx
|
||||
platforms: linux/amd64,linux/arm/v7,linux/arm64
|
||||
tags: |
|
||||
docker.io/stefanprodan/podinfo:${{ steps.prep.outputs.VERSION }}
|
||||
@@ -58,6 +68,19 @@ jobs:
|
||||
org.opencontainers.image.revision=${{ github.sha }}
|
||||
org.opencontainers.image.version=${{ steps.prep.outputs.VERSION }}
|
||||
org.opencontainers.image.created=${{ steps.prep.outputs.BUILD_DATE }}
|
||||
- name: Publish Helm chart to GHCR
|
||||
run: |
|
||||
helm package charts/podinfo
|
||||
helm push podinfo-${{ steps.prep.outputs.VERSION }}.tgz oci://ghcr.io/stefanprodan/charts
|
||||
rm podinfo-${{ steps.prep.outputs.VERSION }}.tgz
|
||||
- name: Sign images
|
||||
env:
|
||||
COSIGN_EXPERIMENTAL: 1
|
||||
run: |
|
||||
cosign sign docker.io/stefanprodan/podinfo:${{ steps.prep.outputs.VERSION }}
|
||||
cosign sign docker.io/stefanprodan/podinfo:latest
|
||||
cosign sign ghcr.io/stefanprodan/podinfo:${{ steps.prep.outputs.VERSION }}
|
||||
cosign sign ghcr.io/stefanprodan/charts/podinfo:${{ steps.prep.outputs.VERSION }}
|
||||
- name: Publish base image
|
||||
uses: docker/build-push-action@v2
|
||||
with:
|
||||
@@ -71,6 +94,21 @@ jobs:
|
||||
uses: stefanprodan/helm-gh-pages@master
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Publish config artifact
|
||||
run: |
|
||||
cd kustomize
|
||||
tar -cf config.tar * --numeric-owner --owner=0 --group=0
|
||||
crane append -f config.tar -t ghcr.io/stefanprodan/podinfo-deploy:${{ steps.prep.outputs.VERSION }}
|
||||
crane tag ghcr.io/stefanprodan/podinfo-deploy:${{ steps.prep.outputs.VERSION }} latest
|
||||
rm config.tar
|
||||
- name: Sign config artifact
|
||||
run: |
|
||||
echo "$COSIGN_KEY" > /tmp/cosign.key
|
||||
cosign sign -key /tmp/cosign.key ghcr.io/stefanprodan/podinfo-deploy:${{ steps.prep.outputs.VERSION }}
|
||||
cosign sign -key /tmp/cosign.key ghcr.io/stefanprodan/podinfo-deploy:latest
|
||||
env:
|
||||
COSIGN_PASSWORD: ${{secrets.COSIGN_PASSWORD}}
|
||||
COSIGN_KEY: ${{secrets.COSIGN_KEY}}
|
||||
- uses: ./.github/actions/release-notes
|
||||
- name: Generate release notes
|
||||
run: |
|
||||
@@ -80,6 +118,6 @@ jobs:
|
||||
uses: goreleaser/goreleaser-action@v1
|
||||
with:
|
||||
version: latest
|
||||
args: release --release-notes=/tmp/release.txt
|
||||
args: release --release-notes=/tmp/release.txt --skip-validate
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
2
.github/workflows/test.yml
vendored
2
.github/workflows/test.yml
vendored
@@ -21,7 +21,7 @@ jobs:
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v2
|
||||
with:
|
||||
go-version: 1.16.x
|
||||
go-version: 1.17.x
|
||||
- name: Run unit tests
|
||||
run: make test
|
||||
- name: Check if working tree is dirty
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.16-alpine as builder
|
||||
FROM golang:1.17-alpine as builder
|
||||
|
||||
ARG REVISION
|
||||
|
||||
@@ -18,7 +18,7 @@ RUN CGO_ENABLED=0 go build -ldflags "-s -w \
|
||||
-X github.com/stefanprodan/podinfo/pkg/version.REVISION=${REVISION}" \
|
||||
-a -o bin/podcli cmd/podcli/*
|
||||
|
||||
FROM alpine:3.14
|
||||
FROM alpine:3.15
|
||||
|
||||
ARG BUILD_DATE
|
||||
ARG VERSION
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM golang:1.16
|
||||
FROM golang:1.17
|
||||
|
||||
WORKDIR /workspace
|
||||
|
||||
|
||||
53
Dockerfile.xx
Normal file
53
Dockerfile.xx
Normal file
@@ -0,0 +1,53 @@
|
||||
ARG GO_VERSION=1.17
|
||||
ARG XX_VERSION=1.1.0
|
||||
|
||||
FROM --platform=$BUILDPLATFORM tonistiigi/xx:${XX_VERSION} AS xx
|
||||
|
||||
FROM --platform=$BUILDPLATFORM golang:${GO_VERSION}-alpine as builder
|
||||
|
||||
# Copy the build utilities.
|
||||
COPY --from=xx / /
|
||||
|
||||
ARG TARGETPLATFORM
|
||||
ARG REVISION
|
||||
|
||||
RUN mkdir -p /podinfo/
|
||||
|
||||
WORKDIR /podinfo
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN go mod download
|
||||
|
||||
ENV CGO_ENABLED=0
|
||||
RUN xx-go build -ldflags "-s -w \
|
||||
-X github.com/stefanprodan/podinfo/pkg/version.REVISION=${REVISION}" \
|
||||
-a -o bin/podinfo cmd/podinfo/*
|
||||
|
||||
RUN xx-go build -ldflags "-s -w \
|
||||
-X github.com/stefanprodan/podinfo/pkg/version.REVISION=${REVISION}" \
|
||||
-a -o bin/podcli cmd/podcli/*
|
||||
|
||||
FROM alpine:3.15
|
||||
|
||||
ARG BUILD_DATE
|
||||
ARG VERSION
|
||||
ARG REVISION
|
||||
|
||||
LABEL maintainer="stefanprodan"
|
||||
|
||||
RUN addgroup -S app \
|
||||
&& adduser -S -G app app \
|
||||
&& apk --no-cache add \
|
||||
ca-certificates curl netcat-openbsd
|
||||
|
||||
WORKDIR /home/app
|
||||
|
||||
COPY --from=builder /podinfo/bin/podinfo .
|
||||
COPY --from=builder /podinfo/bin/podcli /usr/local/bin/podcli
|
||||
COPY ./ui ./ui
|
||||
RUN chown -R app:app ./
|
||||
|
||||
USER app
|
||||
|
||||
CMD ["./podinfo"]
|
||||
30
Makefile
30
Makefile
@@ -23,6 +23,9 @@ build:
|
||||
GIT_COMMIT=$$(git rev-list -1 HEAD) && CGO_ENABLED=0 go build -ldflags "-s -w -X github.com/stefanprodan/podinfo/pkg/version.REVISION=$(GIT_COMMIT)" -a -o ./bin/podinfo ./cmd/podinfo/*
|
||||
GIT_COMMIT=$$(git rev-list -1 HEAD) && CGO_ENABLED=0 go build -ldflags "-s -w -X github.com/stefanprodan/podinfo/pkg/version.REVISION=$(GIT_COMMIT)" -a -o ./bin/podcli ./cmd/podcli/*
|
||||
|
||||
tidy:
|
||||
rm -f go.sum; go mod tidy -compat=1.17
|
||||
|
||||
fmt:
|
||||
gofmt -l -s -w ./
|
||||
goimports -l -w ./
|
||||
@@ -34,6 +37,13 @@ build-charts:
|
||||
build-container:
|
||||
docker build -t $(DOCKER_IMAGE_NAME):$(VERSION) .
|
||||
|
||||
build-xx:
|
||||
docker buildx build \
|
||||
--platform=linux/amd64 \
|
||||
-t $(DOCKER_IMAGE_NAME):$(VERSION) \
|
||||
--load \
|
||||
-f Dockerfile.xx .
|
||||
|
||||
build-base:
|
||||
docker build -f Dockerfile.base -t $(DOCKER_REPOSITORY)/podinfo-base:latest .
|
||||
|
||||
@@ -59,16 +69,16 @@ push-container:
|
||||
version-set:
|
||||
@next="$(TAG)" && \
|
||||
current="$(VERSION)" && \
|
||||
sed -i '' "s/$$current/$$next/g" pkg/version/version.go && \
|
||||
sed -i '' "s/tag: $$current/tag: $$next/g" charts/podinfo/values.yaml && \
|
||||
sed -i '' "s/tag: $$current/tag: $$next/g" charts/podinfo/values-prod.yaml && \
|
||||
sed -i '' "s/appVersion: $$current/appVersion: $$next/g" charts/podinfo/Chart.yaml && \
|
||||
sed -i '' "s/version: $$current/version: $$next/g" charts/podinfo/Chart.yaml && \
|
||||
sed -i '' "s/podinfo:$$current/podinfo:$$next/g" kustomize/deployment.yaml && \
|
||||
sed -i '' "s/podinfo:$$current/podinfo:$$next/g" deploy/webapp/frontend/deployment.yaml && \
|
||||
sed -i '' "s/podinfo:$$current/podinfo:$$next/g" deploy/webapp/backend/deployment.yaml && \
|
||||
sed -i '' "s/podinfo:$$current/podinfo:$$next/g" deploy/bases/frontend/deployment.yaml && \
|
||||
sed -i '' "s/podinfo:$$current/podinfo:$$next/g" deploy/bases/backend/deployment.yaml && \
|
||||
/usr/bin/sed -i '' "s/$$current/$$next/g" pkg/version/version.go && \
|
||||
/usr/bin/sed -i '' "s/tag: $$current/tag: $$next/g" charts/podinfo/values.yaml && \
|
||||
/usr/bin/sed -i '' "s/tag: $$current/tag: $$next/g" charts/podinfo/values-prod.yaml && \
|
||||
/usr/bin/sed -i '' "s/appVersion: $$current/appVersion: $$next/g" charts/podinfo/Chart.yaml && \
|
||||
/usr/bin/sed -i '' "s/version: $$current/version: $$next/g" charts/podinfo/Chart.yaml && \
|
||||
/usr/bin/sed -i '' "s/podinfo:$$current/podinfo:$$next/g" kustomize/deployment.yaml && \
|
||||
/usr/bin/sed -i '' "s/podinfo:$$current/podinfo:$$next/g" deploy/webapp/frontend/deployment.yaml && \
|
||||
/usr/bin/sed -i '' "s/podinfo:$$current/podinfo:$$next/g" deploy/webapp/backend/deployment.yaml && \
|
||||
/usr/bin/sed -i '' "s/podinfo:$$current/podinfo:$$next/g" deploy/bases/frontend/deployment.yaml && \
|
||||
/usr/bin/sed -i '' "s/podinfo:$$current/podinfo:$$next/g" deploy/bases/backend/deployment.yaml && \
|
||||
echo "Version $$next set in code, deployment, chart and kustomize"
|
||||
|
||||
release:
|
||||
|
||||
22
README.md
22
README.md
@@ -15,9 +15,7 @@ Specifications:
|
||||
* Health checks (readiness and liveness)
|
||||
* Graceful shutdown on interrupt signals
|
||||
* File watcher for secrets and configmaps
|
||||
* Instrumented with Prometheus
|
||||
* Tracing with Istio and Jaeger
|
||||
* Linkerd service profile
|
||||
* Instrumented with Prometheus and Open Telemetry
|
||||
* Structured logging with zap
|
||||
* 12-factor app with viper
|
||||
* Fault injection (random errors and latency)
|
||||
@@ -26,7 +24,8 @@ Specifications:
|
||||
* End-to-End testing with Kubernetes Kind and Helm
|
||||
* Kustomize testing with GitHub Actions and Open Policy Agent
|
||||
* Multi-arch container image with Docker buildx and Github Actions
|
||||
* CVE scanning with trivy
|
||||
* Container image signing with Sigstore cosign
|
||||
* CVE scanning with Trivy
|
||||
|
||||
Web API:
|
||||
|
||||
@@ -77,7 +76,9 @@ To access the Swagger UI open `<podinfo-host>/swagger/index.html` in a browser.
|
||||
|
||||
### Install
|
||||
|
||||
Helm:
|
||||
#### Helm
|
||||
|
||||
Install from github.io:
|
||||
|
||||
```bash
|
||||
helm repo add podinfo https://stefanprodan.github.io/podinfo
|
||||
@@ -96,13 +97,20 @@ helm upgrade --install --wait backend \
|
||||
podinfo/podinfo
|
||||
```
|
||||
|
||||
Kustomize:
|
||||
Install from ghcr.io:
|
||||
|
||||
```bash
|
||||
helm upgrade --install --wait podinfo --namespace default \
|
||||
oci://ghcr.io/stefanprodan/charts/podinfo
|
||||
```
|
||||
|
||||
#### Kustomize
|
||||
|
||||
```bash
|
||||
kubectl apply -k github.com/stefanprodan/podinfo//kustomize
|
||||
```
|
||||
|
||||
Docker:
|
||||
#### Docker
|
||||
|
||||
```bash
|
||||
docker run -dp 9898:9898 stefanprodan/podinfo
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
apiVersion: v1
|
||||
version: 6.0.0
|
||||
appVersion: 6.0.0
|
||||
version: 6.1.1
|
||||
appVersion: 6.1.1
|
||||
name: podinfo
|
||||
engine: gotpl
|
||||
description: Podinfo Helm chart for Kubernetes
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
1. Get the application URL by running these commands:
|
||||
{{- if .Values.ingress.enabled }}
|
||||
{{- range .Values.ingress.hosts }}
|
||||
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ . }}{{ $.Values.ingress.path }}
|
||||
{{- range $host := .Values.ingress.hosts }}
|
||||
{{- range .paths }}
|
||||
http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- else if contains "NodePort" .Values.service.type }}
|
||||
export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ template "podinfo.fullname" . }})
|
||||
|
||||
@@ -8,7 +8,7 @@ backends: []
|
||||
|
||||
image:
|
||||
repository: ghcr.io/stefanprodan/podinfo
|
||||
tag: 6.0.0
|
||||
tag: 6.1.1
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
ui:
|
||||
|
||||
@@ -8,7 +8,7 @@ backends: []
|
||||
|
||||
image:
|
||||
repository: ghcr.io/stefanprodan/podinfo
|
||||
tag: 6.0.0
|
||||
tag: 6.1.1
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
ui:
|
||||
|
||||
@@ -29,7 +29,7 @@ func main() {
|
||||
fs.Int("port-metrics", 0, "metrics port")
|
||||
fs.Int("grpc-port", 0, "gRPC port")
|
||||
fs.String("grpc-service-name", "podinfo", "gPRC service name")
|
||||
fs.String("level", "info", "log level debug, info, warn, error, flat or panic")
|
||||
fs.String("level", "info", "log level debug, info, warn, error, fatal or panic")
|
||||
fs.StringSlice("backend-url", []string{}, "backend service URL")
|
||||
fs.Duration("http-client-timeout", 2*time.Minute, "client timeout duration")
|
||||
fs.Duration("http-server-timeout", 30*time.Second, "server read and write timeout duration")
|
||||
@@ -53,6 +53,7 @@ func main() {
|
||||
fs.Int("stress-cpu", 0, "number of CPU cores with 100 load")
|
||||
fs.Int("stress-memory", 0, "MB of data to load into memory")
|
||||
fs.String("cache-server", "", "Redis address in the format <host>:<port>")
|
||||
fs.String("otel-service-name", "", "service name for reporting to open telemetry address, when not set tracing is disabled")
|
||||
|
||||
versionFlag := fs.BoolP("version", "v", false, "get version number")
|
||||
|
||||
@@ -90,8 +91,6 @@ func main() {
|
||||
if readErr := viper.ReadInConfig(); readErr != nil {
|
||||
fmt.Printf("Error reading config file, %v\n", readErr)
|
||||
}
|
||||
} else {
|
||||
fmt.Printf("Error to open config file, %v\n", fileErr)
|
||||
}
|
||||
|
||||
// configure logging
|
||||
|
||||
@@ -23,7 +23,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: backend
|
||||
image: ghcr.io/stefanprodan/podinfo:6.0.0
|
||||
image: ghcr.io/stefanprodan/podinfo:6.1.1
|
||||
imagePullPolicy: IfNotPresent
|
||||
ports:
|
||||
- name: http
|
||||
|
||||
@@ -23,7 +23,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: frontend
|
||||
image: ghcr.io/stefanprodan/podinfo:6.0.0
|
||||
image: ghcr.io/stefanprodan/podinfo:6.1.1
|
||||
imagePullPolicy: IfNotPresent
|
||||
ports:
|
||||
- name: http
|
||||
|
||||
@@ -25,7 +25,7 @@ spec:
|
||||
serviceAccountName: webapp
|
||||
containers:
|
||||
- name: backend
|
||||
image: ghcr.io/stefanprodan/podinfo:6.0.0
|
||||
image: ghcr.io/stefanprodan/podinfo:6.1.1
|
||||
imagePullPolicy: IfNotPresent
|
||||
ports:
|
||||
- name: http
|
||||
|
||||
@@ -25,7 +25,7 @@ spec:
|
||||
serviceAccountName: webapp
|
||||
containers:
|
||||
- name: frontend
|
||||
image: ghcr.io/stefanprodan/podinfo:6.0.0
|
||||
image: ghcr.io/stefanprodan/podinfo:6.1.1
|
||||
imagePullPolicy: IfNotPresent
|
||||
ports:
|
||||
- name: http
|
||||
|
||||
76
go.mod
76
go.mod
@@ -1,6 +1,6 @@
|
||||
module github.com/stefanprodan/podinfo
|
||||
|
||||
go 1.16
|
||||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751
|
||||
@@ -11,14 +11,74 @@ require (
|
||||
github.com/gomodule/redigo v1.8.4
|
||||
github.com/gorilla/mux v1.8.0
|
||||
github.com/gorilla/websocket v1.4.2
|
||||
github.com/mattn/go-isatty v0.0.12 // indirect
|
||||
github.com/prometheus/client_golang v1.11.0
|
||||
github.com/spf13/cobra v1.1.3
|
||||
github.com/spf13/cobra v1.2.1
|
||||
github.com/spf13/pflag v1.0.5
|
||||
github.com/spf13/viper v1.8.0
|
||||
github.com/spf13/viper v1.8.1
|
||||
github.com/swaggo/http-swagger v1.0.0
|
||||
github.com/swaggo/swag v1.7.0
|
||||
go.uber.org/zap v1.17.0
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4
|
||||
google.golang.org/grpc v1.38.0
|
||||
github.com/swaggo/swag v1.7.6
|
||||
go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.28.0
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.28.0
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.28.0
|
||||
go.opentelemetry.io/contrib/propagators/aws v1.3.0
|
||||
go.opentelemetry.io/contrib/propagators/b3 v1.3.0
|
||||
go.opentelemetry.io/contrib/propagators/jaeger v1.3.0
|
||||
go.opentelemetry.io/contrib/propagators/ot v1.3.0
|
||||
go.opentelemetry.io/otel v1.3.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.3.0
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.3.0
|
||||
go.opentelemetry.io/otel/sdk v1.3.0
|
||||
go.opentelemetry.io/otel/trace v1.3.0
|
||||
go.uber.org/zap v1.19.1
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f
|
||||
google.golang.org/grpc v1.43.0
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/KyleBanks/depth v1.2.1 // indirect
|
||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||
github.com/beorn7/perks v1.0.1 // indirect
|
||||
github.com/cenkalti/backoff/v4 v4.1.2 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.1 // indirect
|
||||
github.com/felixge/httpsnoop v1.0.2 // indirect
|
||||
github.com/go-logr/logr v1.2.1 // indirect
|
||||
github.com/go-logr/stdr v1.2.0 // indirect
|
||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||
github.com/go-openapi/jsonreference v0.19.5 // indirect
|
||||
github.com/go-openapi/spec v0.20.3 // indirect
|
||||
github.com/go-openapi/swag v0.19.14 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/magiconair/properties v1.8.5 // indirect
|
||||
github.com/mailru/easyjson v0.7.6 // indirect
|
||||
github.com/mattn/go-colorable v0.1.4 // indirect
|
||||
github.com/mattn/go-isatty v0.0.12 // indirect
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||
github.com/mitchellh/mapstructure v1.4.1 // indirect
|
||||
github.com/pelletier/go-toml v1.9.3 // indirect
|
||||
github.com/prometheus/client_model v0.2.0 // indirect
|
||||
github.com/prometheus/common v0.26.0 // indirect
|
||||
github.com/prometheus/procfs v0.6.0 // indirect
|
||||
github.com/spf13/afero v1.6.0 // indirect
|
||||
github.com/spf13/cast v1.3.1 // indirect
|
||||
github.com/spf13/jwalterweatherman v1.1.0 // indirect
|
||||
github.com/subosito/gotenv v1.2.0 // indirect
|
||||
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14 // indirect
|
||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.3.0 // indirect
|
||||
go.opentelemetry.io/otel/internal/metric v0.26.0 // indirect
|
||||
go.opentelemetry.io/otel/metric v0.26.0 // indirect
|
||||
go.opentelemetry.io/proto/otlp v0.11.0 // indirect
|
||||
go.uber.org/atomic v1.7.0 // indirect
|
||||
go.uber.org/multierr v1.6.0 // indirect
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40 // indirect
|
||||
golang.org/x/text v0.3.6 // indirect
|
||||
golang.org/x/tools v0.1.5 // indirect
|
||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect
|
||||
google.golang.org/protobuf v1.27.1 // indirect
|
||||
gopkg.in/ini.v1 v1.62.0 // indirect
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
)
|
||||
|
||||
149
go.sum
149
go.sum
@@ -41,11 +41,12 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
|
||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||
github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc=
|
||||
github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE=
|
||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
||||
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
|
||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||
github.com/agiledragon/gomonkey/v2 v2.3.1 h1:k+UnUY0EMNYUFUAQVETGY9uUTxjMdnUkP0ARyJS1zzs=
|
||||
github.com/agiledragon/gomonkey/v2 v2.3.1/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM=
|
||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
@@ -56,16 +57,17 @@ github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kd
|
||||
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
|
||||
github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY=
|
||||
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
|
||||
github.com/benbjohnson/clock v1.1.0 h1:Q92kusRqC1XV2MjkWETPvjJVqKetz1OzxZB7mHJLju8=
|
||||
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
|
||||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
|
||||
github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8=
|
||||
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||
github.com/bketelsen/crypt v0.0.4/go.mod h1:aI6NrJ0pMGgvZKL1iVgXLnfIFJtfV+bKCoqOes/6LfM=
|
||||
github.com/cenkalti/backoff/v4 v4.1.2 h1:6Yo7N8UP2K6LWZnW94DLVSSrbobcWdVzAYOisuDPIFo=
|
||||
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=
|
||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
|
||||
@@ -78,34 +80,33 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
|
||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
||||
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||
github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
|
||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
|
||||
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
|
||||
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1 h1:CaO/zOnF8VvUfEbhRatPcwKVWamvbYd8tQGRWacE9kU=
|
||||
github.com/dgrijalva/jwt-go/v4 v4.0.0-preview1/go.mod h1:+hnT3ywWDTAFrW5aE+u2Sa/wT555ZqwoCS+pk3p6ry4=
|
||||
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
|
||||
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
||||
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
|
||||
github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5ynNVH9qI8YYLbd1fK2po=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||
github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s=
|
||||
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/felixge/httpsnoop v1.0.2 h1:+nS9g82KMXccJ/wp0zyRW9ZBHFETmMGtkk+2CTTrW4o=
|
||||
github.com/felixge/httpsnoop v1.0.2/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
|
||||
github.com/fsnotify/fsnotify v1.4.9 h1:hsms1Qyu0jgnwNXIxa+/V/PDsU6CfLf6CNO8H7IWoS4=
|
||||
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
@@ -120,6 +121,11 @@ github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vb
|
||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||
github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
|
||||
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/logr v1.2.1 h1:DX7uPQ4WgAWfoh+NGGlbJQswnYIVvz0SRlLS3rPZQDA=
|
||||
github.com/go-logr/logr v1.2.1/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||
github.com/go-logr/stdr v1.2.0 h1:j4LrlVXgrbIWO83mmQUnK0Hi+YnbD+vzrE1z/EphbFE=
|
||||
github.com/go-logr/stdr v1.2.0/go.mod h1:YkVgnZu1ZjjL7xTxrfm/LLZBfkhTqSR1ydtm6jTKKwI=
|
||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||
@@ -127,19 +133,19 @@ github.com/go-openapi/jsonreference v0.19.4/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE
|
||||
github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM=
|
||||
github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
|
||||
github.com/go-openapi/spec v0.19.14/go.mod h1:gwrgJS15eCUgjLpMjBJmbZezCsw88LmgeEip0M63doA=
|
||||
github.com/go-openapi/spec v0.20.0 h1:HGLc8AJ7ynOxwv0Lq4TsnwLsWMawHAYiJIFzbcML86I=
|
||||
github.com/go-openapi/spec v0.20.0/go.mod h1:+81FIL1JwC5P3/Iuuozq3pPE9dXdIEGxFutcFKaVbmU=
|
||||
github.com/go-openapi/spec v0.20.3 h1:uH9RQ6vdyPSs2pSy9fL8QPspDF2AMIMPtmK5coSSjtQ=
|
||||
github.com/go-openapi/spec v0.20.3/go.mod h1:gG4F8wdEDN+YPBMVnzE85Rbhf+Th2DTvA9nFPQ5AYEg=
|
||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||
github.com/go-openapi/swag v0.19.11/go.mod h1:Uc0gKkdR+ojzsEpjh39QChyu92vPgIr72POcgHMAgSY=
|
||||
github.com/go-openapi/swag v0.19.12 h1:Bc0bnY2c3AoF7Gc+IMIAQQsD8fLHjHpc19wXvYuayQI=
|
||||
github.com/go-openapi/swag v0.19.12/go.mod h1:eFdyEBkTdoAf/9RXBvj4cr1nH7GD8Kzo5HTt47gr72M=
|
||||
github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng=
|
||||
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||
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.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||
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-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||
@@ -183,8 +189,9 @@ github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
|
||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
|
||||
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
||||
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||
@@ -211,9 +218,7 @@ github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/hashicorp/consul/api v1.1.0/go.mod h1:VmuI/Lkw1nC05EYQWNKwWGbkg+FbDBtguAZLlVdkD9Q=
|
||||
github.com/hashicorp/consul/sdk v0.1.1/go.mod h1:VKf9jXwCTEY1QZP2MOLRhb5i/I/ssyNV1vwHyQBF0x8=
|
||||
@@ -240,7 +245,6 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
|
||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
@@ -253,7 +257,6 @@ github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7
|
||||
github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
@@ -265,7 +268,6 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/magiconair/properties v1.8.5 h1:b6kJs+EmPFMYGkow9GiUyCyOvIwYetYJ3fSaWak/Gls=
|
||||
github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60=
|
||||
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
||||
@@ -285,7 +287,6 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
|
||||
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
|
||||
github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc=
|
||||
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||
@@ -301,9 +302,13 @@ github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRW
|
||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
|
||||
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
|
||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||
github.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE=
|
||||
github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U=
|
||||
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
|
||||
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
|
||||
github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
|
||||
github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
|
||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pelletier/go-toml v1.9.3 h1:zeC5b1GviRUyKYd6OJPvBU/mcVDVoL1OhT17FCt5dSQ=
|
||||
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
@@ -315,7 +320,6 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
|
||||
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=
|
||||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw=
|
||||
github.com/prometheus/client_golang v0.9.3/go.mod h1:/TN21ttK/J9q6uSwhBd54HahCDft0ttaMvbicHlPoso=
|
||||
github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo=
|
||||
github.com/prometheus/client_golang v1.7.1/go.mod h1:PY5Wy2awLA44sXw4AOSfFBetzPP4j5+D6mVACh+pe2M=
|
||||
github.com/prometheus/client_golang v1.11.0 h1:HNkLOAEQMIDv/K+04rukrLx6ch7msSRwf3/SASFAGtQ=
|
||||
@@ -325,20 +329,15 @@ github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:
|
||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/client_model v0.2.0 h1:uq5h0d+GuxiXLJLNABMgp2qUWDPiLvgCzz2dUR+/W/M=
|
||||
github.com/prometheus/client_model v0.2.0/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
||||
github.com/prometheus/common v0.0.0-20181113130724-41aa239b4cce/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro=
|
||||
github.com/prometheus/common v0.4.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4=
|
||||
github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB80sz/V91rCo=
|
||||
github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ=
|
||||
github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc=
|
||||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk=
|
||||
github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA=
|
||||
github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU=
|
||||
github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4=
|
||||
github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU=
|
||||
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.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
@@ -352,25 +351,18 @@ github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d h1:zE9ykE
|
||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||
github.com/smartystreets/goconvey v1.6.4 h1:fv0U8FUIMPNf1L9lnHLvLhgicrIVChEkdzIKYqbNC9s=
|
||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/afero v1.6.0 h1:xoax2sJ2DT8S8xA2paPFjDCScCNeWsg75VG0DLRreiY=
|
||||
github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng=
|
||||
github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
github.com/spf13/cobra v1.1.3 h1:xghbfqPkxzxP3C/f3n5DdpAbdKLj4ZE4BWQI362l53M=
|
||||
github.com/spf13/cobra v1.1.3/go.mod h1:pGADOWyqRD/YMrPZigI/zbliZ2wVD/23d+is3pSWzOo=
|
||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||
github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw=
|
||||
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
|
||||
github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk=
|
||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
||||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||
github.com/spf13/viper v1.8.0 h1:QRwDgoG8xX+kp69di68D+YYTCWfYEckbZRfUlEIAal0=
|
||||
github.com/spf13/viper v1.8.0/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
|
||||
github.com/spf13/viper v1.8.1 h1:Kq1fyeebqsBfbjZj4EL7gj2IO0mMaiyjYUWcUsl2O44=
|
||||
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
|
||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||
@@ -386,17 +378,15 @@ github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14 h1:PyYN9JH5jY9j6av01S
|
||||
github.com/swaggo/files v0.0.0-20190704085106-630677cd5c14/go.mod h1:gxQT6pBGRuIGunNf/+tSOB5OHvguWi8Tbt82WOkf35E=
|
||||
github.com/swaggo/http-swagger v1.0.0 h1:ksYgVBCYmAaxFsGVGojlPROgYfiQQSllETTWMtHJHTo=
|
||||
github.com/swaggo/http-swagger v1.0.0/go.mod h1:cKIcshBU9yEAnfWv6ZzVKSsEf8h5ozxB8/zHQWyOQ/8=
|
||||
github.com/swaggo/swag v1.7.0 h1:5bCA/MTLQoIqDXXyHfOpMeDvL9j68OY/udlK4pQoo4E=
|
||||
github.com/swaggo/swag v1.7.0/go.mod h1:BdPIL73gvS9NBsdi7M1JOxLvlbfvNRaBP8m6WT6Aajo=
|
||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||
github.com/swaggo/swag v1.7.6 h1:UbAqHyXkW2J+cDjs5S43MkuYR7a6stB7Am7SK8NBmRg=
|
||||
github.com/swaggo/swag v1.7.6/go.mod h1:7vLqNYEtYoIsD14wXgy9oDS65MNiDANrPtbk9rnLuj0=
|
||||
github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
|
||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||
go.etcd.io/etcd/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||
go.etcd.io/etcd/client/pkg/v3 v3.5.0/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
|
||||
go.etcd.io/etcd/client/v2 v2.305.0/go.mod h1:h9puh54ZTgAKtEbut2oe9P4L/oqKCVB6xsXlzd7alYQ=
|
||||
@@ -407,15 +397,49 @@ 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.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||
go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.28.0 h1:jGqTKfqtAbO+89WoLP7PuuOp2qCjaf+WkEDblYKL43k=
|
||||
go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux v0.28.0/go.mod h1:M4oIwAKStYVkLiVuW0+yPXrwd+pjss8kr547uaJ0cJQ=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.28.0 h1:3bv6d9BPHoaZLcl7OBYlmymaxAt0mngfDFkulGw2LXY=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.28.0/go.mod h1:y6HdV2Mk43TiOiNvrxczQQX2enNN9sQVR9lXfnJj6JQ=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.28.0 h1:hpEoMBvKLC6CqFZogJypr9IHwwSNF3ayEkNzD502QAM=
|
||||
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.28.0/go.mod h1:Ihno+mNBfZlT0Qot3XyRTdZ/9U/Cg2Pfgj75DTdIfq4=
|
||||
go.opentelemetry.io/contrib/propagators/aws v1.3.0 h1:BHhTUInxLQ6duq167/RIYERH6JM/33kYqePoCmSJsoM=
|
||||
go.opentelemetry.io/contrib/propagators/aws v1.3.0/go.mod h1:ugiMjPVWkdZy6FcU7YVYXF5jgLqiigf9TjDY+aRLjdw=
|
||||
go.opentelemetry.io/contrib/propagators/b3 v1.3.0 h1:f+JfMSDNm2u+fekYYjyoixk+DWDTDAGD3SC50y61koE=
|
||||
go.opentelemetry.io/contrib/propagators/b3 v1.3.0/go.mod h1:qzi0km8qO3l2jxB5aDg4Q9xyqV4HKnCWZYpVYDTUIT0=
|
||||
go.opentelemetry.io/contrib/propagators/jaeger v1.3.0 h1:yBy4QZXuMA7s3+uhLK556NdmjKpj3RjGMaW+WMLU6CM=
|
||||
go.opentelemetry.io/contrib/propagators/jaeger v1.3.0/go.mod h1:igceHZGoCcIJavRTG1dS7+9Vnoid4qa7SZPa7doupq8=
|
||||
go.opentelemetry.io/contrib/propagators/ot v1.3.0 h1:hqFpnicJXKy8l8PfwFWhRSt/TgOHCpugKiXsPP1zJUc=
|
||||
go.opentelemetry.io/contrib/propagators/ot v1.3.0/go.mod h1:Gpwe4R8j9Zbw7aaADYSQRE1U0o41j0TwnHxuhwRLklk=
|
||||
go.opentelemetry.io/otel v1.3.0 h1:APxLf0eiBwLl+SOXiJJCVYzA1OOJNyAoV8C5RNRyy7Y=
|
||||
go.opentelemetry.io/otel v1.3.0/go.mod h1:PWIKzi6JCp7sM0k9yZ43VX+T345uNbAkDKwHVjb2PTs=
|
||||
go.opentelemetry.io/otel/exporters/otlp/internal/retry v1.3.0 h1:R/OBkMoGgfy2fLhs2QhkCI1w4HLEQX92GCcJB6SSdNk=
|
||||
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 h1:giGm8w67Ja7amYNfYMdme7xSp2pIxThWopw8+QP51Yk=
|
||||
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 h1:VQbUHoJqytHHSJ1OZodPH9tvZZSVzUHjPHpkO85sT6k=
|
||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.3.0/go.mod h1:keUU7UfnwWTWpJ+FWnyqmogPa82nuU5VUANFq49hlMY=
|
||||
go.opentelemetry.io/otel/internal/metric v0.26.0 h1:dlrvawyd/A+X8Jp0EBT4wWEe4k5avYaXsXrBr4dbfnY=
|
||||
go.opentelemetry.io/otel/internal/metric v0.26.0/go.mod h1:CbBP6AxKynRs3QCbhklyLUtpfzbqCLiafV9oY2Zj1Jk=
|
||||
go.opentelemetry.io/otel/metric v0.26.0 h1:VaPYBTvA13h/FsiWfxa3yZnZEm15BhStD8JZQSA773M=
|
||||
go.opentelemetry.io/otel/metric v0.26.0/go.mod h1:c6YL0fhRo4YVoNs6GoByzUgBp36hBL523rECoZA5UWg=
|
||||
go.opentelemetry.io/otel/sdk v1.3.0 h1:3278edCoH89MEJ0Ky8WQXVmDQv3FX4ZJ3Pp+9fJreAI=
|
||||
go.opentelemetry.io/otel/sdk v1.3.0/go.mod h1:rIo4suHNhQwBIPg9axF8V9CA72Wz2mKF1teNrup8yzs=
|
||||
go.opentelemetry.io/otel/trace v1.3.0 h1:doy8Hzb1RJ+I3yFhtDmwNc7tIyw1tNMOIsyPzp1NOGY=
|
||||
go.opentelemetry.io/otel/trace v1.3.0/go.mod h1:c/VDhno8888bvQYmbYLqe41/Ldmr/KKunbvWM4/fEjk=
|
||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||
go.opentelemetry.io/proto/otlp v0.11.0 h1:cLDgIBTf4lLOlztkhzAEdQsJ4Lj+i5Wc9k6Nn0K1VyU=
|
||||
go.opentelemetry.io/proto/otlp v0.11.0/go.mod h1:QpEjXPrNQzrFDZgoTo49dgHR9RYRSrg3NAKnUGl9YpQ=
|
||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
|
||||
go.uber.org/goleak v1.1.11-0.20210813005559-691160354723/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||
go.uber.org/goleak v1.1.12 h1:gZAh5/EyT/HQwlpkCy6wTpqfH9H8Lz8zbm3dZh+OyzA=
|
||||
go.uber.org/goleak v1.1.12/go.mod h1:cwTWslyiVhfpKIDGSZEM2HlOvcqm+tG4zioyIeLoqMQ=
|
||||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
||||
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
|
||||
go.uber.org/zap v1.17.0 h1:MTjgFu6ZLKvY6Pvaqk97GlxNBuMpV4Hy/3P6tRGlI2U=
|
||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
||||
go.uber.org/zap v1.19.1 h1:ue41HOKd1vGURxrmeKIgELGb3jPW9DMUDGtsinblHwI=
|
||||
go.uber.org/zap v1.19.1/go.mod h1:j3DNczoxDZroyBnOT1L/Q79cfUMGZxlv/9dzN7SM1rI=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||
@@ -465,7 +489,6 @@ golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73r
|
||||
golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181201002055-351d144fa1fc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||
@@ -500,8 +523,9 @@ golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v
|
||||
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
||||
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 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0=
|
||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM=
|
||||
golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||
@@ -529,7 +553,6 @@ golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
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-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -576,6 +599,7 @@ golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7w
|
||||
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40 h1:JWgyZ1qgdTaF3N3oxC+MdTV7qvEEgHo3otj+HB5CM7Q=
|
||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
@@ -586,12 +610,12 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3
|
||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.5 h1:i6eZZ+zk0SOf0xgBpEpPD18qWcJda6q1sxt3S0kzyUQ=
|
||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||
@@ -644,8 +668,9 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f
|
||||
golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
|
||||
golang.org/x/tools v0.1.2 h1:kRBLX7v7Af8W7Gdbbc908OJcdgtK8bOz9Uaj8/F1ACA=
|
||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
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=
|
||||
@@ -741,8 +766,10 @@ google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA5
|
||||
google.golang.org/grpc v1.35.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||
google.golang.org/grpc v1.38.0 h1:/9BgsAsa5nWe26HqOlvlgJnqBuktYOLCgjCPqsa56W0=
|
||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||
google.golang.org/grpc v1.42.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/grpc v1.43.0 h1:Eeu7bZtDZ2DpRCsLhUlcrLnvYaMK1Gz86a+hMVvELmM=
|
||||
google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
|
||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
||||
@@ -754,8 +781,9 @@ google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpAD
|
||||
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
|
||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ=
|
||||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||
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=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
@@ -763,11 +791,8 @@ gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
|
||||
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/ini.v1 v1.62.0 h1:duBzk771uxoUuOlyRLkHsygud9+5lrlGjdFBb4mSKDU=
|
||||
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||
|
||||
@@ -23,7 +23,7 @@ spec:
|
||||
spec:
|
||||
containers:
|
||||
- name: podinfod
|
||||
image: ghcr.io/stefanprodan/podinfo:6.0.0
|
||||
image: ghcr.io/stefanprodan/podinfo:6.1.1
|
||||
imagePullPolicy: IfNotPresent
|
||||
ports:
|
||||
- name: http
|
||||
|
||||
20
otel/Makefile
Normal file
20
otel/Makefile
Normal file
@@ -0,0 +1,20 @@
|
||||
DC=docker-compose -f docker-compose.yaml
|
||||
|
||||
.PHONY: help
|
||||
.DEFAULT_GOAL := help
|
||||
|
||||
help:
|
||||
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | sort | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}'
|
||||
|
||||
stop: ## Stop all Docker Containers run in Compose
|
||||
$(DC) stop
|
||||
|
||||
clean: stop ## Clean all Docker Containers and Volumes
|
||||
$(DC) down --rmi local --remove-orphans -v
|
||||
$(DC) rm -f -v
|
||||
|
||||
build: clean ## Rebuild the Docker Image for use by Compose
|
||||
$(DC) build
|
||||
|
||||
run: stop ## Run the Application
|
||||
$(DC) up
|
||||
37
otel/README.md
Normal file
37
otel/README.md
Normal file
@@ -0,0 +1,37 @@
|
||||
# Tracing Demo
|
||||
|
||||
The directory contains sample [OpenTelemetry Collector](https://github.com/open-telemetry/opentelemetry-collector)
|
||||
and [Jaeger](https://www.jaegertracing.io) configurations for a tracing demo.
|
||||
|
||||
## Configuration
|
||||
|
||||
The provided [docker-compose.yaml](docker-compose.yaml) sets up 4 Containers
|
||||
|
||||
1. PodInfo Frontend on port 9898
|
||||
2. PodInfo Backend on port 9899
|
||||
3. OpenTelemetry Collector listening on port 4317 for GRPC
|
||||
4. Jaeger all-in-one listening on multiple ports
|
||||
|
||||
## How does it work?
|
||||
|
||||
The frontend pods are configured to call onto the backend pods. Both the podinfo
|
||||
pods are configured to send traces over to the collector at port 4317 using GRPC.
|
||||
The collector forwards all received spans to Jaeger over port 14250 and Jaeger
|
||||
exposes a UI over port `16686`.
|
||||
|
||||
## Running it locally
|
||||
|
||||
1. Start all the Containers
|
||||
```shell
|
||||
make run
|
||||
```
|
||||
2. Send some sample requests
|
||||
```shell
|
||||
curl -v http://localhost:9898/status/200
|
||||
curl -X POST -v http://localhost:9898/api/echo
|
||||
```
|
||||
3. Visit `http://localhost:16686/` to see the spans
|
||||
4. Stop all the containers
|
||||
```shell
|
||||
make stop
|
||||
```
|
||||
35
otel/docker-compose.yaml
Normal file
35
otel/docker-compose.yaml
Normal file
@@ -0,0 +1,35 @@
|
||||
version: '2'
|
||||
|
||||
services:
|
||||
podinfo_frontend:
|
||||
build: ..
|
||||
command: ./podinfo --backend-url http://podinfo_backend:9899/status/200 --otel-service-name=podinfo_frontend
|
||||
environment:
|
||||
- OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://otel:4317
|
||||
ports:
|
||||
- "9898:9898"
|
||||
podinfo_backend:
|
||||
build: ..
|
||||
command: ./podinfo --port 9899 --otel-service-name=podinfo_backend
|
||||
environment:
|
||||
- OTEL_EXPORTER_OTLP_TRACES_ENDPOINT=http://otel:4317
|
||||
ports:
|
||||
- "9899:9899"
|
||||
otel:
|
||||
command: --config otel-config.yaml
|
||||
image: otel/opentelemetry-collector:0.41.0
|
||||
ports:
|
||||
- "4317:4317"
|
||||
volumes:
|
||||
- ${PWD}/otel-config.yaml:/otel-config.yaml
|
||||
jaeger:
|
||||
image: jaegertracing/all-in-one:1.29.0
|
||||
ports:
|
||||
- "5775:5775/udp"
|
||||
- "6831:6831/udp"
|
||||
- "6832:6832/udp"
|
||||
- "5778:5778"
|
||||
- "16686:16686"
|
||||
- "14268:14268"
|
||||
- "14250:14250"
|
||||
- "9411:9411"
|
||||
26
otel/otel-config.yaml
Normal file
26
otel/otel-config.yaml
Normal file
@@ -0,0 +1,26 @@
|
||||
receivers:
|
||||
otlp:
|
||||
protocols:
|
||||
grpc:
|
||||
http:
|
||||
|
||||
processors:
|
||||
|
||||
exporters:
|
||||
jaeger:
|
||||
endpoint: jaeger:14250
|
||||
tls:
|
||||
insecure: true
|
||||
|
||||
extensions:
|
||||
health_check:
|
||||
pprof:
|
||||
zpages:
|
||||
|
||||
service:
|
||||
extensions: [health_check,pprof,zpages]
|
||||
pipelines:
|
||||
traces:
|
||||
receivers: [otlp]
|
||||
processors: []
|
||||
exporters: [jaeger]
|
||||
@@ -1,8 +1,10 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"time"
|
||||
|
||||
"github.com/gomodule/redigo/redis"
|
||||
@@ -21,15 +23,18 @@ import (
|
||||
// @Router /cache/{key} [post]
|
||||
// @Success 202
|
||||
func (s *Server) cacheWriteHandler(w http.ResponseWriter, r *http.Request) {
|
||||
_, span := s.tracer.Start(r.Context(), "cacheWriteHandler")
|
||||
defer span.End()
|
||||
|
||||
if s.pool == nil {
|
||||
s.ErrorResponse(w, r, "cache server is offline", http.StatusBadRequest)
|
||||
s.ErrorResponse(w, r, span, "cache server is offline", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
key := mux.Vars(r)["key"]
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
s.ErrorResponse(w, r, "reading the request body failed", http.StatusBadRequest)
|
||||
s.ErrorResponse(w, r, span, "reading the request body failed", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -38,7 +43,7 @@ func (s *Server) cacheWriteHandler(w http.ResponseWriter, r *http.Request) {
|
||||
_, err = conn.Do("SET", key, string(body))
|
||||
if err != nil {
|
||||
s.logger.Warn("cache set failed", zap.Error(err))
|
||||
s.ErrorResponse(w, r, "cache set failed", http.StatusInternalServerError)
|
||||
s.ErrorResponse(w, r, span, "cache set failed", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -54,8 +59,11 @@ func (s *Server) cacheWriteHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// @Router /cache/{key} [delete]
|
||||
// @Success 202
|
||||
func (s *Server) cacheDeleteHandler(w http.ResponseWriter, r *http.Request) {
|
||||
_, span := s.tracer.Start(r.Context(), "cacheDeleteHandler")
|
||||
defer span.End()
|
||||
|
||||
if s.pool == nil {
|
||||
s.ErrorResponse(w, r, "cache server is offline", http.StatusBadRequest)
|
||||
s.ErrorResponse(w, r, span, "cache server is offline", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -82,8 +90,11 @@ func (s *Server) cacheDeleteHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// @Router /cache/{key} [get]
|
||||
// @Success 200 {string} string value
|
||||
func (s *Server) cacheReadHandler(w http.ResponseWriter, r *http.Request) {
|
||||
_, span := s.tracer.Start(r.Context(), "cacheReadHandler")
|
||||
defer span.End()
|
||||
|
||||
if s.pool == nil {
|
||||
s.ErrorResponse(w, r, "cache server is offline", http.StatusBadRequest)
|
||||
s.ErrorResponse(w, r, span, "cache server is offline", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -110,6 +121,23 @@ func (s *Server) cacheReadHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte(data))
|
||||
}
|
||||
|
||||
func (s *Server) getCacheConn() (redis.Conn, error) {
|
||||
redisUrl, err := url.Parse(s.config.CacheServer)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse redis url: %v", err)
|
||||
}
|
||||
|
||||
var opts []redis.DialOption
|
||||
if user := redisUrl.User; user != nil {
|
||||
opts = append(opts, redis.DialUsername(user.Username()))
|
||||
if password, ok := user.Password(); ok {
|
||||
opts = append(opts, redis.DialPassword(password))
|
||||
}
|
||||
}
|
||||
|
||||
return redis.Dial("tcp", redisUrl.Host, opts...)
|
||||
}
|
||||
|
||||
func (s *Server) startCachePool(ticker *time.Ticker, stopCh <-chan struct{}) {
|
||||
if s.config.CacheServer == "" {
|
||||
return
|
||||
@@ -117,9 +145,7 @@ func (s *Server) startCachePool(ticker *time.Ticker, stopCh <-chan struct{}) {
|
||||
s.pool = &redis.Pool{
|
||||
MaxIdle: 3,
|
||||
IdleTimeout: 240 * time.Second,
|
||||
Dial: func() (redis.Conn, error) {
|
||||
return redis.Dial("tcp", s.config.CacheServer)
|
||||
},
|
||||
Dial: s.getCacheConn,
|
||||
TestOnBorrow: func(c redis.Conn, t time.Time) error {
|
||||
_, err := c.Do("PING")
|
||||
return err
|
||||
|
||||
@@ -18,6 +18,9 @@ import (
|
||||
// @Router /chunked/{seconds} [get]
|
||||
// @Success 200 {object} api.MapResponse
|
||||
func (s *Server) chunkedHandler(w http.ResponseWriter, r *http.Request) {
|
||||
_, span := s.tracer.Start(r.Context(), "chunkedHandler")
|
||||
defer span.End()
|
||||
|
||||
vars := mux.Vars(r)
|
||||
|
||||
delay, err := strconv.Atoi(vars["wait"])
|
||||
@@ -27,7 +30,7 @@ func (s *Server) chunkedHandler(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
flusher, ok := w.(http.Flusher)
|
||||
if !ok {
|
||||
s.ErrorResponse(w, r, "Streaming unsupported!", http.StatusInternalServerError)
|
||||
s.ErrorResponse(w, r, span, "Streaming unsupported!", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,9 @@ package api
|
||||
import "net/http"
|
||||
|
||||
func (s *Server) configReadHandler(w http.ResponseWriter, r *http.Request) {
|
||||
_, span := s.tracer.Start(r.Context(), "configReadHandler")
|
||||
defer span.End()
|
||||
|
||||
files := make(map[string]string)
|
||||
if watcher != nil {
|
||||
watcher.Cache.Range(func(key interface{}, value interface{}) bool {
|
||||
|
||||
@@ -52,11 +52,14 @@ func (m *RandomDelayMiddleware) Handler(next http.Handler) http.Handler {
|
||||
// @Router /delay/{seconds} [get]
|
||||
// @Success 200 {object} api.MapResponse
|
||||
func (s *Server) delayHandler(w http.ResponseWriter, r *http.Request) {
|
||||
_, span := s.tracer.Start(r.Context(), "delayHandler")
|
||||
defer span.End()
|
||||
|
||||
vars := mux.Vars(r)
|
||||
|
||||
delay, err := strconv.Atoi(vars["wait"])
|
||||
if err != nil {
|
||||
s.ErrorResponse(w, r, err.Error(), http.StatusBadRequest)
|
||||
s.ErrorResponse(w, r, span, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -6,9 +6,12 @@ import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"net/http/httptrace"
|
||||
"sync"
|
||||
|
||||
"github.com/stefanprodan/podinfo/pkg/version"
|
||||
"go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace"
|
||||
"go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
@@ -21,13 +24,19 @@ import (
|
||||
// @Router /api/echo [post]
|
||||
// @Success 202 {object} api.MapResponse
|
||||
func (s *Server) echoHandler(w http.ResponseWriter, r *http.Request) {
|
||||
ctx, span := s.tracer.Start(r.Context(), "echoHandler")
|
||||
defer span.End()
|
||||
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
s.logger.Error("reading the request body failed", zap.Error(err))
|
||||
s.ErrorResponse(w, r, "invalid request body", http.StatusBadRequest)
|
||||
s.ErrorResponse(w, r, span, "invalid request body", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
defer r.Body.Close()
|
||||
|
||||
client := http.Client{Transport: otelhttp.NewTransport(http.DefaultTransport)}
|
||||
|
||||
if len(s.config.BackendURL) > 0 {
|
||||
result := make([]string, len(s.config.BackendURL))
|
||||
var wg sync.WaitGroup
|
||||
@@ -35,7 +44,12 @@ func (s *Server) echoHandler(w http.ResponseWriter, r *http.Request) {
|
||||
for i, b := range s.config.BackendURL {
|
||||
go func(index int, backend string) {
|
||||
defer wg.Done()
|
||||
backendReq, err := http.NewRequest("POST", backend, bytes.NewReader(body))
|
||||
|
||||
ctx = httptrace.WithClientTrace(ctx, otelhttptrace.NewClientTrace(ctx))
|
||||
ctx, cancel := context.WithTimeout(ctx, s.config.HttpClientTimeout)
|
||||
defer cancel()
|
||||
|
||||
backendReq, err := http.NewRequestWithContext(ctx, "POST", backend, bytes.NewReader(body))
|
||||
if err != nil {
|
||||
s.logger.Error("backend call failed", zap.Error(err), zap.String("url", backend))
|
||||
return
|
||||
@@ -47,11 +61,8 @@ func (s *Server) echoHandler(w http.ResponseWriter, r *http.Request) {
|
||||
backendReq.Header.Set("X-API-Version", version.VERSION)
|
||||
backendReq.Header.Set("X-API-Revision", version.REVISION)
|
||||
|
||||
ctx, cancel := context.WithTimeout(backendReq.Context(), s.config.HttpClientTimeout)
|
||||
defer cancel()
|
||||
|
||||
// call backend
|
||||
resp, err := http.DefaultClient.Do(backendReq.WithContext(ctx))
|
||||
resp, err := client.Do(backendReq)
|
||||
if err != nil {
|
||||
s.logger.Error("backend call failed", zap.Error(err), zap.String("url", backend))
|
||||
result[index] = fmt.Sprintf("backend %v call failed %v", backend, err)
|
||||
@@ -96,3 +107,22 @@ func (s *Server) echoHandler(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write(body)
|
||||
}
|
||||
}
|
||||
|
||||
func copyTracingHeaders(from *http.Request, to *http.Request) {
|
||||
headers := []string{
|
||||
"x-request-id",
|
||||
"x-b3-traceid",
|
||||
"x-b3-spanid",
|
||||
"x-b3-parentspanid",
|
||||
"x-b3-sampled",
|
||||
"x-b3-flags",
|
||||
"x-ot-span-context",
|
||||
}
|
||||
|
||||
for i := range headers {
|
||||
headerValue := from.Header.Get(headers[i])
|
||||
if len(headerValue) > 0 {
|
||||
to.Header.Set(headers[i], headerValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,5 +15,7 @@ import (
|
||||
// @Router /env [get]
|
||||
// @Success 200 {object} api.ArrayResponse
|
||||
func (s *Server) envHandler(w http.ResponseWriter, r *http.Request) {
|
||||
_, span := s.tracer.Start(r.Context(), "envHandler")
|
||||
defer span.End()
|
||||
s.JSONResponse(w, r, os.Environ())
|
||||
}
|
||||
|
||||
@@ -13,5 +13,7 @@ import (
|
||||
// @Router /headers [get]
|
||||
// @Success 200 {object} api.ArrayResponse
|
||||
func (s *Server) echoHeadersHandler(w http.ResponseWriter, r *http.Request) {
|
||||
_, span := s.tracer.Start(r.Context(), "echoHeadersHandler")
|
||||
defer span.End()
|
||||
s.JSONResponse(w, r, r.Header)
|
||||
}
|
||||
|
||||
@@ -8,6 +8,8 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/stefanprodan/podinfo/pkg/version"
|
||||
"go.opentelemetry.io/otel/codes"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
@@ -33,27 +35,6 @@ func versionMiddleware(next http.Handler) http.Handler {
|
||||
})
|
||||
}
|
||||
|
||||
// TODO: use Istio tracing package
|
||||
// https://github.com/istio/istio/blob/master/pkg/tracing/config.go
|
||||
func copyTracingHeaders(from *http.Request, to *http.Request) {
|
||||
headers := []string{
|
||||
"x-request-id",
|
||||
"x-b3-traceid",
|
||||
"x-b3-spanid",
|
||||
"x-b3-parentspanid",
|
||||
"x-b3-sampled",
|
||||
"x-b3-flags",
|
||||
"x-ot-span-context",
|
||||
}
|
||||
|
||||
for i := range headers {
|
||||
headerValue := from.Header.Get(headers[i])
|
||||
if len(headerValue) > 0 {
|
||||
to.Header.Set(headers[i], headerValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) JSONResponse(w http.ResponseWriter, r *http.Request, result interface{}) {
|
||||
body, err := json.Marshal(result)
|
||||
if err != nil {
|
||||
@@ -82,7 +63,7 @@ func (s *Server) JSONResponseCode(w http.ResponseWriter, r *http.Request, result
|
||||
w.Write(prettyJSON(body))
|
||||
}
|
||||
|
||||
func (s *Server) ErrorResponse(w http.ResponseWriter, r *http.Request, error string, code int) {
|
||||
func (s *Server) ErrorResponse(w http.ResponseWriter, r *http.Request, span trace.Span, error string, code int) {
|
||||
data := struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
@@ -91,6 +72,8 @@ func (s *Server) ErrorResponse(w http.ResponseWriter, r *http.Request, error str
|
||||
Message: error,
|
||||
}
|
||||
|
||||
span.SetStatus(codes.Error, error)
|
||||
|
||||
body, err := json.Marshal(data)
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
|
||||
@@ -14,6 +14,9 @@ import (
|
||||
// @Router / [get]
|
||||
// @Success 200 {string} string "OK"
|
||||
func (s *Server) indexHandler(w http.ResponseWriter, r *http.Request) {
|
||||
_, span := s.tracer.Start(r.Context(), "indexHandler")
|
||||
defer span.End()
|
||||
|
||||
tmpl, err := template.New("vue.html").ParseFiles(path.Join(s.config.UIPath, "vue.html"))
|
||||
if err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
|
||||
@@ -18,6 +18,9 @@ import (
|
||||
// @Success 200 {object} api.RuntimeResponse
|
||||
// @Router /api/info [get]
|
||||
func (s *Server) infoHandler(w http.ResponseWriter, r *http.Request) {
|
||||
_, span := s.tracer.Start(r.Context(), "infoHandler")
|
||||
defer span.End()
|
||||
|
||||
data := RuntimeResponse{
|
||||
Hostname: s.config.Hostname,
|
||||
Version: version.VERSION,
|
||||
|
||||
@@ -3,6 +3,8 @@ package api
|
||||
import (
|
||||
"time"
|
||||
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@@ -28,5 +30,6 @@ func NewMockServer() *Server {
|
||||
router: mux.NewRouter(),
|
||||
logger: logger,
|
||||
config: config,
|
||||
tracer: trace.NewNoopTracerProvider().Tracer("mock"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,8 @@ import (
|
||||
"github.com/stefanprodan/podinfo/pkg/fscache"
|
||||
httpSwagger "github.com/swaggo/http-swagger"
|
||||
"github.com/swaggo/swag"
|
||||
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/net/http2"
|
||||
"golang.org/x/net/http2/h2c"
|
||||
@@ -74,11 +76,13 @@ type Config struct {
|
||||
}
|
||||
|
||||
type Server struct {
|
||||
router *mux.Router
|
||||
logger *zap.Logger
|
||||
config *Config
|
||||
pool *redis.Pool
|
||||
handler http.Handler
|
||||
router *mux.Router
|
||||
logger *zap.Logger
|
||||
config *Config
|
||||
pool *redis.Pool
|
||||
handler http.Handler
|
||||
tracer trace.Tracer
|
||||
tracerProvider *sdktrace.TracerProvider
|
||||
}
|
||||
|
||||
func NewServer(config *Config, logger *zap.Logger) (*Server, error) {
|
||||
@@ -123,9 +127,6 @@ func (s *Server) registerHandlers() {
|
||||
s.router.PathPrefix("/swagger/").Handler(httpSwagger.Handler(
|
||||
httpSwagger.URL("/swagger/doc.json"),
|
||||
))
|
||||
s.router.PathPrefix("/swagger/").Handler(httpSwagger.Handler(
|
||||
httpSwagger.URL("/swagger/doc.json"),
|
||||
))
|
||||
s.router.HandleFunc("/swagger.json", func(w http.ResponseWriter, r *http.Request) {
|
||||
doc, err := swag.ReadDoc()
|
||||
if err != nil {
|
||||
@@ -138,6 +139,8 @@ func (s *Server) registerHandlers() {
|
||||
func (s *Server) registerMiddlewares() {
|
||||
prom := NewPrometheusMiddleware()
|
||||
s.router.Use(prom.Handler)
|
||||
otel := NewOpenTelemetryMiddleware()
|
||||
s.router.Use(otel)
|
||||
httpLogger := NewLoggingMiddleware(s.logger)
|
||||
s.router.Use(httpLogger.Handler)
|
||||
s.router.Use(versionMiddleware)
|
||||
@@ -151,8 +154,11 @@ func (s *Server) registerMiddlewares() {
|
||||
}
|
||||
|
||||
func (s *Server) ListenAndServe(stopCh <-chan struct{}) {
|
||||
ctx := context.Background()
|
||||
|
||||
go s.startMetricsServer()
|
||||
|
||||
s.initTracer(ctx)
|
||||
s.registerHandlers()
|
||||
s.registerMiddlewares()
|
||||
|
||||
@@ -195,7 +201,7 @@ func (s *Server) ListenAndServe(stopCh <-chan struct{}) {
|
||||
|
||||
// wait for SIGTERM or SIGINT
|
||||
<-stopCh
|
||||
ctx, cancel := context.WithTimeout(context.Background(), s.config.HttpServerShutdownTimeout)
|
||||
ctx, cancel := context.WithTimeout(ctx, s.config.HttpServerShutdownTimeout)
|
||||
defer cancel()
|
||||
|
||||
// all calls to /healthz and /readyz will fail from now on
|
||||
@@ -215,6 +221,13 @@ func (s *Server) ListenAndServe(stopCh <-chan struct{}) {
|
||||
time.Sleep(3 * time.Second)
|
||||
}
|
||||
|
||||
// stop OpenTelemetry tracer provider
|
||||
if s.tracerProvider != nil {
|
||||
if err := s.tracerProvider.Shutdown(ctx); err != nil {
|
||||
s.logger.Warn("stopping tracer provider", zap.Error(err))
|
||||
}
|
||||
}
|
||||
|
||||
// determine if the http server was started
|
||||
if srv != nil {
|
||||
if err := srv.Shutdown(ctx); err != nil {
|
||||
|
||||
@@ -17,11 +17,14 @@ import (
|
||||
// @Router /status/{code} [get]
|
||||
// @Success 200 {object} api.MapResponse
|
||||
func (s *Server) statusHandler(w http.ResponseWriter, r *http.Request) {
|
||||
_, span := s.tracer.Start(r.Context(), "statusHandler")
|
||||
defer span.End()
|
||||
|
||||
vars := mux.Vars(r)
|
||||
|
||||
code, err := strconv.Atoi(vars["code"])
|
||||
if err != nil {
|
||||
s.ErrorResponse(w, r, err.Error(), http.StatusBadRequest)
|
||||
s.ErrorResponse(w, r, span, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -20,10 +20,12 @@ import (
|
||||
// @Router /store [post]
|
||||
// @Success 200 {object} api.MapResponse
|
||||
func (s *Server) storeWriteHandler(w http.ResponseWriter, r *http.Request) {
|
||||
_, span := s.tracer.Start(r.Context(), "storeWriteHandler")
|
||||
defer span.End()
|
||||
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
s.ErrorResponse(w, r, "reading the request body failed", http.StatusBadRequest)
|
||||
s.ErrorResponse(w, r, span, "reading the request body failed", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -31,7 +33,7 @@ func (s *Server) storeWriteHandler(w http.ResponseWriter, r *http.Request) {
|
||||
err = ioutil.WriteFile(path.Join(s.config.DataPath, hash), body, 0644)
|
||||
if err != nil {
|
||||
s.logger.Warn("writing file failed", zap.Error(err), zap.String("file", path.Join(s.config.DataPath, hash)))
|
||||
s.ErrorResponse(w, r, "writing file failed", http.StatusInternalServerError)
|
||||
s.ErrorResponse(w, r, span, "writing file failed", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
s.JSONResponseCode(w, r, map[string]string{"hash": hash}, http.StatusAccepted)
|
||||
@@ -46,11 +48,14 @@ func (s *Server) storeWriteHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// @Router /store/{hash} [get]
|
||||
// @Success 200 {string} string "file"
|
||||
func (s *Server) storeReadHandler(w http.ResponseWriter, r *http.Request) {
|
||||
_, span := s.tracer.Start(r.Context(), "storeReadHandler")
|
||||
defer span.End()
|
||||
|
||||
hash := mux.Vars(r)["hash"]
|
||||
content, err := ioutil.ReadFile(path.Join(s.config.DataPath, hash))
|
||||
if err != nil {
|
||||
s.logger.Warn("reading file failed", zap.Error(err), zap.String("file", path.Join(s.config.DataPath, hash)))
|
||||
s.ErrorResponse(w, r, "reading file failed", http.StatusInternalServerError)
|
||||
s.ErrorResponse(w, r, span, "reading file failed", http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
w.WriteHeader(http.StatusAccepted)
|
||||
|
||||
@@ -26,10 +26,13 @@ type jwtCustomClaims struct {
|
||||
// @Router /token [post]
|
||||
// @Success 200 {object} api.TokenResponse
|
||||
func (s *Server) tokenGenerateHandler(w http.ResponseWriter, r *http.Request) {
|
||||
_, span := s.tracer.Start(r.Context(), "tokenGenerateHandler")
|
||||
defer span.End()
|
||||
|
||||
body, err := ioutil.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
s.logger.Error("reading the request body failed", zap.Error(err))
|
||||
s.ErrorResponse(w, r, "invalid request body", http.StatusBadRequest)
|
||||
s.ErrorResponse(w, r, span, "invalid request body", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
defer r.Body.Close()
|
||||
@@ -51,7 +54,7 @@ func (s *Server) tokenGenerateHandler(w http.ResponseWriter, r *http.Request) {
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
t, err := token.SignedString([]byte(s.config.JWTSecret))
|
||||
if err != nil {
|
||||
s.ErrorResponse(w, r, err.Error(), http.StatusBadRequest)
|
||||
s.ErrorResponse(w, r, span, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -75,14 +78,17 @@ func (s *Server) tokenGenerateHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// Get: JWT=$(curl -s -d 'test' localhost:9898/token | jq -r .token)
|
||||
// Post: curl -H "Authorization: Bearer ${JWT}" localhost:9898/token/validate
|
||||
func (s *Server) tokenValidateHandler(w http.ResponseWriter, r *http.Request) {
|
||||
_, span := s.tracer.Start(r.Context(), "tokenValidateHandler")
|
||||
defer span.End()
|
||||
|
||||
authorizationHeader := r.Header.Get("authorization")
|
||||
if authorizationHeader == "" {
|
||||
s.ErrorResponse(w, r, "authorization bearer header required", http.StatusUnauthorized)
|
||||
s.ErrorResponse(w, r, span, "authorization bearer header required", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
bearerToken := strings.Split(authorizationHeader, " ")
|
||||
if len(bearerToken) != 2 || strings.ToLower(bearerToken[0]) != "bearer" {
|
||||
s.ErrorResponse(w, r, "authorization bearer header required", http.StatusUnauthorized)
|
||||
s.ErrorResponse(w, r, span, "authorization bearer header required", http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -94,13 +100,13 @@ func (s *Server) tokenValidateHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return []byte(s.config.JWTSecret), nil
|
||||
})
|
||||
if err != nil {
|
||||
s.ErrorResponse(w, r, err.Error(), http.StatusUnauthorized)
|
||||
s.ErrorResponse(w, r, span, err.Error(), http.StatusUnauthorized)
|
||||
return
|
||||
}
|
||||
|
||||
if token.Valid {
|
||||
if claims.StandardClaims.Issuer != "podinfo" {
|
||||
s.ErrorResponse(w, r, "invalid issuer", http.StatusUnauthorized)
|
||||
s.ErrorResponse(w, r, span, "invalid issuer", http.StatusUnauthorized)
|
||||
} else {
|
||||
var result = TokenValidationResponse{
|
||||
TokenName: claims.Name,
|
||||
@@ -109,7 +115,7 @@ func (s *Server) tokenValidateHandler(w http.ResponseWriter, r *http.Request) {
|
||||
s.JSONResponse(w, r, result)
|
||||
}
|
||||
} else {
|
||||
s.ErrorResponse(w, r, "Invalid authorization token", http.StatusUnauthorized)
|
||||
s.ErrorResponse(w, r, span, "Invalid authorization token", http.StatusUnauthorized)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
70
pkg/api/tracer.go
Normal file
70
pkg/api/tracer.go
Normal file
@@ -0,0 +1,70 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/spf13/viper"
|
||||
"github.com/stefanprodan/podinfo/pkg/version"
|
||||
"go.opentelemetry.io/contrib/instrumentation/github.com/gorilla/mux/otelmux"
|
||||
"go.opentelemetry.io/contrib/propagators/aws/xray"
|
||||
"go.opentelemetry.io/contrib/propagators/b3"
|
||||
"go.opentelemetry.io/contrib/propagators/jaeger"
|
||||
"go.opentelemetry.io/contrib/propagators/ot"
|
||||
"go.opentelemetry.io/otel"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlptrace"
|
||||
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
|
||||
"go.opentelemetry.io/otel/propagation"
|
||||
"go.opentelemetry.io/otel/sdk/resource"
|
||||
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
||||
semconv "go.opentelemetry.io/otel/semconv/v1.7.0"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
const (
|
||||
instrumentationName = "github.com/stefanprodan/podinfo/pkg/api"
|
||||
)
|
||||
|
||||
func (s *Server) initTracer(ctx context.Context) {
|
||||
if viper.GetString("otel-service-name") == "" {
|
||||
nop := trace.NewNoopTracerProvider()
|
||||
s.tracer = nop.Tracer(viper.GetString("otel-service-name"))
|
||||
return
|
||||
}
|
||||
|
||||
client := otlptracegrpc.NewClient()
|
||||
exporter, err := otlptrace.New(ctx, client)
|
||||
if err != nil {
|
||||
s.logger.Error("creating OTLP trace exporter", zap.Error(err))
|
||||
}
|
||||
|
||||
s.tracerProvider = sdktrace.NewTracerProvider(
|
||||
sdktrace.WithBatcher(exporter),
|
||||
sdktrace.WithResource(resource.NewWithAttributes(
|
||||
semconv.SchemaURL,
|
||||
semconv.ServiceNameKey.String(viper.GetString("otel-service-name")),
|
||||
semconv.ServiceVersionKey.String(version.VERSION),
|
||||
)),
|
||||
)
|
||||
|
||||
otel.SetTracerProvider(s.tracerProvider)
|
||||
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(
|
||||
propagation.TraceContext{},
|
||||
propagation.Baggage{},
|
||||
b3.New(),
|
||||
&jaeger.Jaeger{},
|
||||
&ot.OT{},
|
||||
&xray.Propagator{},
|
||||
))
|
||||
|
||||
s.tracer = s.tracerProvider.Tracer(
|
||||
instrumentationName,
|
||||
trace.WithInstrumentationVersion(version.VERSION),
|
||||
trace.WithSchemaURL(semconv.SchemaURL),
|
||||
)
|
||||
}
|
||||
|
||||
func NewOpenTelemetryMiddleware() mux.MiddlewareFunc {
|
||||
return otelmux.Middleware(viper.GetString("otel-service-name"))
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
//go:build !windows
|
||||
// +build !windows
|
||||
|
||||
package signals
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package version
|
||||
|
||||
var VERSION = "6.0.0"
|
||||
var VERSION = "6.1.1"
|
||||
var REVISION = "unknown"
|
||||
|
||||
@@ -1,17 +1,12 @@
|
||||
#! /usr/bin/env sh
|
||||
|
||||
# add jetstack repository
|
||||
helm repo add jetstack https://charts.jetstack.io || true
|
||||
|
||||
# install cert-manager
|
||||
helm upgrade --install cert-manager jetstack/cert-manager \
|
||||
--set installCRDs=true \
|
||||
--namespace default
|
||||
kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.5.3/cert-manager.yaml
|
||||
|
||||
# wait for cert manager
|
||||
kubectl rollout status deployment/cert-manager --timeout=2m
|
||||
kubectl rollout status deployment/cert-manager-webhook --timeout=2m
|
||||
kubectl rollout status deployment/cert-manager-cainjector --timeout=2m
|
||||
kubectl -n cert-manager rollout status deployment/cert-manager --timeout=2m
|
||||
kubectl -n cert-manager rollout status deployment/cert-manager-webhook --timeout=2m
|
||||
kubectl -n cert-manager rollout status deployment/cert-manager-cainjector --timeout=2m
|
||||
|
||||
# install self-signed certificate
|
||||
cat << 'EOF' | kubectl apply -f -
|
||||
|
||||
Reference in New Issue
Block a user