mirror of
https://github.com/kubeshark/kubeshark.git
synced 2026-03-02 17:50:30 +00:00
Compare commits
99 Commits
32.0-dev14
...
36.0-dev4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
38c05a6634 | ||
|
|
d857935889 | ||
|
|
ec11b21b51 | ||
|
|
52c9251c00 | ||
|
|
f3a6b3a9d4 | ||
|
|
5f73c2d50a | ||
|
|
d6944d467c | ||
|
|
57078517a4 | ||
|
|
b4bc09637c | ||
|
|
302333b4ae | ||
|
|
13ed8eb58a | ||
|
|
48619b3e1c | ||
|
|
3b0b311e1e | ||
|
|
3a9236a381 | ||
|
|
2e7fd34210 | ||
|
|
01af6aa19c | ||
|
|
2bfae1baae | ||
|
|
2df9fb49db | ||
|
|
c1b2cda468 | ||
|
|
cf91f3dab4 | ||
|
|
1ebc51b45e | ||
|
|
a96072623f | ||
|
|
8c187179b0 | ||
|
|
d7d802830f | ||
|
|
4d64dd4b04 | ||
|
|
9a40895e9c | ||
|
|
f9a9c05f48 | ||
|
|
c9d4f88de8 | ||
|
|
6f117d0a84 | ||
|
|
99cb0b4f44 | ||
|
|
167bbe3741 | ||
|
|
7a823e89f1 | ||
|
|
be98d85cb8 | ||
|
|
e743ab7f7a | ||
|
|
78081a4a16 | ||
|
|
0ef6a7d2c4 | ||
|
|
ba361df7e7 | ||
|
|
1f70eab0a4 | ||
|
|
ea4991905b | ||
|
|
2ad4838cf5 | ||
|
|
e41488ef3e | ||
|
|
533fb71bf4 | ||
|
|
6f8aad83e6 | ||
|
|
6e6bcec77e | ||
|
|
71db792a4e | ||
|
|
f7f61c1217 | ||
|
|
696501fa11 | ||
|
|
415b5e08fd | ||
|
|
7810f6defb | ||
|
|
2aeac6c9e6 | ||
|
|
dc241218bf | ||
|
|
02b3672e09 | ||
|
|
45b368b33e | ||
|
|
8f64fdaa61 | ||
|
|
7edb0b153b | ||
|
|
569a687fdf | ||
|
|
11e8b5eb65 | ||
|
|
3901f3f3fe | ||
|
|
2f1cc21fcb | ||
|
|
433253a27b | ||
|
|
00cc94fbe5 | ||
|
|
8feef78ab1 | ||
|
|
992abc99bc | ||
|
|
486d0b1088 | ||
|
|
f61a02d288 | ||
|
|
03694e57c0 | ||
|
|
1760afda2b | ||
|
|
522e2cc3da | ||
|
|
ab38f4c011 | ||
|
|
a9de4f0bba | ||
|
|
948af518b5 | ||
|
|
73448b514e | ||
|
|
fc194354bc | ||
|
|
8418802c7e | ||
|
|
bfa834e840 | ||
|
|
5c012641a5 | ||
|
|
74bd4b180f | ||
|
|
8ea2dabb34 | ||
|
|
366d34b8d0 | ||
|
|
5fc3e38c1a | ||
|
|
09a0fca2c2 | ||
|
|
0437586908 | ||
|
|
f8181ccb07 | ||
|
|
414e5cfe5a | ||
|
|
2fac0009ea | ||
|
|
36d59ede07 | ||
|
|
ac53508ad7 | ||
|
|
e24c18254c | ||
|
|
b2830f133f | ||
|
|
eef0ee8023 | ||
|
|
4c0aeb8146 | ||
|
|
0dc0459dff | ||
|
|
81f06003d5 | ||
|
|
c7d068748a | ||
|
|
8102c49138 | ||
|
|
65fb2a4fe4 | ||
|
|
57f8a8dca9 | ||
|
|
aead6cbc19 | ||
|
|
2f89690da6 |
12
.github/workflows/release.yml
vendored
12
.github/workflows/release.yml
vendored
@@ -290,3 +290,15 @@ jobs:
|
|||||||
tag: ${{ steps.versioning.outputs.version }}
|
tag: ${{ steps.versioning.outputs.version }}
|
||||||
prerelease: ${{ github.ref != 'refs/heads/main' }}
|
prerelease: ${{ github.ref != 'refs/heads/main' }}
|
||||||
bodyFile: 'cli/bin/README.md'
|
bodyFile: 'cli/bin/README.md'
|
||||||
|
|
||||||
|
- name: Slack notification on failure
|
||||||
|
uses: ravsamhq/notify-slack-action@v1
|
||||||
|
if: always()
|
||||||
|
with:
|
||||||
|
status: ${{ job.status }}
|
||||||
|
notification_title: 'Mizu enterprise {workflow} has {status_message}'
|
||||||
|
message_format: '{emoji} *{workflow}* {status_message} during <{run_url}|run>, after commit <{commit_url}|{commit_sha}> by ${{ github.event.head_commit.author.name }} <${{ github.event.head_commit.author.email }}> ```${{ github.event.head_commit.message }}```'
|
||||||
|
footer: 'Linked Repo <{repo_url}|{repo}>'
|
||||||
|
notify_when: 'failure'
|
||||||
|
env:
|
||||||
|
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||||
|
|||||||
11
.github/workflows/static_code_analysis.yml
vendored
11
.github/workflows/static_code_analysis.yml
vendored
@@ -26,6 +26,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install -y libpcap-dev
|
sudo apt install -y libpcap-dev
|
||||||
|
./devops/install-capstone.sh
|
||||||
|
|
||||||
- name: Check Agent modified files
|
- name: Check Agent modified files
|
||||||
id: agent_modified_files
|
id: agent_modified_files
|
||||||
@@ -37,7 +38,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
working-directory: agent
|
working-directory: agent
|
||||||
args: --timeout=3m
|
args: --timeout=10m
|
||||||
|
|
||||||
- name: Check shared modified files
|
- name: Check shared modified files
|
||||||
id: shared_modified_files
|
id: shared_modified_files
|
||||||
@@ -49,7 +50,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
working-directory: shared
|
working-directory: shared
|
||||||
args: --timeout=3m
|
args: --timeout=10m
|
||||||
|
|
||||||
- name: Check tap modified files
|
- name: Check tap modified files
|
||||||
id: tap_modified_files
|
id: tap_modified_files
|
||||||
@@ -61,7 +62,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
working-directory: tap
|
working-directory: tap
|
||||||
args: --timeout=3m
|
args: --timeout=10m
|
||||||
|
|
||||||
- name: Check cli modified files
|
- name: Check cli modified files
|
||||||
id: cli_modified_files
|
id: cli_modified_files
|
||||||
@@ -73,7 +74,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
working-directory: cli
|
working-directory: cli
|
||||||
args: --timeout=3m
|
args: --timeout=10m
|
||||||
|
|
||||||
- name: Check acceptanceTests modified files
|
- name: Check acceptanceTests modified files
|
||||||
id: acceptanceTests_modified_files
|
id: acceptanceTests_modified_files
|
||||||
@@ -85,7 +86,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
working-directory: acceptanceTests
|
working-directory: acceptanceTests
|
||||||
args: --timeout=3m
|
args: --timeout=10m
|
||||||
|
|
||||||
- name: Check tap/api modified files
|
- name: Check tap/api modified files
|
||||||
id: tap_api_modified_files
|
id: tap_api_modified_files
|
||||||
|
|||||||
5
.github/workflows/test.yml
vendored
5
.github/workflows/test.yml
vendored
@@ -35,6 +35,11 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
sudo apt-get install libpcap-dev
|
sudo apt-get install libpcap-dev
|
||||||
|
|
||||||
|
- name: Install Capstone
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
./devops/install-capstone.sh
|
||||||
|
|
||||||
- name: Check CLI modified files
|
- name: Check CLI modified files
|
||||||
id: cli_modified_files
|
id: cli_modified_files
|
||||||
run: devops/check_modified_files.sh cli/
|
run: devops/check_modified_files.sh cli/
|
||||||
|
|||||||
5
.gitignore
vendored
5
.gitignore
vendored
@@ -52,4 +52,7 @@ tap/extensions/*/expect
|
|||||||
# UI folders to ignore
|
# UI folders to ignore
|
||||||
**/node_modules/**
|
**/node_modules/**
|
||||||
**/dist/**
|
**/dist/**
|
||||||
*.editorconfig
|
*.editorconfig
|
||||||
|
|
||||||
|
# Ignore *.log files
|
||||||
|
*.log
|
||||||
|
|||||||
40
Dockerfile
40
Dockerfile
@@ -25,29 +25,46 @@ RUN npm run build
|
|||||||
### Base builder image for native builds architecture
|
### Base builder image for native builds architecture
|
||||||
FROM golang:1.17-alpine AS builder-native-base
|
FROM golang:1.17-alpine AS builder-native-base
|
||||||
ENV CGO_ENABLED=1 GOOS=linux
|
ENV CGO_ENABLED=1 GOOS=linux
|
||||||
RUN apk add --no-cache libpcap-dev g++ perl-utils
|
RUN apk add --no-cache \
|
||||||
|
libpcap-dev \
|
||||||
|
g++ \
|
||||||
|
perl-utils \
|
||||||
|
curl \
|
||||||
|
build-base \
|
||||||
|
binutils-gold \
|
||||||
|
bash \
|
||||||
|
clang \
|
||||||
|
llvm \
|
||||||
|
libbpf-dev \
|
||||||
|
linux-headers
|
||||||
|
COPY devops/install-capstone.sh .
|
||||||
|
RUN ./install-capstone.sh
|
||||||
|
|
||||||
|
|
||||||
### Intermediate builder image for x86-64 to x86-64 native builds
|
### Intermediate builder image for x86-64 to x86-64 native builds
|
||||||
FROM builder-native-base AS builder-from-amd64-to-amd64
|
FROM builder-native-base AS builder-from-amd64-to-amd64
|
||||||
ENV GOARCH=amd64
|
ENV GOARCH=amd64
|
||||||
|
ENV BPF_TARGET=amd64 BPF_CFLAGS="-O2 -g -D__TARGET_ARCH_x86"
|
||||||
|
|
||||||
|
|
||||||
### Intermediate builder image for AArch64 to AArch64 native builds
|
### Intermediate builder image for AArch64 to AArch64 native builds
|
||||||
FROM builder-native-base AS builder-from-arm64v8-to-arm64v8
|
FROM builder-native-base AS builder-from-arm64v8-to-arm64v8
|
||||||
ENV GOARCH=arm64
|
ENV GOARCH=arm64
|
||||||
|
ENV BPF_TARGET=arm64 BPF_CFLAGS="-O2 -g -D__TARGET_ARCH_arm64"
|
||||||
|
|
||||||
|
|
||||||
### Builder image for x86-64 to AArch64 cross-compilation
|
### Builder image for x86-64 to AArch64 cross-compilation
|
||||||
FROM up9inc/linux-arm64-musl-go-libpcap AS builder-from-amd64-to-arm64v8
|
FROM up9inc/linux-arm64-musl-go-libpcap-capstone-bpf:capstone-5.0-rc2 AS builder-from-amd64-to-arm64v8
|
||||||
ENV CGO_ENABLED=1 GOOS=linux
|
ENV CGO_ENABLED=1 GOOS=linux
|
||||||
ENV GOARCH=arm64 CGO_CFLAGS="-I/work/libpcap"
|
ENV GOARCH=arm64 CGO_CFLAGS="-I/work/libpcap -I/work/capstone/include"
|
||||||
|
ENV BPF_TARGET=arm64 BPF_CFLAGS="-O2 -g -D__TARGET_ARCH_arm64 -I/usr/xcc/aarch64-linux-musl-cross/aarch64-linux-musl/include/"
|
||||||
|
|
||||||
|
|
||||||
### Builder image for AArch64 to x86-64 cross-compilation
|
### Builder image for AArch64 to x86-64 cross-compilation
|
||||||
FROM up9inc/linux-x86_64-musl-go-libpcap AS builder-from-arm64v8-to-amd64
|
FROM up9inc/linux-x86_64-musl-go-libpcap-capstone-bpf:capstone-5.0-rc2 AS builder-from-arm64v8-to-amd64
|
||||||
ENV CGO_ENABLED=1 GOOS=linux
|
ENV CGO_ENABLED=1 GOOS=linux
|
||||||
ENV GOARCH=amd64 CGO_CFLAGS="-I/libpcap"
|
ENV GOARCH=amd64 CGO_CFLAGS="-I/libpcap -I/capstone/include"
|
||||||
|
ENV BPF_TARGET=amd64 BPF_CFLAGS="-O2 -g -D__TARGET_ARCH_x86 -I/usr/local/musl/x86_64-unknown-linux-musl/include/"
|
||||||
|
|
||||||
|
|
||||||
### Final builder image where the build happens
|
### Final builder image where the build happens
|
||||||
@@ -68,14 +85,12 @@ COPY shared/go.mod shared/go.mod ../shared/
|
|||||||
COPY logger/go.mod logger/go.mod ../logger/
|
COPY logger/go.mod logger/go.mod ../logger/
|
||||||
COPY tap/go.mod tap/go.mod ../tap/
|
COPY tap/go.mod tap/go.mod ../tap/
|
||||||
COPY tap/api/go.mod ../tap/api/
|
COPY tap/api/go.mod ../tap/api/
|
||||||
|
COPY tap/dbgctl/go.mod ../tap/dbgctl/
|
||||||
COPY tap/extensions/amqp/go.mod ../tap/extensions/amqp/
|
COPY tap/extensions/amqp/go.mod ../tap/extensions/amqp/
|
||||||
COPY tap/extensions/http/go.mod ../tap/extensions/http/
|
COPY tap/extensions/http/go.mod ../tap/extensions/http/
|
||||||
COPY tap/extensions/kafka/go.mod ../tap/extensions/kafka/
|
COPY tap/extensions/kafka/go.mod ../tap/extensions/kafka/
|
||||||
COPY tap/extensions/redis/go.mod ../tap/extensions/redis/
|
COPY tap/extensions/redis/go.mod ../tap/extensions/redis/
|
||||||
RUN go mod download
|
RUN go mod download
|
||||||
# cheap trick to make the build faster (as long as go.mod did not change)
|
|
||||||
RUN go get github.com/patrickmn/go-cache
|
|
||||||
RUN go list -f '{{.Path}}@{{.Version}}' -m all | sed 1d | grep -e 'go-cache' | xargs go get
|
|
||||||
|
|
||||||
# Copy and build agent code
|
# Copy and build agent code
|
||||||
COPY shared ../shared
|
COPY shared ../shared
|
||||||
@@ -88,6 +103,11 @@ ARG GIT_BRANCH
|
|||||||
ARG BUILD_TIMESTAMP
|
ARG BUILD_TIMESTAMP
|
||||||
ARG VER=0.0
|
ARG VER=0.0
|
||||||
|
|
||||||
|
WORKDIR /app/tap/tlstapper
|
||||||
|
|
||||||
|
RUN rm tlstapper_bpf*
|
||||||
|
RUN GOARCH=${BUILDARCH} go generate tls_tapper.go
|
||||||
|
|
||||||
WORKDIR /app/agent-build
|
WORKDIR /app/agent-build
|
||||||
|
|
||||||
RUN go build -ldflags="-extldflags=-static -s -w \
|
RUN go build -ldflags="-extldflags=-static -s -w \
|
||||||
@@ -97,8 +117,8 @@ RUN go build -ldflags="-extldflags=-static -s -w \
|
|||||||
-X 'github.com/up9inc/mizu/agent/pkg/version.Ver=${VER}'" -o mizuagent .
|
-X 'github.com/up9inc/mizu/agent/pkg/version.Ver=${VER}'" -o mizuagent .
|
||||||
|
|
||||||
# Download Basenine executable, verify the sha1sum
|
# Download Basenine executable, verify the sha1sum
|
||||||
ADD https://github.com/up9inc/basenine/releases/download/v0.7.3/basenine_linux_${GOARCH} ./basenine_linux_${GOARCH}
|
ADD https://github.com/up9inc/basenine/releases/download/v0.8.3/basenine_linux_${GOARCH} ./basenine_linux_${GOARCH}
|
||||||
ADD https://github.com/up9inc/basenine/releases/download/v0.7.3/basenine_linux_${GOARCH}.sha256 ./basenine_linux_${GOARCH}.sha256
|
ADD https://github.com/up9inc/basenine/releases/download/v0.8.3/basenine_linux_${GOARCH}.sha256 ./basenine_linux_${GOARCH}.sha256
|
||||||
|
|
||||||
RUN shasum -a 256 -c basenine_linux_"${GOARCH}".sha256 && \
|
RUN shasum -a 256 -c basenine_linux_"${GOARCH}".sha256 && \
|
||||||
chmod +x ./basenine_linux_"${GOARCH}" && \
|
chmod +x ./basenine_linux_"${GOARCH}" && \
|
||||||
|
|||||||
1
Makefile
1
Makefile
@@ -83,6 +83,7 @@ test-lint: ## Run lint on all modules
|
|||||||
cd cli && golangci-lint run
|
cd cli && golangci-lint run
|
||||||
cd acceptanceTests && golangci-lint run
|
cd acceptanceTests && golangci-lint run
|
||||||
cd tap/api && golangci-lint run
|
cd tap/api && golangci-lint run
|
||||||
|
cd tap/dbgctl && golangci-lint run
|
||||||
cd tap/extensions/ && for D in */; do cd $$D && golangci-lint run && cd ..; done
|
cd tap/extensions/ && for D in */; do cd $$D && golangci-lint run && cd ..; done
|
||||||
|
|
||||||
test-cli: ## Run cli tests
|
test-cli: ## Run cli tests
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
test: ## Run acceptance tests.
|
test: ## Run acceptance tests.
|
||||||
|
@npm install cypress@10.0.1 -y
|
||||||
@go test ./... -timeout 1h -v
|
@go test ./... -timeout 1h -v
|
||||||
|
|||||||
31
acceptanceTests/cypress.config.js
Normal file
31
acceptanceTests/cypress.config.js
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
const { defineConfig } = require('cypress')
|
||||||
|
|
||||||
|
module.exports = defineConfig({
|
||||||
|
watchForFileChanges: false,
|
||||||
|
viewportWidth: 1920,
|
||||||
|
viewportHeight: 1080,
|
||||||
|
video: false,
|
||||||
|
screenshotOnRunFailure: false,
|
||||||
|
defaultCommandTimeout: 6000,
|
||||||
|
env: {
|
||||||
|
testUrl: 'http://localhost:8899/',
|
||||||
|
redactHeaderContent: 'User-Header[REDACTED]',
|
||||||
|
redactBodyContent: '{ "User": "[REDACTED]" }',
|
||||||
|
regexMaskingBodyContent: '[REDACTED]',
|
||||||
|
greenFilterColor: 'rgb(210, 250, 210)',
|
||||||
|
redFilterColor: 'rgb(250, 214, 220)',
|
||||||
|
bodyJsonClass: '.hljs',
|
||||||
|
mizuWidth: 1920,
|
||||||
|
normalMizuHeight: 1080,
|
||||||
|
hugeMizuHeight: 3500,
|
||||||
|
},
|
||||||
|
e2e: {
|
||||||
|
// We've imported your old cypress plugins here.
|
||||||
|
// You may want to clean this up later by importing these.
|
||||||
|
// setupNodeEvents(on, config) {
|
||||||
|
// return require('./cypress/plugins/index.js')(on, config)
|
||||||
|
// },
|
||||||
|
specPattern: 'cypress/e2e/tests/*.js',
|
||||||
|
supportFile: false
|
||||||
|
},
|
||||||
|
})
|
||||||
@@ -1,34 +0,0 @@
|
|||||||
{
|
|
||||||
"watchForFileChanges":false,
|
|
||||||
"viewportWidth": 1920,
|
|
||||||
"viewportHeight": 1080,
|
|
||||||
"video": false,
|
|
||||||
"screenshotOnRunFailure": false,
|
|
||||||
"defaultCommandTimeout": 6000,
|
|
||||||
"testFiles": [
|
|
||||||
"tests/GuiPort.js",
|
|
||||||
"tests/MultipleNamespaces.js",
|
|
||||||
"tests/Redact.js",
|
|
||||||
"tests/NoRedact.js",
|
|
||||||
"tests/Regex.js",
|
|
||||||
"tests/RegexMasking.js",
|
|
||||||
"tests/IgnoredUserAgents.js",
|
|
||||||
"tests/UiTest.js",
|
|
||||||
"tests/Redis.js",
|
|
||||||
"tests/Rabbit.js",
|
|
||||||
"tests/serviceMapFunction.js"
|
|
||||||
],
|
|
||||||
|
|
||||||
"env": {
|
|
||||||
"testUrl": "http://localhost:8899/",
|
|
||||||
"redactHeaderContent": "User-Header[REDACTED]",
|
|
||||||
"redactBodyContent": "{ \"User\": \"[REDACTED]\" }",
|
|
||||||
"regexMaskingBodyContent": "[REDACTED]",
|
|
||||||
"greenFilterColor": "rgb(210, 250, 210)",
|
|
||||||
"redFilterColor": "rgb(250, 214, 220)",
|
|
||||||
"bodyJsonClass": ".hljs",
|
|
||||||
"mizuWidth": 1920,
|
|
||||||
"normalMizuHeight": 1080,
|
|
||||||
"hugeMizuHeight": 3500
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -4,8 +4,6 @@ export const valueTabs = {
|
|||||||
none: null
|
none: null
|
||||||
}
|
}
|
||||||
|
|
||||||
const maxEntriesInDom = 13;
|
|
||||||
|
|
||||||
export function isValueExistsInElement(shouldInclude, content, domPathToContainer){
|
export function isValueExistsInElement(shouldInclude, content, domPathToContainer){
|
||||||
it(`should ${shouldInclude ? '' : 'not'} include '${content}'`, function () {
|
it(`should ${shouldInclude ? '' : 'not'} include '${content}'`, function () {
|
||||||
cy.get(domPathToContainer).then(htmlText => {
|
cy.get(domPathToContainer).then(htmlText => {
|
||||||
@@ -57,15 +55,8 @@ export function rightOnHoverCheck(path, expectedText) {
|
|||||||
cy.get(`#rightSideContainer [data-cy='QueryableTooltip']`).invoke('text').should('match', new RegExp(expectedText));
|
cy.get(`#rightSideContainer [data-cy='QueryableTooltip']`).invoke('text').should('match', new RegExp(expectedText));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkThatAllEntriesShown() {
|
|
||||||
cy.get('#entries-length').then(number => {
|
|
||||||
if (number.text() === '1')
|
|
||||||
cy.get('[title="Fetch old records"]').click();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function checkFilterByMethod(funcDict) {
|
export function checkFilterByMethod(funcDict) {
|
||||||
const {protocol, method, methodQuery, summary, summaryQuery} = funcDict;
|
const {protocol, method, methodQuery, summary, summaryQuery, numberOfRecords} = funcDict;
|
||||||
const summaryDict = getSummaryDict(summary, summaryQuery);
|
const summaryDict = getSummaryDict(summary, summaryQuery);
|
||||||
const methodDict = getMethodDict(method, methodQuery);
|
const methodDict = getMethodDict(method, methodQuery);
|
||||||
const protocolDict = getProtocolDict(protocol.name, protocol.text);
|
const protocolDict = getProtocolDict(protocol.name, protocol.text);
|
||||||
@@ -76,53 +67,53 @@ export function checkFilterByMethod(funcDict) {
|
|||||||
cy.get('[type="submit"]').click();
|
cy.get('[type="submit"]').click();
|
||||||
cy.get('.w-tc-editor').should('have.attr', 'style').and('include', Cypress.env('greenFilterColor'));
|
cy.get('.w-tc-editor').should('have.attr', 'style').and('include', Cypress.env('greenFilterColor'));
|
||||||
|
|
||||||
cy.get('#entries-length').then(number => {
|
waitForFetch(numberOfRecords);
|
||||||
// if the entries list isn't expanded it expands here
|
pauseStream();
|
||||||
if (number.text() === '0' || number.text() === '1') // todo change when TRA-4262 is fixed
|
|
||||||
cy.get('[title="Fetch old records"]').click();
|
|
||||||
|
|
||||||
cy.get('#entries-length').should('not.have.text', '0').and('not.have.text', '1').then(() => {
|
cy.get(`#list [id^=entry]`).then(elements => {
|
||||||
cy.get(`#list [id]`).then(elements => {
|
const listElmWithIdAttr = Object.values(elements);
|
||||||
const listElmWithIdAttr = Object.values(elements);
|
let doneCheckOnFirst = false;
|
||||||
let doneCheckOnFirst = false;
|
|
||||||
|
|
||||||
cy.get('#entries-length').invoke('text').then(len => {
|
cy.get('#entries-length').invoke('text').then(len => {
|
||||||
resizeIfNeeded(len);
|
listElmWithIdAttr.forEach(entry => {
|
||||||
listElmWithIdAttr.forEach(entry => {
|
if (entry?.id && entry.id.match(RegExp(/entry-(\d{24})$/gm))) {
|
||||||
if (entry?.id && entry.id.match(RegExp(/entry-(\d{24})$/gm))) {
|
const entryId = getEntryId(entry.id);
|
||||||
const entryId = getEntryId(entry.id);
|
|
||||||
|
|
||||||
leftTextCheck(entryId, methodDict.pathLeft, methodDict.expectedText);
|
leftTextCheck(entryId, methodDict.pathLeft, methodDict.expectedText);
|
||||||
leftTextCheck(entryId, protocolDict.pathLeft, protocolDict.expectedTextLeft);
|
leftTextCheck(entryId, protocolDict.pathLeft, protocolDict.expectedTextLeft);
|
||||||
if (summaryDict)
|
if (summaryDict)
|
||||||
leftTextCheck(entryId, summaryDict.pathLeft, summaryDict.expectedText);
|
leftTextCheck(entryId, summaryDict.pathLeft, summaryDict.expectedText);
|
||||||
|
|
||||||
if (!doneCheckOnFirst) {
|
if (!doneCheckOnFirst) {
|
||||||
deepCheck(funcDict, protocolDict, methodDict, entry);
|
deepCheck(funcDict, protocolDict, methodDict, entry);
|
||||||
doneCheckOnFirst = true;
|
doneCheckOnFirst = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
|
||||||
resizeIfNeeded(len);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const refreshWaitTimeout = 10000;
|
||||||
|
|
||||||
|
export function waitForFetch(gt) {
|
||||||
|
cy.get('#entries-length', {timeout: refreshWaitTimeout}).should((el) => {
|
||||||
|
expect(parseInt(el.text().trim(), 10)).to.be.greaterThan(gt);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function pauseStream() {
|
||||||
|
cy.get('#pause-icon').click();
|
||||||
|
cy.get('#pause-icon').should('not.be.visible');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
export function getEntryId(id) {
|
export function getEntryId(id) {
|
||||||
// take the second part from the string (entry-<ID>)
|
// take the second part from the string (entry-<ID>)
|
||||||
return id.split('-')[1];
|
return id.split('-')[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
function resizeIfNeeded(entriesLen) {
|
|
||||||
if (entriesLen > maxEntriesInDom){
|
|
||||||
Cypress.config().viewportHeight === Cypress.env('normalMizuHeight') ?
|
|
||||||
resizeToHugeMizu() : resizeToNormalMizu()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function deepCheck(generalDict, protocolDict, methodDict, entry) {
|
function deepCheck(generalDict, protocolDict, methodDict, entry) {
|
||||||
const entryId = getEntryId(entry.id);
|
const entryId = getEntryId(entry.id);
|
||||||
const {summary, value} = generalDict;
|
const {summary, value} = generalDict;
|
||||||
25
acceptanceTests/cypress/e2e/tests/IgnoredUserAgents.js
Normal file
25
acceptanceTests/cypress/e2e/tests/IgnoredUserAgents.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import {
|
||||||
|
isValueExistsInElement,
|
||||||
|
resizeToHugeMizu,
|
||||||
|
} from "../testHelpers/TrafficHelper";
|
||||||
|
|
||||||
|
it('Loading Mizu', function () {
|
||||||
|
cy.visit(Cypress.env('testUrl'));
|
||||||
|
});
|
||||||
|
|
||||||
|
checkEntries();
|
||||||
|
|
||||||
|
function checkEntries() {
|
||||||
|
it('checking all entries', function () {
|
||||||
|
cy.get('#entries-length').should('not.have.text', '0').then(() => {
|
||||||
|
resizeToHugeMizu();
|
||||||
|
|
||||||
|
cy.get('#list [id^=entry]').each(entryElement => {
|
||||||
|
entryElement.click();
|
||||||
|
cy.get('#tbody-Headers').should('be.visible');
|
||||||
|
isValueExistsInElement(false, 'Ignored-User-Agent', '#tbody-Headers');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@@ -5,6 +5,7 @@ it('opening mizu', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const rabbitProtocolDetails = {name: 'AMQP', text: 'Advanced Message Queuing Protocol 0-9-1'};
|
const rabbitProtocolDetails = {name: 'AMQP', text: 'Advanced Message Queuing Protocol 0-9-1'};
|
||||||
|
const numberOfRecords = 5;
|
||||||
|
|
||||||
checkFilterByMethod({
|
checkFilterByMethod({
|
||||||
protocol: rabbitProtocolDetails,
|
protocol: rabbitProtocolDetails,
|
||||||
@@ -12,6 +13,7 @@ checkFilterByMethod({
|
|||||||
methodQuery: 'request.method == "exchange declare"',
|
methodQuery: 'request.method == "exchange declare"',
|
||||||
summary: 'exchange',
|
summary: 'exchange',
|
||||||
summaryQuery: 'request.exchange == "exchange"',
|
summaryQuery: 'request.exchange == "exchange"',
|
||||||
|
numberOfRecords: numberOfRecords,
|
||||||
value: null
|
value: null
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -21,6 +23,7 @@ checkFilterByMethod({
|
|||||||
methodQuery: 'request.method == "queue declare"',
|
methodQuery: 'request.method == "queue declare"',
|
||||||
summary: 'queue',
|
summary: 'queue',
|
||||||
summaryQuery: 'request.queue == "queue"',
|
summaryQuery: 'request.queue == "queue"',
|
||||||
|
numberOfRecords: numberOfRecords,
|
||||||
value: null
|
value: null
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -30,6 +33,7 @@ checkFilterByMethod({
|
|||||||
methodQuery: 'request.method == "queue bind"',
|
methodQuery: 'request.method == "queue bind"',
|
||||||
summary: 'queue',
|
summary: 'queue',
|
||||||
summaryQuery: 'request.queue == "queue"',
|
summaryQuery: 'request.queue == "queue"',
|
||||||
|
numberOfRecords: numberOfRecords,
|
||||||
value: null
|
value: null
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -39,6 +43,7 @@ checkFilterByMethod({
|
|||||||
methodQuery: 'request.method == "basic publish"',
|
methodQuery: 'request.method == "basic publish"',
|
||||||
summary: 'exchange',
|
summary: 'exchange',
|
||||||
summaryQuery: 'request.exchange == "exchange"',
|
summaryQuery: 'request.exchange == "exchange"',
|
||||||
|
numberOfRecords: numberOfRecords,
|
||||||
value: {tab: valueTabs.request, regex: /^message$/mg}
|
value: {tab: valueTabs.request, regex: /^message$/mg}
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -48,6 +53,7 @@ checkFilterByMethod({
|
|||||||
methodQuery: 'request.method == "basic consume"',
|
methodQuery: 'request.method == "basic consume"',
|
||||||
summary: 'queue',
|
summary: 'queue',
|
||||||
summaryQuery: 'request.queue == "queue"',
|
summaryQuery: 'request.queue == "queue"',
|
||||||
|
numberOfRecords: numberOfRecords,
|
||||||
value: null
|
value: null
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -57,5 +63,6 @@ checkFilterByMethod({
|
|||||||
methodQuery: 'request.method == "basic deliver"',
|
methodQuery: 'request.method == "basic deliver"',
|
||||||
summary: 'exchange',
|
summary: 'exchange',
|
||||||
summaryQuery: 'request.queue == "exchange"',
|
summaryQuery: 'request.queue == "exchange"',
|
||||||
|
numberOfRecords: numberOfRecords,
|
||||||
value: {tab: valueTabs.request, regex: /^message$/mg}
|
value: {tab: valueTabs.request, regex: /^message$/mg}
|
||||||
});
|
});
|
||||||
@@ -5,6 +5,7 @@ it('opening mizu', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const redisProtocolDetails = {name: 'redis', text: 'Redis Serialization Protocol'};
|
const redisProtocolDetails = {name: 'redis', text: 'Redis Serialization Protocol'};
|
||||||
|
const numberOfRecords = 5;
|
||||||
|
|
||||||
checkFilterByMethod({
|
checkFilterByMethod({
|
||||||
protocol: redisProtocolDetails,
|
protocol: redisProtocolDetails,
|
||||||
@@ -12,6 +13,7 @@ checkFilterByMethod({
|
|||||||
methodQuery: 'request.command == "PING"',
|
methodQuery: 'request.command == "PING"',
|
||||||
summary: null,
|
summary: null,
|
||||||
summaryQuery: '',
|
summaryQuery: '',
|
||||||
|
numberOfRecords: numberOfRecords,
|
||||||
value: null
|
value: null
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -21,6 +23,7 @@ checkFilterByMethod({
|
|||||||
methodQuery: 'request.command == "SET"',
|
methodQuery: 'request.command == "SET"',
|
||||||
summary: 'key',
|
summary: 'key',
|
||||||
summaryQuery: 'request.key == "key"',
|
summaryQuery: 'request.key == "key"',
|
||||||
|
numberOfRecords: numberOfRecords,
|
||||||
value: {tab: valueTabs.request, regex: /^\[value, keepttl]$/mg}
|
value: {tab: valueTabs.request, regex: /^\[value, keepttl]$/mg}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -30,6 +33,7 @@ checkFilterByMethod({
|
|||||||
methodQuery: 'request.command == "EXISTS"',
|
methodQuery: 'request.command == "EXISTS"',
|
||||||
summary: 'key',
|
summary: 'key',
|
||||||
summaryQuery: 'request.key == "key"',
|
summaryQuery: 'request.key == "key"',
|
||||||
|
numberOfRecords: numberOfRecords,
|
||||||
value: {tab: valueTabs.response, regex: /^1$/mg}
|
value: {tab: valueTabs.response, regex: /^1$/mg}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -39,6 +43,7 @@ checkFilterByMethod({
|
|||||||
methodQuery: 'request.command == "GET"',
|
methodQuery: 'request.command == "GET"',
|
||||||
summary: 'key',
|
summary: 'key',
|
||||||
summaryQuery: 'request.key == "key"',
|
summaryQuery: 'request.key == "key"',
|
||||||
|
numberOfRecords: numberOfRecords,
|
||||||
value: {tab: valueTabs.response, regex: /^value$/mg}
|
value: {tab: valueTabs.response, regex: /^value$/mg}
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -48,5 +53,6 @@ checkFilterByMethod({
|
|||||||
methodQuery: 'request.command == "DEL"',
|
methodQuery: 'request.command == "DEL"',
|
||||||
summary: 'key',
|
summary: 'key',
|
||||||
summaryQuery: 'request.key == "key"',
|
summaryQuery: 'request.key == "key"',
|
||||||
|
numberOfRecords: numberOfRecords,
|
||||||
value: {tab: valueTabs.response, regex: /^1$|^0$/mg}
|
value: {tab: valueTabs.response, regex: /^1$|^0$/mg}
|
||||||
})
|
})
|
||||||
@@ -7,12 +7,12 @@ import {
|
|||||||
resizeToNormalMizu,
|
resizeToNormalMizu,
|
||||||
rightOnHoverCheck,
|
rightOnHoverCheck,
|
||||||
rightTextCheck,
|
rightTextCheck,
|
||||||
verifyMinimumEntries
|
verifyMinimumEntries,
|
||||||
|
refreshWaitTimeout,
|
||||||
|
waitForFetch,
|
||||||
|
pauseStream
|
||||||
} from "../testHelpers/TrafficHelper";
|
} from "../testHelpers/TrafficHelper";
|
||||||
|
|
||||||
const refreshWaitTimeout = 10000;
|
|
||||||
|
|
||||||
|
|
||||||
const fullParam = Cypress.env('arrayDict'); // "Name:fooNamespace:barName:foo1Namespace:bar1"
|
const fullParam = Cypress.env('arrayDict'); // "Name:fooNamespace:barName:foo1Namespace:bar1"
|
||||||
const podsArray = fullParam.split('Name:').slice(1); // ["fooNamespace:bar", "foo1Namespace:bar1"]
|
const podsArray = fullParam.split('Name:').slice(1); // ["fooNamespace:bar", "foo1Namespace:bar1"]
|
||||||
podsArray.forEach((podStr, index) => {
|
podsArray.forEach((podStr, index) => {
|
||||||
@@ -65,70 +65,77 @@ it('right side sanity test', function () {
|
|||||||
checkIllegalFilter('invalid filter');
|
checkIllegalFilter('invalid filter');
|
||||||
|
|
||||||
checkFilter({
|
checkFilter({
|
||||||
name: 'http',
|
filter: 'http',
|
||||||
leftSidePath: '> :nth-child(1) > :nth-child(1)',
|
leftSidePath: '> :nth-child(1) > :nth-child(1)',
|
||||||
leftSideExpectedText: 'HTTP',
|
leftSideExpectedText: 'HTTP',
|
||||||
rightSidePath: '[title=HTTP]',
|
rightSidePath: '[title=HTTP]',
|
||||||
rightSideExpectedText: 'Hypertext Transfer Protocol -- HTTP/1.1',
|
rightSideExpectedText: 'Hypertext Transfer Protocol -- HTTP/1.1',
|
||||||
applyByEnter: true
|
applyByCtrlEnter: true,
|
||||||
|
numberOfRecords: 20,
|
||||||
});
|
});
|
||||||
|
|
||||||
checkFilter({
|
checkFilter({
|
||||||
name: 'response.status == 200',
|
filter: 'response.status == 200',
|
||||||
leftSidePath: '[title="Status Code"]',
|
leftSidePath: '[title="Status Code"]',
|
||||||
leftSideExpectedText: '200',
|
leftSideExpectedText: '200',
|
||||||
rightSidePath: '> :nth-child(2) [title="Status Code"]',
|
rightSidePath: '> :nth-child(2) [title="Status Code"]',
|
||||||
rightSideExpectedText: '200',
|
rightSideExpectedText: '200',
|
||||||
applyByEnter: false
|
applyByCtrlEnter: false,
|
||||||
|
numberOfRecords: 20
|
||||||
});
|
});
|
||||||
|
|
||||||
if (Cypress.env('shouldCheckSrcAndDest')) {
|
if (Cypress.env('shouldCheckSrcAndDest')) {
|
||||||
serviceMapCheck();
|
serviceMapCheck();
|
||||||
|
|
||||||
checkFilter({
|
checkFilter({
|
||||||
name: 'src.name == ""',
|
filter: 'src.name == ""',
|
||||||
leftSidePath: '[title="Source Name"]',
|
leftSidePath: '[title="Source Name"]',
|
||||||
leftSideExpectedText: '[Unresolved]',
|
leftSideExpectedText: '[Unresolved]',
|
||||||
rightSidePath: '> :nth-child(2) [title="Source Name"]',
|
rightSidePath: '> :nth-child(2) [title="Source Name"]',
|
||||||
rightSideExpectedText: '[Unresolved]',
|
rightSideExpectedText: '[Unresolved]',
|
||||||
applyByEnter: false
|
applyByCtrlEnter: false,
|
||||||
|
numberOfRecords: 20
|
||||||
});
|
});
|
||||||
|
|
||||||
checkFilter({
|
checkFilter({
|
||||||
name: `dst.name == "httpbin.mizu-tests"`,
|
filter: `dst.name == "httpbin.mizu-tests"`,
|
||||||
leftSidePath: '> :nth-child(3) > :nth-child(2) > :nth-child(3) > :nth-child(2)',
|
leftSidePath: '> :nth-child(3) > :nth-child(2) > :nth-child(3) > :nth-child(2)',
|
||||||
leftSideExpectedText: 'httpbin.mizu-tests',
|
leftSideExpectedText: 'httpbin.mizu-tests',
|
||||||
rightSidePath: '> :nth-child(2) > :nth-child(2) > :nth-child(2) > :nth-child(3) > :nth-child(2)',
|
rightSidePath: '> :nth-child(2) > :nth-child(2) > :nth-child(2) > :nth-child(3) > :nth-child(2)',
|
||||||
rightSideExpectedText: 'httpbin.mizu-tests',
|
rightSideExpectedText: 'httpbin.mizu-tests',
|
||||||
applyByEnter: false
|
applyByCtrlEnter: false,
|
||||||
|
numberOfRecords: 20
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
checkFilter({
|
checkFilter({
|
||||||
name: 'request.method == "GET"',
|
filter: 'request.method == "GET"',
|
||||||
leftSidePath: '> :nth-child(3) > :nth-child(1) > :nth-child(1) > :nth-child(2)',
|
leftSidePath: '> :nth-child(3) > :nth-child(1) > :nth-child(1) > :nth-child(2)',
|
||||||
leftSideExpectedText: 'GET',
|
leftSideExpectedText: 'GET',
|
||||||
rightSidePath: '> :nth-child(2) > :nth-child(2) > :nth-child(1) > :nth-child(1) > :nth-child(2)',
|
rightSidePath: '> :nth-child(2) > :nth-child(2) > :nth-child(1) > :nth-child(1) > :nth-child(2)',
|
||||||
rightSideExpectedText: 'GET',
|
rightSideExpectedText: 'GET',
|
||||||
applyByEnter: true
|
applyByCtrlEnter: true,
|
||||||
|
numberOfRecords: 20
|
||||||
});
|
});
|
||||||
|
|
||||||
checkFilter({
|
checkFilter({
|
||||||
name: 'request.path == "/get"',
|
filter: 'request.path == "/get"',
|
||||||
leftSidePath: '> :nth-child(3) > :nth-child(1) > :nth-child(2) > :nth-child(2)',
|
leftSidePath: '> :nth-child(3) > :nth-child(1) > :nth-child(2) > :nth-child(2)',
|
||||||
leftSideExpectedText: '/get',
|
leftSideExpectedText: '/get',
|
||||||
rightSidePath: '> :nth-child(2) > :nth-child(2) > :nth-child(1) > :nth-child(2) > :nth-child(2)',
|
rightSidePath: '> :nth-child(2) > :nth-child(2) > :nth-child(1) > :nth-child(2) > :nth-child(2)',
|
||||||
rightSideExpectedText: '/get',
|
rightSideExpectedText: '/get',
|
||||||
applyByEnter: false
|
applyByCtrlEnter: false,
|
||||||
|
numberOfRecords: 20
|
||||||
});
|
});
|
||||||
|
|
||||||
checkFilter({
|
checkFilter({
|
||||||
name: 'src.ip == "127.0.0.1"',
|
filter: 'src.ip == "127.0.0.1"',
|
||||||
leftSidePath: '[title="Source IP"]',
|
leftSidePath: '[title="Source IP"]',
|
||||||
leftSideExpectedText: '127.0.0.1',
|
leftSideExpectedText: '127.0.0.1',
|
||||||
rightSidePath: '> :nth-child(2) [title="Source IP"]',
|
rightSidePath: '> :nth-child(2) [title="Source IP"]',
|
||||||
rightSideExpectedText: '127.0.0.1',
|
rightSideExpectedText: '127.0.0.1',
|
||||||
applyByEnter: false
|
applyByCtrlEnter: false,
|
||||||
|
numberOfRecords: 20
|
||||||
});
|
});
|
||||||
|
|
||||||
checkFilterNoResults('request.method == "POST"');
|
checkFilterNoResults('request.method == "POST"');
|
||||||
@@ -182,67 +189,62 @@ function checkIllegalFilter(illegalFilterName) {
|
|||||||
|
|
||||||
function checkFilter(filterDetails) {
|
function checkFilter(filterDetails) {
|
||||||
const {
|
const {
|
||||||
name,
|
filter,
|
||||||
leftSidePath,
|
leftSidePath,
|
||||||
rightSidePath,
|
rightSidePath,
|
||||||
rightSideExpectedText,
|
rightSideExpectedText,
|
||||||
leftSideExpectedText,
|
leftSideExpectedText,
|
||||||
applyByEnter
|
applyByCtrlEnter,
|
||||||
|
numberOfRecords
|
||||||
} = filterDetails;
|
} = filterDetails;
|
||||||
|
|
||||||
const entriesForDeeperCheck = 5;
|
const entriesForDeeperCheck = 5;
|
||||||
|
|
||||||
it(`checking the filter: ${name}`, function () {
|
it(`checking the filter: ${filter}`, function () {
|
||||||
cy.get('#total-entries').should('not.have.text', '0').then(number => {
|
cy.get('.w-tc-editor-text').clear();
|
||||||
const totalEntries = number.text();
|
// applying the filter with alt+enter or with the button
|
||||||
|
cy.get('.w-tc-editor-text').type(`${filter}${applyByCtrlEnter ? '{ctrl+enter}' : ''}`);
|
||||||
|
cy.get('.w-tc-editor').should('have.attr', 'style').and('include', Cypress.env('greenFilterColor'));
|
||||||
|
if (!applyByCtrlEnter)
|
||||||
|
cy.get('[type="submit"]').click();
|
||||||
|
|
||||||
cy.get(`#list [id^=entry]`).last().then(elem => {
|
waitForFetch(numberOfRecords);
|
||||||
const element = elem[0];
|
pauseStream();
|
||||||
const entryId = getEntryId(element.id);
|
|
||||||
// checks the hover on the last entry (the only one in DOM at the beginning)
|
|
||||||
leftOnHoverCheck(entryId, leftSidePath, name);
|
|
||||||
|
|
||||||
cy.get('.w-tc-editor-text').clear();
|
cy.get(`#list [id^=entry]`).last().then(elem => {
|
||||||
// applying the filter with alt+enter or with the button
|
const element = elem[0];
|
||||||
cy.get('.w-tc-editor-text').type(`${name}${applyByEnter ? '{alt+enter}' : ''}`);
|
const entryId = getEntryId(element.id);
|
||||||
cy.get('.w-tc-editor').should('have.attr', 'style').and('include', Cypress.env('greenFilterColor'));
|
|
||||||
if (!applyByEnter)
|
|
||||||
cy.get('[type="submit"]').click();
|
|
||||||
|
|
||||||
// only one entry in DOM after filtering, checking all checks on it
|
// only one entry in DOM after filtering, checking all checks on it
|
||||||
leftTextCheck(entryId, leftSidePath, leftSideExpectedText);
|
leftTextCheck(entryId, leftSidePath, leftSideExpectedText);
|
||||||
leftOnHoverCheck(entryId, leftSidePath, name);
|
leftOnHoverCheck(entryId, leftSidePath, filter);
|
||||||
|
|
||||||
rightTextCheck(rightSidePath, rightSideExpectedText);
|
rightTextCheck(rightSidePath, rightSideExpectedText);
|
||||||
rightOnHoverCheck(rightSidePath, name);
|
rightOnHoverCheck(rightSidePath, filter);
|
||||||
checkRightSideResponseBody();
|
checkRightSideResponseBody();
|
||||||
});
|
});
|
||||||
|
|
||||||
cy.get('[title="Fetch old records"]').click();
|
resizeToHugeMizu();
|
||||||
resizeToHugeMizu();
|
|
||||||
|
|
||||||
// waiting for the entries number to load
|
// checking only 'leftTextCheck' on all entries because the rest of the checks require more time
|
||||||
cy.get('#entries-length', {timeout: refreshWaitTimeout}).should('have.text', totalEntries);
|
cy.get(`#list [id^=entry]`).each(elem => {
|
||||||
|
const element = elem[0];
|
||||||
|
let entryId = getEntryId(element.id);
|
||||||
|
leftTextCheck(entryId, leftSidePath, leftSideExpectedText);
|
||||||
|
});
|
||||||
|
|
||||||
// checking only 'leftTextCheck' on all entries because the rest of the checks require more time
|
// making the other 3 checks on the first X entries (longer time for each check)
|
||||||
cy.get(`#list [id^=entry]`).each(elem => {
|
deeperCheck(leftSidePath, rightSidePath, filter, rightSideExpectedText, entriesForDeeperCheck);
|
||||||
const element = elem[0];
|
|
||||||
let entryId = getEntryId(element.id);
|
|
||||||
leftTextCheck(entryId, leftSidePath, leftSideExpectedText);
|
|
||||||
});
|
|
||||||
|
|
||||||
// making the other 3 checks on the first X entries (longer time for each check)
|
// reloading then waiting for the entries number to load
|
||||||
deeperCheck(leftSidePath, rightSidePath, name, leftSideExpectedText, rightSideExpectedText, entriesForDeeperCheck);
|
resizeToNormalMizu();
|
||||||
|
cy.reload();
|
||||||
// reloading then waiting for the entries number to load
|
waitForFetch(numberOfRecords);
|
||||||
resizeToNormalMizu();
|
pauseStream();
|
||||||
cy.reload();
|
|
||||||
cy.get('#total-entries', {timeout: refreshWaitTimeout}).should('have.text', totalEntries);
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function deeperCheck(leftSidePath, rightSidePath, filterName, leftSideExpectedText, rightSideExpectedText, entriesNumToCheck) {
|
function deeperCheck(leftSidePath, rightSidePath, filterName, rightSideExpectedText, entriesNumToCheck) {
|
||||||
cy.get(`#list [id^=entry]`).each((element, index) => {
|
cy.get(`#list [id^=entry]`).each((element, index) => {
|
||||||
if (index < entriesNumToCheck) {
|
if (index < entriesNumToCheck) {
|
||||||
const entryId = getEntryId(element[0].id);
|
const entryId = getEntryId(element[0].id);
|
||||||
@@ -266,37 +268,35 @@ function checkRightSideResponseBody() {
|
|||||||
const decodedBody = atob(encodedBody);
|
const decodedBody = atob(encodedBody);
|
||||||
const responseBody = JSON.parse(decodedBody);
|
const responseBody = JSON.parse(decodedBody);
|
||||||
|
|
||||||
const expectdJsonBody = {
|
|
||||||
|
const expectedJsonBody = {
|
||||||
args: RegExp({}),
|
args: RegExp({}),
|
||||||
url: RegExp('http://.*/get'),
|
url: RegExp('http://.*/get'),
|
||||||
headers: {
|
headers: {
|
||||||
"User-Agent": RegExp('[REDACTED]'),
|
"User-Agent": RegExp('client'),
|
||||||
"Accept-Encoding": RegExp('gzip'),
|
"Accept-Encoding": RegExp('gzip'),
|
||||||
"X-Forwarded-Uri": RegExp('/api/v1/namespaces/.*/services/.*/proxy/get')
|
"X-Forwarded-Uri": RegExp('/api/v1/namespaces/.*/services/.*/proxy/get')
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
expect(responseBody.args).to.match(expectdJsonBody.args);
|
const expectedStringInJsonBody = RegExp('/api/v1/namespaces/.*/services/.*/proxy/get');
|
||||||
expect(responseBody.url).to.match(expectdJsonBody.url);
|
|
||||||
expect(responseBody.headers['User-Agent']).to.match(expectdJsonBody.headers['User-Agent']);
|
|
||||||
expect(responseBody.headers['Accept-Encoding']).to.match(expectdJsonBody.headers['Accept-Encoding']);
|
expect(responseBody.args).to.match(expectedJsonBody.args);
|
||||||
expect(responseBody.headers['X-Forwarded-Uri']).to.match(expectdJsonBody.headers['X-Forwarded-Uri']);
|
expect(responseBody.url).to.match(expectedJsonBody.url);
|
||||||
|
expect(responseBody.headers['User-Agent']).to.match(expectedJsonBody.headers['User-Agent']);
|
||||||
|
expect(responseBody.headers['Accept-Encoding']).to.match(expectedJsonBody.headers['Accept-Encoding']);
|
||||||
|
expect(responseBody.headers['X-Forwarded-Uri']).to.match(expectedJsonBody.headers['X-Forwarded-Uri']);
|
||||||
|
|
||||||
cy.get(`${Cypress.env('bodyJsonClass')}`).should('have.text', encodedBody);
|
cy.get(`${Cypress.env('bodyJsonClass')}`).should('have.text', encodedBody);
|
||||||
|
cy.get(`[data-cy="lineNumbersCheckBoxInput"]`).should('be.disabled');
|
||||||
|
|
||||||
clickCheckbox('Decode Base64');
|
clickCheckbox('Decode Base64');
|
||||||
|
cy.get(`[data-cy="lineNumbersCheckBoxInput"]`).should('not.be.disabled');
|
||||||
|
|
||||||
cy.get(`${Cypress.env('bodyJsonClass')} > `).its('length').should('be.gt', 1).then(linesNum => {
|
cy.get(`${Cypress.env('bodyJsonClass')} > `).its('length').should('be.gt', 1).then(linesNum => {
|
||||||
cy.get(`${Cypress.env('bodyJsonClass')} > >`).its('length').should('be.gt', linesNum).then(jsonItemsNum => {
|
cy.get(`${Cypress.env('bodyJsonClass')} > >`).its('length').should('be.gt', linesNum).then(jsonItemsNum => {
|
||||||
checkPrettyAndLineNums(jsonItemsNum, decodedBody);
|
checkOnlyLineNumberes(jsonItemsNum, expectedStringInJsonBody);
|
||||||
|
|
||||||
clickCheckbox('Line numbers');
|
|
||||||
checkPrettyOrNothing(jsonItemsNum, decodedBody);
|
|
||||||
|
|
||||||
clickCheckbox('Pretty');
|
|
||||||
checkPrettyOrNothing(jsonItemsNum, decodedBody);
|
|
||||||
|
|
||||||
clickCheckbox('Line numbers');
|
|
||||||
checkOnlyLineNumberes(jsonItemsNum, decodedBody);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -306,37 +306,9 @@ function clickCheckbox(type) {
|
|||||||
cy.contains(`${type}`).prev().children().click();
|
cy.contains(`${type}`).prev().children().click();
|
||||||
}
|
}
|
||||||
|
|
||||||
function checkPrettyAndLineNums(jsonItemsLen, decodedBody) {
|
|
||||||
decodedBody = decodedBody.replaceAll(' ', '');
|
|
||||||
cy.get(`${Cypress.env('bodyJsonClass')} >`).then(elements => {
|
|
||||||
const lines = Object.values(elements);
|
|
||||||
lines.forEach((line, index) => {
|
|
||||||
if (line.getAttribute) {
|
|
||||||
const cleanLine = getCleanLine(line);
|
|
||||||
const currentLineFromDecodedText = decodedBody.substring(0, cleanLine.length);
|
|
||||||
|
|
||||||
expect(cleanLine).to.equal(currentLineFromDecodedText, `expected the text in line number ${index + 1} to match the text that generated by the base64 decoding`)
|
|
||||||
|
|
||||||
decodedBody = decodedBody.substring(cleanLine.length);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCleanLine(lineElement) {
|
|
||||||
return (lineElement.innerText.substring(0, lineElement.innerText.length - 1)).replaceAll(' ', '');
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkPrettyOrNothing(jsonItems, decodedBody) {
|
|
||||||
cy.get(`${Cypress.env('bodyJsonClass')} > `).should('have.length', jsonItems).then(text => {
|
|
||||||
const json = text.text();
|
|
||||||
expect(json).to.equal(decodedBody);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function checkOnlyLineNumberes(jsonItems, decodedText) {
|
function checkOnlyLineNumberes(jsonItems, decodedText) {
|
||||||
cy.get(`${Cypress.env('bodyJsonClass')} >`).should('have.length', 1).and('have.text', decodedText);
|
cy.get(`${Cypress.env('bodyJsonClass')} > >`).should('have.length', jsonItems);
|
||||||
cy.get(`${Cypress.env('bodyJsonClass')} > >`).should('have.length', jsonItems)
|
cy.get(`${Cypress.env('bodyJsonClass')} >`).contains(decodedText);
|
||||||
}
|
}
|
||||||
|
|
||||||
function serviceMapCheck() {
|
function serviceMapCheck() {
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
import {
|
|
||||||
checkThatAllEntriesShown,
|
|
||||||
isValueExistsInElement,
|
|
||||||
resizeToHugeMizu,
|
|
||||||
} from "../testHelpers/TrafficHelper";
|
|
||||||
|
|
||||||
it('Loading Mizu', function () {
|
|
||||||
cy.visit(Cypress.env('testUrl'));
|
|
||||||
});
|
|
||||||
|
|
||||||
checkEntries();
|
|
||||||
|
|
||||||
function checkEntries() {
|
|
||||||
it('checking all entries', function () {
|
|
||||||
checkThatAllEntriesShown();
|
|
||||||
resizeToHugeMizu();
|
|
||||||
|
|
||||||
cy.get('#list [id^=entry]').each(entryElement => {
|
|
||||||
entryElement.click();
|
|
||||||
cy.get('#tbody-Headers').should('be.visible');
|
|
||||||
isValueExistsInElement(false, 'Ignored-User-Agent', '#tbody-Headers');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -105,10 +105,13 @@ func TestRedis(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RunCypressTests(t, "npx cypress run --spec \"cypress/integration/tests/Redis.js\"")
|
RunCypressTests(t, "npx cypress run --spec \"cypress/e2e/tests/Redis.js\"")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestAmqp(t *testing.T) {
|
func TestAmqp(t *testing.T) {
|
||||||
|
|
||||||
|
t.Skip("ignoredd for now because those tests are not stable")
|
||||||
|
|
||||||
if testing.Short() {
|
if testing.Short() {
|
||||||
t.Skip("ignored acceptance test")
|
t.Skip("ignored acceptance test")
|
||||||
}
|
}
|
||||||
@@ -236,5 +239,5 @@ func TestAmqp(t *testing.T) {
|
|||||||
ch.Close()
|
ch.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
RunCypressTests(t, "npx cypress run --spec \"cypress/integration/tests/Rabbit.js\"")
|
RunCypressTests(t, "npx cypress run --spec \"cypress/e2e/tests/Rabbit.js\"")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,3 +54,5 @@ replace github.com/up9inc/mizu/logger v0.0.0 => ../logger
|
|||||||
replace github.com/up9inc/mizu/shared v0.0.0 => ../shared
|
replace github.com/up9inc/mizu/shared v0.0.0 => ../shared
|
||||||
|
|
||||||
replace github.com/up9inc/mizu/tap/api v0.0.0 => ../tap/api
|
replace github.com/up9inc/mizu/tap/api v0.0.0 => ../tap/api
|
||||||
|
|
||||||
|
replace github.com/up9inc/mizu/tap/dbgctl v0.0.0 => ../tap/dbgctl
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
PREFIX=$HOME/local/bin
|
PREFIX=$HOME/local/bin
|
||||||
VERSION=v1.22.0
|
VERSION=v1.22.0
|
||||||
|
TUNNEL_LOG="tunnel.log"
|
||||||
|
PROXY_LOG="proxy.log"
|
||||||
|
|
||||||
echo "Attempting to install minikube and assorted tools to $PREFIX"
|
echo "Attempting to install minikube and assorted tools to $PREFIX"
|
||||||
|
|
||||||
@@ -11,7 +14,7 @@ if ! [ -x "$(command -v kubectl)" ]; then
|
|||||||
chmod +x kubectl
|
chmod +x kubectl
|
||||||
mv kubectl "$PREFIX"
|
mv kubectl "$PREFIX"
|
||||||
else
|
else
|
||||||
echo "kubetcl is already installed"
|
echo "kubectl is already installed"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! [ -x "$(command -v minikube)" ]; then
|
if ! [ -x "$(command -v minikube)" ]; then
|
||||||
@@ -24,38 +27,41 @@ else
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
echo "Starting minikube..."
|
echo "Starting minikube..."
|
||||||
minikube start
|
minikube start --cpus 2 --memory 6946
|
||||||
|
|
||||||
echo "Creating mizu tests namespaces"
|
echo "Creating mizu tests namespaces"
|
||||||
kubectl create namespace mizu-tests
|
kubectl create namespace mizu-tests --dry-run=client -o yaml | kubectl apply -f -
|
||||||
kubectl create namespace mizu-tests2
|
kubectl create namespace mizu-tests2 --dry-run=client -o yaml | kubectl apply -f -
|
||||||
|
|
||||||
echo "Creating httpbin deployments"
|
echo "Creating httpbin deployments"
|
||||||
kubectl create deployment httpbin --image=kennethreitz/httpbin -n mizu-tests
|
kubectl create deployment httpbin --image=kennethreitz/httpbin -n mizu-tests --dry-run=client -o yaml | kubectl apply -f -
|
||||||
kubectl create deployment httpbin2 --image=kennethreitz/httpbin -n mizu-tests
|
kubectl create deployment httpbin2 --image=kennethreitz/httpbin -n mizu-tests --dry-run=client -o yaml | kubectl apply -f -
|
||||||
|
|
||||||
kubectl create deployment httpbin --image=kennethreitz/httpbin -n mizu-tests2
|
kubectl create deployment httpbin --image=kennethreitz/httpbin -n mizu-tests2 --dry-run=client -o yaml | kubectl apply -f -
|
||||||
|
|
||||||
echo "Creating redis deployment"
|
echo "Creating redis deployment"
|
||||||
kubectl create deployment redis --image=redis -n mizu-tests
|
kubectl create deployment redis --image=redis -n mizu-tests --dry-run=client -o yaml | kubectl apply -f -
|
||||||
|
|
||||||
echo "Creating rabbitmq deployment"
|
echo "Creating rabbitmq deployment"
|
||||||
kubectl create deployment rabbitmq --image=rabbitmq -n mizu-tests
|
kubectl create deployment rabbitmq --image=rabbitmq -n mizu-tests --dry-run=client -o yaml | kubectl apply -f -
|
||||||
|
|
||||||
echo "Creating httpbin services"
|
echo "Creating httpbin services"
|
||||||
kubectl expose deployment httpbin --type=NodePort --port=80 -n mizu-tests
|
kubectl expose deployment httpbin --type=NodePort --port=80 -n mizu-tests --dry-run=client -o yaml | kubectl apply -f -
|
||||||
kubectl expose deployment httpbin2 --type=NodePort --port=80 -n mizu-tests
|
kubectl expose deployment httpbin2 --type=NodePort --port=80 -n mizu-tests --dry-run=client -o yaml | kubectl apply -f -
|
||||||
|
|
||||||
kubectl expose deployment httpbin --type=NodePort --port=80 -n mizu-tests2
|
kubectl expose deployment httpbin --type=NodePort --port=80 -n mizu-tests2 --dry-run=client -o yaml | kubectl apply -f -
|
||||||
|
|
||||||
echo "Creating redis service"
|
echo "Creating redis service"
|
||||||
kubectl expose deployment redis --type=LoadBalancer --port=6379 -n mizu-tests
|
kubectl expose deployment redis --type=LoadBalancer --port=6379 -n mizu-tests --dry-run=client -o yaml | kubectl apply -f -
|
||||||
|
|
||||||
echo "Creating rabbitmq service"
|
echo "Creating rabbitmq service"
|
||||||
kubectl expose deployment rabbitmq --type=LoadBalancer --port=5672 -n mizu-tests
|
kubectl expose deployment rabbitmq --type=LoadBalancer --port=5672 -n mizu-tests --dry-run=client -o yaml | kubectl apply -f -
|
||||||
|
|
||||||
echo "Starting proxy"
|
echo "Starting proxy"
|
||||||
kubectl proxy --port=8080 &
|
rm -f ${PROXY_LOG}
|
||||||
|
kubectl proxy --port=8080 > ${PROXY_LOG} &
|
||||||
|
PID1=$!
|
||||||
|
echo "kubectl proxy process id is ${PID1} and log of proxy in ${PROXY_LOG}"
|
||||||
|
|
||||||
if [[ -z "${CI}" ]]; then
|
if [[ -z "${CI}" ]]; then
|
||||||
echo "Setting env var of mizu ci image"
|
echo "Setting env var of mizu ci image"
|
||||||
@@ -72,4 +78,7 @@ echo "Build cli"
|
|||||||
cd cli && make build GIT_BRANCH=ci SUFFIX=ci
|
cd cli && make build GIT_BRANCH=ci SUFFIX=ci
|
||||||
|
|
||||||
echo "Starting tunnel"
|
echo "Starting tunnel"
|
||||||
minikube tunnel &
|
rm -f ${TUNNEL_LOG}
|
||||||
|
minikube tunnel > ${TUNNEL_LOG} &
|
||||||
|
PID2=$!
|
||||||
|
echo "Minikube tunnel process id is ${PID2} and log of tunnel in ${TUNNEL_LOG}"
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ func basicTapTest(t *testing.T, shouldCheckSrcAndDest bool, extraArgs... string)
|
|||||||
expectedPodsStr += fmt.Sprintf("Name:%vNamespace:%v", expectedPods[i].Name, expectedPods[i].Namespace)
|
expectedPodsStr += fmt.Sprintf("Name:%vNamespace:%v", expectedPods[i].Name, expectedPods[i].Namespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
RunCypressTests(t, fmt.Sprintf("npx cypress run --spec \"cypress/integration/tests/UiTest.js\" --env entriesCount=%d,arrayDict=%v,shouldCheckSrcAndDest=%v",
|
RunCypressTests(t, fmt.Sprintf("npx cypress run --spec \"cypress/e2e/tests/UiTest.js\" --env entriesCount=%d,arrayDict=%v,shouldCheckSrcAndDest=%v",
|
||||||
entriesCount, expectedPodsStr, shouldCheckSrcAndDest))
|
entriesCount, expectedPodsStr, shouldCheckSrcAndDest))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -135,7 +135,7 @@ func TestTapGuiPort(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RunCypressTests(t, fmt.Sprintf("npx cypress run --spec \"cypress/integration/tests/GuiPort.js\" --env name=%v,namespace=%v,port=%d",
|
RunCypressTests(t, fmt.Sprintf("npx cypress run --spec \"cypress/e2e/tests/GuiPort.js\" --env name=%v,namespace=%v,port=%d",
|
||||||
"httpbin", "mizu-tests", guiPort))
|
"httpbin", "mizu-tests", guiPort))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -182,7 +182,7 @@ func TestTapAllNamespaces(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
RunCypressTests(t, fmt.Sprintf("npx cypress run --spec \"cypress/integration/tests/MultipleNamespaces.js\" --env name1=%v,name2=%v,name3=%v,namespace1=%v,namespace2=%v,namespace3=%v",
|
RunCypressTests(t, fmt.Sprintf("npx cypress run --spec \"cypress/e2e/tests/MultipleNamespaces.js\" --env name1=%v,name2=%v,name3=%v,namespace1=%v,namespace2=%v,namespace3=%v",
|
||||||
expectedPods[0].Name, expectedPods[1].Name, expectedPods[2].Name, expectedPods[0].Namespace, expectedPods[1].Namespace, expectedPods[2].Namespace))
|
expectedPods[0].Name, expectedPods[1].Name, expectedPods[2].Name, expectedPods[0].Namespace, expectedPods[1].Namespace, expectedPods[2].Namespace))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -231,7 +231,7 @@ func TestTapMultipleNamespaces(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
RunCypressTests(t, fmt.Sprintf("npx cypress run --spec \"cypress/integration/tests/MultipleNamespaces.js\" --env name1=%v,name2=%v,name3=%v,namespace1=%v,namespace2=%v,namespace3=%v",
|
RunCypressTests(t, fmt.Sprintf("npx cypress run --spec \"cypress/e2e/tests/MultipleNamespaces.js\" --env name1=%v,name2=%v,name3=%v,namespace1=%v,namespace2=%v,namespace3=%v",
|
||||||
expectedPods[0].Name, expectedPods[1].Name, expectedPods[2].Name, expectedPods[0].Namespace, expectedPods[1].Namespace, expectedPods[2].Namespace))
|
expectedPods[0].Name, expectedPods[1].Name, expectedPods[2].Name, expectedPods[0].Namespace, expectedPods[1].Namespace, expectedPods[2].Namespace))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -277,7 +277,7 @@ func TestTapRegex(t *testing.T) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
RunCypressTests(t, fmt.Sprintf("npx cypress run --spec \"cypress/integration/tests/Regex.js\" --env name=%v,namespace=%v",
|
RunCypressTests(t, fmt.Sprintf("npx cypress run --spec \"cypress/e2e/tests/Regex.js\" --env name=%v,namespace=%v",
|
||||||
expectedPods[0].Name, expectedPods[0].Namespace))
|
expectedPods[0].Name, expectedPods[0].Namespace))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -343,6 +343,7 @@ func TestTapRedact(t *testing.T) {
|
|||||||
|
|
||||||
tapNamespace := GetDefaultTapNamespace()
|
tapNamespace := GetDefaultTapNamespace()
|
||||||
tapCmdArgs = append(tapCmdArgs, tapNamespace...)
|
tapCmdArgs = append(tapCmdArgs, tapNamespace...)
|
||||||
|
tapCmdArgs = append(tapCmdArgs, "--redact")
|
||||||
|
|
||||||
tapCmd := exec.Command(cliPath, tapCmdArgs...)
|
tapCmd := exec.Command(cliPath, tapCmdArgs...)
|
||||||
t.Logf("running command: %v", tapCmd.String())
|
t.Logf("running command: %v", tapCmd.String())
|
||||||
@@ -375,7 +376,7 @@ func TestTapRedact(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RunCypressTests(t, "npx cypress run --spec \"cypress/integration/tests/Redact.js\"")
|
RunCypressTests(t, "npx cypress run --spec \"cypress/e2e/tests/Redact.js\"")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTapNoRedact(t *testing.T) {
|
func TestTapNoRedact(t *testing.T) {
|
||||||
@@ -394,8 +395,6 @@ func TestTapNoRedact(t *testing.T) {
|
|||||||
tapNamespace := GetDefaultTapNamespace()
|
tapNamespace := GetDefaultTapNamespace()
|
||||||
tapCmdArgs = append(tapCmdArgs, tapNamespace...)
|
tapCmdArgs = append(tapCmdArgs, tapNamespace...)
|
||||||
|
|
||||||
tapCmdArgs = append(tapCmdArgs, "--no-redact")
|
|
||||||
|
|
||||||
tapCmd := exec.Command(cliPath, tapCmdArgs...)
|
tapCmd := exec.Command(cliPath, tapCmdArgs...)
|
||||||
t.Logf("running command: %v", tapCmd.String())
|
t.Logf("running command: %v", tapCmd.String())
|
||||||
|
|
||||||
@@ -427,7 +426,7 @@ func TestTapNoRedact(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RunCypressTests(t, "npx cypress run --spec \"cypress/integration/tests/NoRedact.js\"")
|
RunCypressTests(t, "npx cypress run --spec \"cypress/e2e/tests/NoRedact.js\"")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTapRegexMasking(t *testing.T) {
|
func TestTapRegexMasking(t *testing.T) {
|
||||||
@@ -446,6 +445,8 @@ func TestTapRegexMasking(t *testing.T) {
|
|||||||
tapNamespace := GetDefaultTapNamespace()
|
tapNamespace := GetDefaultTapNamespace()
|
||||||
tapCmdArgs = append(tapCmdArgs, tapNamespace...)
|
tapCmdArgs = append(tapCmdArgs, tapNamespace...)
|
||||||
|
|
||||||
|
tapCmdArgs = append(tapCmdArgs, "--redact")
|
||||||
|
|
||||||
tapCmdArgs = append(tapCmdArgs, "-r", "Mizu")
|
tapCmdArgs = append(tapCmdArgs, "-r", "Mizu")
|
||||||
|
|
||||||
tapCmd := exec.Command(cliPath, tapCmdArgs...)
|
tapCmd := exec.Command(cliPath, tapCmdArgs...)
|
||||||
@@ -478,7 +479,7 @@ func TestTapRegexMasking(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RunCypressTests(t, "npx cypress run --spec \"cypress/integration/tests/RegexMasking.js\"")
|
RunCypressTests(t, "npx cypress run --spec \"cypress/e2e/tests/RegexMasking.js\"")
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -540,7 +541,7 @@ func TestTapIgnoredUserAgents(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
RunCypressTests(t, "npx cypress run --spec \"cypress/integration/tests/IgnoredUserAgents.js\"")
|
RunCypressTests(t, "npx cypress run --spec \"cypress/e2e/tests/IgnoredUserAgents.js\"")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestTapDumpLogs(t *testing.T) {
|
func TestTapDumpLogs(t *testing.T) {
|
||||||
|
|||||||
@@ -6,10 +6,6 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
"k8s.io/client-go/kubernetes"
|
|
||||||
"k8s.io/client-go/tools/clientcmd"
|
|
||||||
"k8s.io/client-go/util/homedir"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@@ -20,6 +16,11 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/client-go/kubernetes"
|
||||||
|
"k8s.io/client-go/tools/clientcmd"
|
||||||
|
"k8s.io/client-go/util/homedir"
|
||||||
|
|
||||||
"github.com/up9inc/mizu/shared"
|
"github.com/up9inc/mizu/shared"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -175,7 +176,7 @@ func ApplyKubeFilesForTest(t *testing.T, kubeContext string, namespace string, f
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ApplyKubeFile(kubeContext string, namespace string, filename string) (error) {
|
func ApplyKubeFile(kubeContext string, namespace string, filename string) error {
|
||||||
cmdArgs := []string{
|
cmdArgs := []string{
|
||||||
"apply",
|
"apply",
|
||||||
"--context", kubeContext,
|
"--context", kubeContext,
|
||||||
|
|||||||
23
agent/go.mod
23
agent/go.mod
@@ -6,8 +6,7 @@ require (
|
|||||||
github.com/antelman107/net-wait-go v0.0.0-20210623112055-cf684aebda7b
|
github.com/antelman107/net-wait-go v0.0.0-20210623112055-cf684aebda7b
|
||||||
github.com/chanced/openapi v0.0.8
|
github.com/chanced/openapi v0.0.8
|
||||||
github.com/djherbis/atime v1.1.0
|
github.com/djherbis/atime v1.1.0
|
||||||
github.com/elastic/go-elasticsearch/v7 v7.17.0
|
github.com/gin-contrib/pprof v1.3.0
|
||||||
github.com/getkin/kin-openapi v0.89.0
|
|
||||||
github.com/gin-contrib/static v0.0.1
|
github.com/gin-contrib/static v0.0.1
|
||||||
github.com/gin-gonic/gin v1.7.7
|
github.com/gin-gonic/gin v1.7.7
|
||||||
github.com/go-playground/locales v0.14.0
|
github.com/go-playground/locales v0.14.0
|
||||||
@@ -20,17 +19,17 @@ require (
|
|||||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
|
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
|
||||||
github.com/orcaman/concurrent-map v1.0.0
|
github.com/orcaman/concurrent-map v1.0.0
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
github.com/up9inc/basenine/client/go v0.0.0-20220419100955-e2ca51087607
|
github.com/up9inc/basenine/client/go v0.0.0-20220612112747-3b28eeac9c51
|
||||||
github.com/up9inc/mizu/logger v0.0.0
|
github.com/up9inc/mizu/logger v0.0.0
|
||||||
github.com/up9inc/mizu/shared v0.0.0
|
github.com/up9inc/mizu/shared v0.0.0
|
||||||
github.com/up9inc/mizu/tap v0.0.0
|
github.com/up9inc/mizu/tap v0.0.0
|
||||||
github.com/up9inc/mizu/tap/api v0.0.0
|
github.com/up9inc/mizu/tap/api v0.0.0
|
||||||
|
github.com/up9inc/mizu/tap/dbgctl v0.0.0
|
||||||
github.com/up9inc/mizu/tap/extensions/amqp v0.0.0
|
github.com/up9inc/mizu/tap/extensions/amqp v0.0.0
|
||||||
github.com/up9inc/mizu/tap/extensions/http v0.0.0
|
github.com/up9inc/mizu/tap/extensions/http v0.0.0
|
||||||
github.com/up9inc/mizu/tap/extensions/kafka v0.0.0
|
github.com/up9inc/mizu/tap/extensions/kafka v0.0.0
|
||||||
github.com/up9inc/mizu/tap/extensions/redis v0.0.0
|
github.com/up9inc/mizu/tap/extensions/redis v0.0.0
|
||||||
github.com/wI2L/jsondiff v0.1.1
|
github.com/wI2L/jsondiff v0.1.1
|
||||||
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0
|
|
||||||
k8s.io/api v0.23.3
|
k8s.io/api v0.23.3
|
||||||
k8s.io/apimachinery v0.23.3
|
k8s.io/apimachinery v0.23.3
|
||||||
k8s.io/client-go v0.23.3
|
k8s.io/client-go v0.23.3
|
||||||
@@ -46,21 +45,22 @@ require (
|
|||||||
github.com/Azure/go-autorest/logger v0.2.1 // indirect
|
github.com/Azure/go-autorest/logger v0.2.1 // indirect
|
||||||
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
github.com/Azure/go-autorest/tracing v0.6.0 // indirect
|
||||||
github.com/MakeNowJust/heredoc v1.0.0 // indirect
|
github.com/MakeNowJust/heredoc v1.0.0 // indirect
|
||||||
|
github.com/Masterminds/semver v1.5.0 // indirect
|
||||||
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
github.com/PuerkitoBio/purell v1.1.1 // indirect
|
||||||
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
|
||||||
github.com/beevik/etree v1.1.0 // indirect
|
github.com/beevik/etree v1.1.0 // indirect
|
||||||
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect
|
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect
|
||||||
github.com/chanced/dynamic v0.0.0-20211210164248-f8fadb1d735b // indirect
|
github.com/chanced/dynamic v0.0.0-20211210164248-f8fadb1d735b // indirect
|
||||||
github.com/cilium/ebpf v0.8.0 // indirect
|
github.com/cilium/ebpf v0.9.0 // indirect
|
||||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
|
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
|
||||||
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
|
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
|
||||||
github.com/fatih/camelcase v1.0.0 // indirect
|
github.com/fatih/camelcase v1.0.0 // indirect
|
||||||
github.com/fvbommel/sortorder v1.0.2 // indirect
|
github.com/fvbommel/sortorder v1.0.2 // indirect
|
||||||
github.com/ghodss/yaml v1.0.0 // indirect
|
|
||||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||||
github.com/go-errors/errors v1.4.2 // indirect
|
github.com/go-errors/errors v1.4.2 // indirect
|
||||||
github.com/go-logr/logr v1.2.2 // indirect
|
github.com/go-logr/logr v1.2.2 // indirect
|
||||||
|
github.com/go-ole/go-ole v1.2.6 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||||
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
github.com/go-openapi/jsonreference v0.19.6 // indirect
|
||||||
github.com/go-openapi/swag v0.21.1 // indirect
|
github.com/go-openapi/swag v0.21.1 // indirect
|
||||||
@@ -76,17 +76,20 @@ require (
|
|||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||||
github.com/googleapis/gnostic v0.5.5 // indirect
|
github.com/googleapis/gnostic v0.5.5 // indirect
|
||||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
|
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
|
||||||
|
github.com/hashicorp/golang-lru v0.5.4 // indirect
|
||||||
github.com/imdario/mergo v0.3.12 // indirect
|
github.com/imdario/mergo v0.3.12 // indirect
|
||||||
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||||
github.com/josharian/intern v1.0.0 // indirect
|
github.com/josharian/intern v1.0.0 // indirect
|
||||||
github.com/json-iterator/go v1.1.12 // indirect
|
github.com/json-iterator/go v1.1.12 // indirect
|
||||||
github.com/klauspost/compress v1.14.2 // indirect
|
github.com/klauspost/compress v1.14.2 // indirect
|
||||||
|
github.com/knightsc/gapstone v0.0.0-20191231144527-6fa5afaf11a9 // indirect
|
||||||
github.com/leodido/go-urn v1.2.1 // indirect
|
github.com/leodido/go-urn v1.2.1 // indirect
|
||||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
|
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
|
||||||
github.com/mailru/easyjson v0.7.7 // indirect
|
github.com/mailru/easyjson v0.7.7 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||||
github.com/mertyildiran/gqlparser/v2 v2.4.6 // indirect
|
github.com/mertyildiran/gqlparser/v2 v2.4.6 // indirect
|
||||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||||
|
github.com/moby/moby v20.10.17+incompatible // indirect
|
||||||
github.com/moby/spdystream v0.2.0 // indirect
|
github.com/moby/spdystream v0.2.0 // indirect
|
||||||
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
|
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
@@ -101,15 +104,21 @@ require (
|
|||||||
github.com/russross/blackfriday v1.6.0 // indirect
|
github.com/russross/blackfriday v1.6.0 // indirect
|
||||||
github.com/santhosh-tekuri/jsonschema/v5 v5.0.0 // indirect
|
github.com/santhosh-tekuri/jsonschema/v5 v5.0.0 // indirect
|
||||||
github.com/segmentio/kafka-go v0.4.27 // indirect
|
github.com/segmentio/kafka-go v0.4.27 // indirect
|
||||||
|
github.com/shirou/gopsutil v3.21.11+incompatible // indirect
|
||||||
|
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||||
github.com/spf13/cobra v1.3.0 // indirect
|
github.com/spf13/cobra v1.3.0 // indirect
|
||||||
github.com/spf13/pflag v1.0.5 // indirect
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
github.com/struCoder/pidusage v0.2.1 // indirect
|
||||||
github.com/tidwall/gjson v1.14.0 // indirect
|
github.com/tidwall/gjson v1.14.0 // indirect
|
||||||
github.com/tidwall/match v1.1.1 // indirect
|
github.com/tidwall/match v1.1.1 // indirect
|
||||||
github.com/tidwall/pretty v1.2.0 // indirect
|
github.com/tidwall/pretty v1.2.0 // indirect
|
||||||
github.com/tidwall/sjson v1.2.4 // indirect
|
github.com/tidwall/sjson v1.2.4 // indirect
|
||||||
|
github.com/tklauser/go-sysconf v0.3.10 // indirect
|
||||||
|
github.com/tklauser/numcpus v0.4.0 // indirect
|
||||||
github.com/ugorji/go/codec v1.2.6 // indirect
|
github.com/ugorji/go/codec v1.2.6 // indirect
|
||||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
|
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 // indirect
|
||||||
github.com/xlab/treeprint v1.1.0 // indirect
|
github.com/xlab/treeprint v1.1.0 // indirect
|
||||||
|
github.com/yusufpapurcu/wmi v1.2.2 // indirect
|
||||||
go.starlark.net v0.0.0-20220203230714-bb14e151c28f // indirect
|
go.starlark.net v0.0.0-20220203230714-bb14e151c28f // indirect
|
||||||
golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b // indirect
|
golang.org/x/crypto v0.0.0-20220314234659-1baeb1ce4c0b // indirect
|
||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
|
||||||
@@ -151,3 +160,5 @@ replace github.com/up9inc/mizu/tap/extensions/http v0.0.0 => ../tap/extensions/h
|
|||||||
replace github.com/up9inc/mizu/tap/extensions/kafka v0.0.0 => ../tap/extensions/kafka
|
replace github.com/up9inc/mizu/tap/extensions/kafka v0.0.0 => ../tap/extensions/kafka
|
||||||
|
|
||||||
replace github.com/up9inc/mizu/tap/extensions/redis v0.0.0 => ../tap/extensions/redis
|
replace github.com/up9inc/mizu/tap/extensions/redis v0.0.0 => ../tap/extensions/redis
|
||||||
|
|
||||||
|
replace github.com/up9inc/mizu/tap/dbgctl v0.0.0 => ../tap/dbgctl
|
||||||
|
|||||||
45
agent/go.sum
45
agent/go.sum
@@ -77,6 +77,8 @@ github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3
|
|||||||
github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E=
|
github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E=
|
||||||
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
|
github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ=
|
||||||
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
|
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
|
||||||
|
github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww=
|
||||||
|
github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
||||||
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
|
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 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
|
||||||
@@ -126,8 +128,8 @@ github.com/chanced/openapi v0.0.8/go.mod h1:SxE2VMLPw+T7Vq8nwbVVhDF2PigvRF4n5Xyq
|
|||||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
||||||
github.com/cilium/ebpf v0.8.0 h1:2V6KSg3FRADVU2BMIRemZ0hV+9OM+aAHhZDjQyjJTAs=
|
github.com/cilium/ebpf v0.9.0 h1:ldiV+FscPCQ/p3mNEV4O02EPbUZJFsoEtHvIr9xLTvk=
|
||||||
github.com/cilium/ebpf v0.8.0/go.mod h1:f5zLIM0FSNuAkSyLAN7X+Hy6yznlF1mNiWUMfxMtrgk=
|
github.com/cilium/ebpf v0.9.0/go.mod h1:+OhNOIXx/Fnu1IE8bJz2dzOA+VSfyTfdNUVdlQnxUFY=
|
||||||
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
|
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
|
||||||
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
|
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
||||||
@@ -166,8 +168,6 @@ github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD
|
|||||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
||||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw=
|
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8/yCZMuEPMUDHG0CW/brkkEp8mzqk2+ODEitlw=
|
||||||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU=
|
||||||
github.com/elastic/go-elasticsearch/v7 v7.17.0 h1:0fcSh4qeC/i1+7QU1KXpmq2iUAdMk4l0/vmbtW1+KJM=
|
|
||||||
github.com/elastic/go-elasticsearch/v7 v7.17.0/go.mod h1:OJ4wdbtDNk5g503kvlHLyErCgQwwzmDtaFC4XyOxXA4=
|
|
||||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
|
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
|
||||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
||||||
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||||
@@ -211,14 +211,14 @@ github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui72
|
|||||||
github.com/fvbommel/sortorder v1.0.2 h1:mV4o8B2hKboCdkJm+a7uX/SIpZob4JzUpc5GGnM45eo=
|
github.com/fvbommel/sortorder v1.0.2 h1:mV4o8B2hKboCdkJm+a7uX/SIpZob4JzUpc5GGnM45eo=
|
||||||
github.com/fvbommel/sortorder v1.0.2/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
|
github.com/fvbommel/sortorder v1.0.2/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
|
||||||
github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
|
github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
|
||||||
github.com/getkin/kin-openapi v0.89.0 h1:p4nagHchUKGn85z/f+pse4aSh50nIBOYjOhMIku2hiA=
|
|
||||||
github.com/getkin/kin-openapi v0.89.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
|
|
||||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
|
github.com/gin-contrib/pprof v1.3.0 h1:G9eK6HnbkSqDZBYbzG4wrjCsA4e+cvYAHUZw6W+W9K0=
|
||||||
|
github.com/gin-contrib/pprof v1.3.0/go.mod h1:waMjT1H9b179t3CxuG1cV3DHpga6ybizwfBaM5OXaB0=
|
||||||
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
|
||||||
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
|
||||||
github.com/gin-contrib/static v0.0.1 h1:JVxuvHPuUfkoul12N7dtQw7KRn/pSMq7Ue1Va9Swm1U=
|
github.com/gin-contrib/static v0.0.1 h1:JVxuvHPuUfkoul12N7dtQw7KRn/pSMq7Ue1Va9Swm1U=
|
||||||
github.com/gin-contrib/static v0.0.1/go.mod h1:CSxeF+wep05e0kCOsqWdAWbSszmc31zTIbD8TvWl7Hs=
|
github.com/gin-contrib/static v0.0.1/go.mod h1:CSxeF+wep05e0kCOsqWdAWbSszmc31zTIbD8TvWl7Hs=
|
||||||
|
github.com/gin-gonic/gin v1.6.2/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||||
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
|
||||||
github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs=
|
github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs=
|
||||||
github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
|
github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
|
||||||
@@ -240,6 +240,8 @@ github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbV
|
|||||||
github.com/go-logr/logr v1.2.2 h1:ahHml/yUpnlb96Rp8HCvtYVPY8ZYpxq3g7UYchIYwbs=
|
github.com/go-logr/logr v1.2.2 h1:ahHml/yUpnlb96Rp8HCvtYVPY8ZYpxq3g7UYchIYwbs=
|
||||||
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
github.com/go-logr/zapr v1.2.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQf7Ro=
|
github.com/go-logr/zapr v1.2.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQf7Ro=
|
||||||
|
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
|
||||||
|
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
|
||||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
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 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY=
|
||||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||||
@@ -368,7 +370,6 @@ github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2c
|
|||||||
github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw=
|
github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw=
|
||||||
github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
|
github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
|
||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
|
||||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||||
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
|
||||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
||||||
@@ -405,6 +406,7 @@ github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/b
|
|||||||
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90=
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
||||||
|
github.com/hashicorp/golang-lru v0.5.4 h1:YDjusn29QI/Das2iO9M0BHnIbxPeyuCHsjMW+lJfyTc=
|
||||||
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
github.com/hashicorp/golang-lru v0.5.4/go.mod h1:iADmTwqILo4mZ8BN3D2Q6+9jd8WM5uGBxy+E8yxSoD4=
|
||||||
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ=
|
||||||
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64=
|
||||||
@@ -451,6 +453,8 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
|
|||||||
github.com/klauspost/compress v1.9.8/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
github.com/klauspost/compress v1.9.8/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
|
||||||
github.com/klauspost/compress v1.14.2 h1:S0OHlFk/Gbon/yauFJ4FfJJF5V0fc5HbBTJazi28pRw=
|
github.com/klauspost/compress v1.14.2 h1:S0OHlFk/Gbon/yauFJ4FfJJF5V0fc5HbBTJazi28pRw=
|
||||||
github.com/klauspost/compress v1.14.2/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
github.com/klauspost/compress v1.14.2/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
|
||||||
|
github.com/knightsc/gapstone v0.0.0-20191231144527-6fa5afaf11a9 h1:1KszOoXSFt0aRQ6wxxcKm7QKgfLPI0TWO47UcY/f+vA=
|
||||||
|
github.com/knightsc/gapstone v0.0.0-20191231144527-6fa5afaf11a9/go.mod h1:1K5hEzsMBLTPdRJKEHqBFJ8Zt2VRqDhomcQ11KH0WW4=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
|
||||||
@@ -513,6 +517,8 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F
|
|||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
||||||
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
|
||||||
|
github.com/moby/moby v20.10.17+incompatible h1:TJJfyk2fLEgK+RzqVpFNkDkm0oEi+MLUfwt9lEYnp5g=
|
||||||
|
github.com/moby/moby v20.10.17+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc=
|
||||||
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
|
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
|
||||||
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
||||||
github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A=
|
github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A=
|
||||||
@@ -619,10 +625,14 @@ github.com/segmentio/kafka-go v0.4.27 h1:sIhEozeL/TLN2mZ5dkG462vcGEWYKS+u31sXPjK
|
|||||||
github.com/segmentio/kafka-go v0.4.27/go.mod h1:XzMcoMjSzDGHcIwpWUI7GB43iKZ2fTVmryPSGLf/MPg=
|
github.com/segmentio/kafka-go v0.4.27/go.mod h1:XzMcoMjSzDGHcIwpWUI7GB43iKZ2fTVmryPSGLf/MPg=
|
||||||
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0=
|
||||||
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||||
|
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
|
||||||
|
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
|
||||||
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
|
||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||||
|
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||||
|
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
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/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
@@ -660,6 +670,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5
|
|||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/struCoder/pidusage v0.2.1 h1:dFiEgUDkubeIj0XA1NpQ6+8LQmKrLi7NiIQl86E6BoY=
|
||||||
|
github.com/struCoder/pidusage v0.2.1/go.mod h1:bewtP2KUA1TBUyza5+/PCpSQ6sc/H6jJbIKAzqW86BA=
|
||||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
github.com/tidwall/gjson v1.10.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
github.com/tidwall/gjson v1.10.2/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||||
github.com/tidwall/gjson v1.12.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
github.com/tidwall/gjson v1.12.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
|
||||||
@@ -673,6 +685,10 @@ github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhso
|
|||||||
github.com/tidwall/sjson v1.2.3/go.mod h1:5WdjKx3AQMvCJ4RG6/2UYT7dLrGvJUV1x4jdTAyGvZs=
|
github.com/tidwall/sjson v1.2.3/go.mod h1:5WdjKx3AQMvCJ4RG6/2UYT7dLrGvJUV1x4jdTAyGvZs=
|
||||||
github.com/tidwall/sjson v1.2.4 h1:cuiLzLnaMeBhRmEv00Lpk3tkYrcxpmbU81tAY4Dw0tc=
|
github.com/tidwall/sjson v1.2.4 h1:cuiLzLnaMeBhRmEv00Lpk3tkYrcxpmbU81tAY4Dw0tc=
|
||||||
github.com/tidwall/sjson v1.2.4/go.mod h1:098SZ494YoMWPmMO6ct4dcFnqxwj9r/gF0Etp19pSNM=
|
github.com/tidwall/sjson v1.2.4/go.mod h1:098SZ494YoMWPmMO6ct4dcFnqxwj9r/gF0Etp19pSNM=
|
||||||
|
github.com/tklauser/go-sysconf v0.3.10 h1:IJ1AZGZRWbY8T5Vfk04D9WOA5WSejdflXxP03OUqALw=
|
||||||
|
github.com/tklauser/go-sysconf v0.3.10/go.mod h1:C8XykCvCb+Gn0oNCWPIlcb0RuglQTYaQ2hGm7jmxEFk=
|
||||||
|
github.com/tklauser/numcpus v0.4.0 h1:E53Dm1HjH1/R2/aoCtXtPgzmElmn51aOkhCFSuZq//o=
|
||||||
|
github.com/tklauser/numcpus v0.4.0/go.mod h1:1+UI3pD8NW14VMwdgJNJ1ESk2UnwhAnz5hMwiKKqXCQ=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
|
||||||
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
|
||||||
@@ -682,8 +698,8 @@ github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn
|
|||||||
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
|
||||||
github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ=
|
github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ=
|
||||||
github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
|
github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
|
||||||
github.com/up9inc/basenine/client/go v0.0.0-20220419100955-e2ca51087607 h1:UqxUSkOYOmsLZWQtMSk02ttnhdRwBRLOLt2aDiS9tEk=
|
github.com/up9inc/basenine/client/go v0.0.0-20220612112747-3b28eeac9c51 h1:6op+PUYmTlxze3V3f30lWKix3sWqv1M9rvRhyaxbsdQ=
|
||||||
github.com/up9inc/basenine/client/go v0.0.0-20220419100955-e2ca51087607/go.mod h1:SvJGPoa/6erhUQV7kvHBwM/0x5LyO6XaG2lUaCaKiUI=
|
github.com/up9inc/basenine/client/go v0.0.0-20220612112747-3b28eeac9c51/go.mod h1:SvJGPoa/6erhUQV7kvHBwM/0x5LyO6XaG2lUaCaKiUI=
|
||||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg=
|
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg=
|
||||||
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
|
||||||
github.com/wI2L/jsondiff v0.1.1 h1:r2TkoEet7E4JMO5+s1RCY2R0LrNPNHY6hbDeow2hRHw=
|
github.com/wI2L/jsondiff v0.1.1 h1:r2TkoEet7E4JMO5+s1RCY2R0LrNPNHY6hbDeow2hRHw=
|
||||||
@@ -695,14 +711,14 @@ github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6Ut
|
|||||||
github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk=
|
github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk=
|
||||||
github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
|
github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
|
||||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||||
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY=
|
|
||||||
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
|
|
||||||
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
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.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.1.32/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.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
|
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
|
||||||
|
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
|
||||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
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/api/v3 v3.5.0/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||||
go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
go.etcd.io/etcd/api/v3 v3.5.1/go.mod h1:cbVKeC6lCfl7j/8jBhAK6aIYO9XOjdptoxU/nLQcPvs=
|
||||||
@@ -895,6 +911,7 @@ golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190922100055-0a153f010e69/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190924154521-2837fb4f24fe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
@@ -963,6 +980,7 @@ golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||||||
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211210111614-af8b64212486/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20220207234003-57398862261d h1:Bm7BNOQt2Qv7ZqysjeLjgCBanX+88Z/OtdvsrEv1Djc=
|
golang.org/x/sys v0.0.0-20220207234003-57398862261d h1:Bm7BNOQt2Qv7ZqysjeLjgCBanX+88Z/OtdvsrEv1Djc=
|
||||||
golang.org/x/sys v0.0.0-20220207234003-57398862261d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220207234003-57398862261d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||||
@@ -1235,8 +1253,9 @@ gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C
|
|||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
|
||||||
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
|
|
||||||
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
|
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
|
||||||
|
gotest.tools/v3 v3.3.0 h1:MfDY1b1/0xN1CyMlQDac0ziEy9zJQd9CXBRRDHw2jJo=
|
||||||
|
gotest.tools/v3 v3.3.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
|||||||
@@ -14,17 +14,16 @@ import (
|
|||||||
"syscall"
|
"syscall"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/gin-contrib/pprof"
|
||||||
"github.com/gin-contrib/static"
|
"github.com/gin-contrib/static"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/up9inc/mizu/agent/pkg/dependency"
|
"github.com/up9inc/mizu/agent/pkg/dependency"
|
||||||
"github.com/up9inc/mizu/agent/pkg/elastic"
|
|
||||||
"github.com/up9inc/mizu/agent/pkg/entries"
|
"github.com/up9inc/mizu/agent/pkg/entries"
|
||||||
"github.com/up9inc/mizu/agent/pkg/middlewares"
|
"github.com/up9inc/mizu/agent/pkg/middlewares"
|
||||||
"github.com/up9inc/mizu/agent/pkg/models"
|
"github.com/up9inc/mizu/agent/pkg/models"
|
||||||
"github.com/up9inc/mizu/agent/pkg/oas"
|
"github.com/up9inc/mizu/agent/pkg/oas"
|
||||||
"github.com/up9inc/mizu/agent/pkg/routes"
|
"github.com/up9inc/mizu/agent/pkg/routes"
|
||||||
"github.com/up9inc/mizu/agent/pkg/servicemap"
|
"github.com/up9inc/mizu/agent/pkg/servicemap"
|
||||||
"github.com/up9inc/mizu/agent/pkg/up9"
|
|
||||||
"github.com/up9inc/mizu/agent/pkg/utils"
|
"github.com/up9inc/mizu/agent/pkg/utils"
|
||||||
|
|
||||||
"github.com/up9inc/mizu/agent/pkg/api"
|
"github.com/up9inc/mizu/agent/pkg/api"
|
||||||
@@ -37,6 +36,7 @@ import (
|
|||||||
"github.com/up9inc/mizu/shared"
|
"github.com/up9inc/mizu/shared"
|
||||||
"github.com/up9inc/mizu/tap"
|
"github.com/up9inc/mizu/tap"
|
||||||
tapApi "github.com/up9inc/mizu/tap/api"
|
tapApi "github.com/up9inc/mizu/tap/api"
|
||||||
|
"github.com/up9inc/mizu/tap/dbgctl"
|
||||||
)
|
)
|
||||||
|
|
||||||
var tapperMode = flag.Bool("tap", false, "Run in tapper mode without API")
|
var tapperMode = flag.Bool("tap", false, "Run in tapper mode without API")
|
||||||
@@ -46,6 +46,7 @@ var apiServerAddress = flag.String("api-server-address", "", "Address of mizu AP
|
|||||||
var namespace = flag.String("namespace", "", "Resolve IPs if they belong to resources in this namespace (default is all)")
|
var namespace = flag.String("namespace", "", "Resolve IPs if they belong to resources in this namespace (default is all)")
|
||||||
var harsReaderMode = flag.Bool("hars-read", false, "Run in hars-read mode")
|
var harsReaderMode = flag.Bool("hars-read", false, "Run in hars-read mode")
|
||||||
var harsDir = flag.String("hars-dir", "", "Directory to read hars from")
|
var harsDir = flag.String("hars-dir", "", "Directory to read hars from")
|
||||||
|
var profiler = flag.Bool("profiler", false, "Run pprof server")
|
||||||
|
|
||||||
const (
|
const (
|
||||||
socketConnectionRetries = 30
|
socketConnectionRetries = 30
|
||||||
@@ -62,7 +63,7 @@ func main() {
|
|||||||
app.LoadExtensions()
|
app.LoadExtensions()
|
||||||
|
|
||||||
if !*tapperMode && !*apiServerMode && !*standaloneMode && !*harsReaderMode {
|
if !*tapperMode && !*apiServerMode && !*standaloneMode && !*harsReaderMode {
|
||||||
panic("One of the flags --tap, --api or --standalone or --hars-read must be provided")
|
panic("One of the flags --tap, --api-server, --standalone or --hars-read must be provided")
|
||||||
}
|
}
|
||||||
|
|
||||||
if *standaloneMode {
|
if *standaloneMode {
|
||||||
@@ -70,7 +71,14 @@ func main() {
|
|||||||
} else if *tapperMode {
|
} else if *tapperMode {
|
||||||
runInTapperMode()
|
runInTapperMode()
|
||||||
} else if *apiServerMode {
|
} else if *apiServerMode {
|
||||||
utils.StartServer(runInApiServerMode(*namespace))
|
ginApp := runInApiServerMode(*namespace)
|
||||||
|
|
||||||
|
if *profiler {
|
||||||
|
pprof.Register(ginApp)
|
||||||
|
}
|
||||||
|
|
||||||
|
utils.StartServer(ginApp)
|
||||||
|
|
||||||
} else if *harsReaderMode {
|
} else if *harsReaderMode {
|
||||||
runInHarReaderMode()
|
runInHarReaderMode()
|
||||||
}
|
}
|
||||||
@@ -83,9 +91,9 @@ func main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func hostApi(socketHarOutputChannel chan<- *tapApi.OutputChannelItem) *gin.Engine {
|
func hostApi(socketHarOutputChannel chan<- *tapApi.OutputChannelItem) *gin.Engine {
|
||||||
app := gin.Default()
|
ginApp := gin.Default()
|
||||||
|
|
||||||
app.GET("/echo", func(c *gin.Context) {
|
ginApp.GET("/echo", func(c *gin.Context) {
|
||||||
c.JSON(http.StatusOK, "Here is Mizu agent")
|
c.JSON(http.StatusOK, "Here is Mizu agent")
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -93,7 +101,7 @@ func hostApi(socketHarOutputChannel chan<- *tapApi.OutputChannelItem) *gin.Engin
|
|||||||
SocketOutChannel: socketHarOutputChannel,
|
SocketOutChannel: socketHarOutputChannel,
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Use(disableRootStaticCache())
|
ginApp.Use(disableRootStaticCache())
|
||||||
|
|
||||||
staticFolder := "./site"
|
staticFolder := "./site"
|
||||||
indexStaticFile := staticFolder + "/index.html"
|
indexStaticFile := staticFolder + "/index.html"
|
||||||
@@ -101,30 +109,31 @@ func hostApi(socketHarOutputChannel chan<- *tapApi.OutputChannelItem) *gin.Engin
|
|||||||
logger.Log.Errorf("Error setting ui flags, err: %v", err)
|
logger.Log.Errorf("Error setting ui flags, err: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
app.Use(static.ServeRoot("/", staticFolder))
|
ginApp.Use(static.ServeRoot("/", staticFolder))
|
||||||
app.NoRoute(func(c *gin.Context) {
|
ginApp.NoRoute(func(c *gin.Context) {
|
||||||
c.File(indexStaticFile)
|
c.File(indexStaticFile)
|
||||||
})
|
})
|
||||||
|
|
||||||
app.Use(middlewares.CORSMiddleware()) // This has to be called after the static middleware, does not work if its called before
|
ginApp.Use(middlewares.CORSMiddleware()) // This has to be called after the static middleware, does not work if it's called before
|
||||||
|
|
||||||
api.WebSocketRoutes(app, &eventHandlers)
|
api.WebSocketRoutes(ginApp, &eventHandlers)
|
||||||
|
|
||||||
if config.Config.OAS {
|
if config.Config.OAS.Enable {
|
||||||
routes.OASRoutes(app)
|
routes.OASRoutes(ginApp)
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.Config.ServiceMap {
|
if config.Config.ServiceMap {
|
||||||
routes.ServiceMapRoutes(app)
|
routes.ServiceMapRoutes(ginApp)
|
||||||
}
|
}
|
||||||
|
|
||||||
routes.QueryRoutes(app)
|
routes.QueryRoutes(ginApp)
|
||||||
routes.EntriesRoutes(app)
|
routes.EntriesRoutes(ginApp)
|
||||||
routes.MetadataRoutes(app)
|
routes.MetadataRoutes(ginApp)
|
||||||
routes.StatusRoutes(app)
|
routes.StatusRoutes(ginApp)
|
||||||
routes.DbRoutes(app)
|
routes.DbRoutes(ginApp)
|
||||||
|
routes.ReplayRoutes(ginApp)
|
||||||
|
|
||||||
return app
|
return ginApp
|
||||||
}
|
}
|
||||||
|
|
||||||
func runInApiServerMode(namespace string) *gin.Engine {
|
func runInApiServerMode(namespace string) *gin.Engine {
|
||||||
@@ -136,13 +145,6 @@ func runInApiServerMode(namespace string) *gin.Engine {
|
|||||||
|
|
||||||
enableExpFeatureIfNeeded()
|
enableExpFeatureIfNeeded()
|
||||||
|
|
||||||
syncEntriesConfig := getSyncEntriesConfig()
|
|
||||||
if syncEntriesConfig != nil {
|
|
||||||
if err := up9.SyncEntries(syncEntriesConfig); err != nil {
|
|
||||||
logger.Log.Error("Error syncing entries, err: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return hostApi(app.GetEntryInputChannel())
|
return hostApi(app.GetEntryInputChannel())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -153,7 +155,9 @@ func runInTapperMode() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
hostMode := os.Getenv(shared.HostModeEnvVar) == "1"
|
hostMode := os.Getenv(shared.HostModeEnvVar) == "1"
|
||||||
tapOpts := &tap.TapOpts{HostMode: hostMode}
|
tapOpts := &tap.TapOpts{
|
||||||
|
HostMode: hostMode,
|
||||||
|
}
|
||||||
|
|
||||||
filteredOutputItemsChannel := make(chan *tapApi.OutputChannelItem)
|
filteredOutputItemsChannel := make(chan *tapApi.OutputChannelItem)
|
||||||
|
|
||||||
@@ -197,30 +201,14 @@ func runInHarReaderMode() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func enableExpFeatureIfNeeded() {
|
func enableExpFeatureIfNeeded() {
|
||||||
if config.Config.OAS {
|
if config.Config.OAS.Enable {
|
||||||
oasGenerator := dependency.GetInstance(dependency.OasGeneratorDependency).(oas.OasGenerator)
|
oasGenerator := dependency.GetInstance(dependency.OasGeneratorDependency).(oas.OasGenerator)
|
||||||
oasGenerator.Start(nil)
|
oasGenerator.Start()
|
||||||
}
|
}
|
||||||
if config.Config.ServiceMap {
|
if config.Config.ServiceMap {
|
||||||
serviceMapGenerator := dependency.GetInstance(dependency.ServiceMapGeneratorDependency).(servicemap.ServiceMap)
|
serviceMapGenerator := dependency.GetInstance(dependency.ServiceMapGeneratorDependency).(servicemap.ServiceMap)
|
||||||
serviceMapGenerator.Enable()
|
serviceMapGenerator.Enable()
|
||||||
}
|
}
|
||||||
elastic.GetInstance().Configure(config.Config.Elastic)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getSyncEntriesConfig() *shared.SyncEntriesConfig {
|
|
||||||
syncEntriesConfigJson := os.Getenv(shared.SyncEntriesConfigEnvVar)
|
|
||||||
if syncEntriesConfigJson == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
var syncEntriesConfig = &shared.SyncEntriesConfig{}
|
|
||||||
err := json.Unmarshal([]byte(syncEntriesConfigJson), syncEntriesConfig)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("env var %s's value of %s is invalid! json must match the shared.SyncEntriesConfig struct, err: %v", shared.SyncEntriesConfigEnvVar, syncEntriesConfigJson, err))
|
|
||||||
}
|
|
||||||
|
|
||||||
return syncEntriesConfig
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func disableRootStaticCache() gin.HandlerFunc {
|
func disableRootStaticCache() gin.HandlerFunc {
|
||||||
@@ -240,7 +228,7 @@ func setUIFlags(uiIndexPath string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
replacedContent := strings.Replace(string(read), "__IS_OAS_ENABLED__", strconv.FormatBool(config.Config.OAS), 1)
|
replacedContent := strings.Replace(string(read), "__IS_OAS_ENABLED__", strconv.FormatBool(config.Config.OAS.Enable), 1)
|
||||||
replacedContent = strings.Replace(replacedContent, "__IS_SERVICE_MAP_ENABLED__", strconv.FormatBool(config.Config.ServiceMap), 1)
|
replacedContent = strings.Replace(replacedContent, "__IS_SERVICE_MAP_ENABLED__", strconv.FormatBool(config.Config.ServiceMap), 1)
|
||||||
|
|
||||||
err = ioutil.WriteFile(uiIndexPath, []byte(replacedContent), 0)
|
err = ioutil.WriteFile(uiIndexPath, []byte(replacedContent), 0)
|
||||||
@@ -283,6 +271,10 @@ func pipeTapChannelToSocket(connection *websocket.Conn, messageDataChannel <-cha
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if dbgctl.MizuTapperDisableSending {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// NOTE: This is where the `*tapApi.OutputChannelItem` leaves the code
|
// NOTE: This is where the `*tapApi.OutputChannelItem` leaves the code
|
||||||
// and goes into the intermediate WebSocket.
|
// and goes into the intermediate WebSocket.
|
||||||
err = connection.WriteMessage(websocket.TextMessage, marshaledData)
|
err = connection.WriteMessage(websocket.TextMessage, marshaledData)
|
||||||
@@ -372,7 +364,8 @@ func handleIncomingMessageAsTapper(socketConnection *websocket.Conn) {
|
|||||||
|
|
||||||
func initializeDependencies() {
|
func initializeDependencies() {
|
||||||
dependency.RegisterGenerator(dependency.ServiceMapGeneratorDependency, func() interface{} { return servicemap.GetDefaultServiceMapInstance() })
|
dependency.RegisterGenerator(dependency.ServiceMapGeneratorDependency, func() interface{} { return servicemap.GetDefaultServiceMapInstance() })
|
||||||
dependency.RegisterGenerator(dependency.OasGeneratorDependency, func() interface{} { return oas.GetDefaultOasGeneratorInstance() })
|
dependency.RegisterGenerator(dependency.OasGeneratorDependency, func() interface{} { return oas.GetDefaultOasGeneratorInstance(config.Config.OAS.MaxExampleLen) })
|
||||||
|
dependency.RegisterGenerator(dependency.EntriesInserter, func() interface{} { return api.GetBasenineEntryInserterInstance() })
|
||||||
dependency.RegisterGenerator(dependency.EntriesProvider, func() interface{} { return &entries.BasenineEntriesProvider{} })
|
dependency.RegisterGenerator(dependency.EntriesProvider, func() interface{} { return &entries.BasenineEntriesProvider{} })
|
||||||
dependency.RegisterGenerator(dependency.EntriesSocketStreamer, func() interface{} { return &api.BasenineEntryStreamer{} })
|
dependency.RegisterGenerator(dependency.EntriesSocketStreamer, func() interface{} { return &api.BasenineEntryStreamer{} })
|
||||||
dependency.RegisterGenerator(dependency.EntryStreamerSocketConnector, func() interface{} { return &api.DefaultEntryStreamerSocketConnector{} })
|
dependency.RegisterGenerator(dependency.EntryStreamerSocketConnector, func() interface{} { return &api.DefaultEntryStreamerSocketConnector{} })
|
||||||
|
|||||||
@@ -1,107 +0,0 @@
|
|||||||
package api
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"context"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"github.com/getkin/kin-openapi/openapi3"
|
|
||||||
"github.com/getkin/kin-openapi/openapi3filter"
|
|
||||||
"github.com/getkin/kin-openapi/routers"
|
|
||||||
legacyrouter "github.com/getkin/kin-openapi/routers/legacy"
|
|
||||||
|
|
||||||
"github.com/up9inc/mizu/shared"
|
|
||||||
"github.com/up9inc/mizu/tap/api"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
ContractNotApplicable api.ContractStatus = 0
|
|
||||||
ContractPassed api.ContractStatus = 1
|
|
||||||
ContractFailed api.ContractStatus = 2
|
|
||||||
)
|
|
||||||
|
|
||||||
func loadOAS(ctx context.Context) (doc *openapi3.T, contractContent string, router routers.Router, err error) {
|
|
||||||
path := fmt.Sprintf("%s%s", shared.ConfigDirPath, shared.ContractFileName)
|
|
||||||
bytes, err := ioutil.ReadFile(path)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
contractContent = string(bytes)
|
|
||||||
loader := &openapi3.Loader{Context: ctx}
|
|
||||||
doc, _ = loader.LoadFromData(bytes)
|
|
||||||
err = doc.Validate(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
router, _ = legacyrouter.NewRouter(doc)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func validateOAS(ctx context.Context, doc *openapi3.T, router routers.Router, req *http.Request, res *http.Response) (isValid bool, reqErr error, resErr error) {
|
|
||||||
isValid = true
|
|
||||||
reqErr = nil
|
|
||||||
resErr = nil
|
|
||||||
|
|
||||||
// Find route
|
|
||||||
route, pathParams, err := router.FindRoute(req)
|
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate request
|
|
||||||
requestValidationInput := &openapi3filter.RequestValidationInput{
|
|
||||||
Request: req,
|
|
||||||
PathParams: pathParams,
|
|
||||||
Route: route,
|
|
||||||
}
|
|
||||||
if reqErr = openapi3filter.ValidateRequest(ctx, requestValidationInput); reqErr != nil {
|
|
||||||
isValid = false
|
|
||||||
}
|
|
||||||
|
|
||||||
responseValidationInput := &openapi3filter.ResponseValidationInput{
|
|
||||||
RequestValidationInput: requestValidationInput,
|
|
||||||
Status: res.StatusCode,
|
|
||||||
Header: res.Header,
|
|
||||||
}
|
|
||||||
|
|
||||||
if res.Body != nil {
|
|
||||||
body, _ := ioutil.ReadAll(res.Body)
|
|
||||||
res.Body = ioutil.NopCloser(bytes.NewBuffer(body))
|
|
||||||
responseValidationInput.SetBodyBytes(body)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Validate response.
|
|
||||||
if resErr = openapi3filter.ValidateResponse(ctx, responseValidationInput); resErr != nil {
|
|
||||||
isValid = false
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func handleOAS(ctx context.Context, doc *openapi3.T, router routers.Router, req *http.Request, res *http.Response, contractContent string) (contract api.Contract) {
|
|
||||||
contract = api.Contract{
|
|
||||||
Content: contractContent,
|
|
||||||
Status: ContractNotApplicable,
|
|
||||||
}
|
|
||||||
|
|
||||||
isValid, reqErr, resErr := validateOAS(ctx, doc, router, req, res)
|
|
||||||
if isValid {
|
|
||||||
contract.Status = ContractPassed
|
|
||||||
} else {
|
|
||||||
contract.Status = ContractFailed
|
|
||||||
if reqErr != nil {
|
|
||||||
contract.RequestReason = reqErr.Error()
|
|
||||||
} else {
|
|
||||||
contract.RequestReason = ""
|
|
||||||
}
|
|
||||||
if resErr != nil {
|
|
||||||
contract.ResponseReason = resErr.Error()
|
|
||||||
} else {
|
|
||||||
contract.ResponseReason = ""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return
|
|
||||||
}
|
|
||||||
@@ -5,50 +5,64 @@ import (
|
|||||||
|
|
||||||
basenine "github.com/up9inc/basenine/client/go"
|
basenine "github.com/up9inc/basenine/client/go"
|
||||||
"github.com/up9inc/mizu/agent/pkg/models"
|
"github.com/up9inc/mizu/agent/pkg/models"
|
||||||
"github.com/up9inc/mizu/logger"
|
|
||||||
tapApi "github.com/up9inc/mizu/tap/api"
|
tapApi "github.com/up9inc/mizu/tap/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
type EntryStreamerSocketConnector interface {
|
type EntryStreamerSocketConnector interface {
|
||||||
SendEntry(socketId int, entry *tapApi.Entry, params *WebSocketParams)
|
SendEntry(socketId int, entry *tapApi.Entry, params *WebSocketParams) error
|
||||||
SendMetadata(socketId int, metadata *basenine.Metadata)
|
SendMetadata(socketId int, metadata *basenine.Metadata) error
|
||||||
SendToastError(socketId int, err error)
|
SendToastError(socketId int, err error) error
|
||||||
CleanupSocket(socketId int)
|
CleanupSocket(socketId int)
|
||||||
}
|
}
|
||||||
|
|
||||||
type DefaultEntryStreamerSocketConnector struct{}
|
type DefaultEntryStreamerSocketConnector struct{}
|
||||||
|
|
||||||
func (e *DefaultEntryStreamerSocketConnector) SendEntry(socketId int, entry *tapApi.Entry, params *WebSocketParams) {
|
func (e *DefaultEntryStreamerSocketConnector) SendEntry(socketId int, entry *tapApi.Entry, params *WebSocketParams) error {
|
||||||
var message []byte
|
var message []byte
|
||||||
if params.EnableFullEntries {
|
if params.EnableFullEntries {
|
||||||
message, _ = models.CreateFullEntryWebSocketMessage(entry)
|
message, _ = models.CreateFullEntryWebSocketMessage(entry)
|
||||||
} else {
|
} else {
|
||||||
extension := extensionsMap[entry.Protocol.Name]
|
protocol, ok := protocolsMap[entry.ProtocolId]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("protocol not found, protocol: %v", protocol)
|
||||||
|
}
|
||||||
|
|
||||||
|
extension, ok := extensionsMap[protocol.Name]
|
||||||
|
if !ok {
|
||||||
|
return fmt.Errorf("extension not found, extension: %v", protocol.Name)
|
||||||
|
}
|
||||||
|
|
||||||
base := extension.Dissector.Summarize(entry)
|
base := extension.Dissector.Summarize(entry)
|
||||||
message, _ = models.CreateBaseEntryWebSocketMessage(base)
|
message, _ = models.CreateBaseEntryWebSocketMessage(base)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := SendToSocket(socketId, message); err != nil {
|
if err := SendToSocket(socketId, message); err != nil {
|
||||||
logger.Log.Error(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *DefaultEntryStreamerSocketConnector) SendMetadata(socketId int, metadata *basenine.Metadata) {
|
func (e *DefaultEntryStreamerSocketConnector) SendMetadata(socketId int, metadata *basenine.Metadata) error {
|
||||||
metadataBytes, _ := models.CreateWebsocketQueryMetadataMessage(metadata)
|
metadataBytes, _ := models.CreateWebsocketQueryMetadataMessage(metadata)
|
||||||
if err := SendToSocket(socketId, metadataBytes); err != nil {
|
if err := SendToSocket(socketId, metadataBytes); err != nil {
|
||||||
logger.Log.Error(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *DefaultEntryStreamerSocketConnector) SendToastError(socketId int, err error) {
|
func (e *DefaultEntryStreamerSocketConnector) SendToastError(socketId int, err error) error {
|
||||||
toastBytes, _ := models.CreateWebsocketToastMessage(&models.ToastMessage{
|
toastBytes, _ := models.CreateWebsocketToastMessage(&models.ToastMessage{
|
||||||
Type: "error",
|
Type: "error",
|
||||||
AutoClose: 5000,
|
AutoClose: 5000,
|
||||||
Text: fmt.Sprintf("Syntax error: %s", err.Error()),
|
Text: fmt.Sprintf("Syntax error: %s", err.Error()),
|
||||||
})
|
})
|
||||||
if err := SendToSocket(socketId, toastBytes); err != nil {
|
if err := SendToSocket(socketId, toastBytes); err != nil {
|
||||||
logger.Log.Error(err)
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (e *DefaultEntryStreamerSocketConnector) CleanupSocket(socketId int) {
|
func (e *DefaultEntryStreamerSocketConnector) CleanupSocket(socketId int) {
|
||||||
|
|||||||
@@ -11,24 +11,19 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/up9inc/mizu/agent/pkg/models"
|
|
||||||
|
|
||||||
"github.com/up9inc/mizu/agent/pkg/dependency"
|
"github.com/up9inc/mizu/agent/pkg/dependency"
|
||||||
"github.com/up9inc/mizu/agent/pkg/elastic"
|
"github.com/up9inc/mizu/agent/pkg/oas"
|
||||||
|
"github.com/up9inc/mizu/agent/pkg/servicemap"
|
||||||
|
|
||||||
"github.com/up9inc/mizu/agent/pkg/har"
|
"github.com/up9inc/mizu/agent/pkg/har"
|
||||||
"github.com/up9inc/mizu/agent/pkg/holder"
|
"github.com/up9inc/mizu/agent/pkg/holder"
|
||||||
"github.com/up9inc/mizu/agent/pkg/providers"
|
"github.com/up9inc/mizu/agent/pkg/providers"
|
||||||
|
|
||||||
"github.com/up9inc/mizu/agent/pkg/servicemap"
|
|
||||||
|
|
||||||
"github.com/up9inc/mizu/agent/pkg/resolver"
|
"github.com/up9inc/mizu/agent/pkg/resolver"
|
||||||
"github.com/up9inc/mizu/agent/pkg/utils"
|
"github.com/up9inc/mizu/agent/pkg/utils"
|
||||||
|
|
||||||
"github.com/up9inc/mizu/logger"
|
"github.com/up9inc/mizu/logger"
|
||||||
"github.com/up9inc/mizu/shared"
|
|
||||||
tapApi "github.com/up9inc/mizu/tap/api"
|
tapApi "github.com/up9inc/mizu/tap/api"
|
||||||
|
|
||||||
basenine "github.com/up9inc/basenine/client/go"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var k8sResolver *resolver.Resolver
|
var k8sResolver *resolver.Resolver
|
||||||
@@ -103,57 +98,15 @@ func startReadingChannel(outputItems <-chan *tapApi.OutputChannelItem, extension
|
|||||||
panic("Channel of captured messages is nil")
|
panic("Channel of captured messages is nil")
|
||||||
}
|
}
|
||||||
|
|
||||||
BasenineReconnect:
|
|
||||||
connection, err := basenine.NewConnection(shared.BasenineHost, shared.BaseninePort)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Errorf("Can't establish a new connection to Basenine server: %v", err)
|
|
||||||
time.Sleep(shared.BasenineReconnectInterval * time.Second)
|
|
||||||
goto BasenineReconnect
|
|
||||||
}
|
|
||||||
if err = connection.InsertMode(); err != nil {
|
|
||||||
logger.Log.Errorf("Insert mode call failed: %v", err)
|
|
||||||
connection.Close()
|
|
||||||
time.Sleep(shared.BasenineReconnectInterval * time.Second)
|
|
||||||
goto BasenineReconnect
|
|
||||||
}
|
|
||||||
|
|
||||||
disableOASValidation := false
|
|
||||||
ctx := context.Background()
|
|
||||||
doc, contractContent, router, err := loadOAS(ctx)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Infof("Disabled OAS validation: %s", err.Error())
|
|
||||||
disableOASValidation = true
|
|
||||||
}
|
|
||||||
|
|
||||||
for item := range outputItems {
|
for item := range outputItems {
|
||||||
extension := extensionsMap[item.Protocol.Name]
|
extension := extensionsMap[item.Protocol.Name]
|
||||||
resolvedSource, resolvedDestionation, namespace := resolveIP(item.ConnectionInfo)
|
resolvedSource, resolvedDestination, namespace := resolveIP(item.ConnectionInfo)
|
||||||
|
|
||||||
if namespace == "" && item.Namespace != tapApi.UNKNOWN_NAMESPACE {
|
if namespace == "" && item.Namespace != tapApi.UnknownNamespace {
|
||||||
namespace = item.Namespace
|
namespace = item.Namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
mizuEntry := extension.Dissector.Analyze(item, resolvedSource, resolvedDestionation, namespace)
|
mizuEntry := extension.Dissector.Analyze(item, resolvedSource, resolvedDestination, namespace)
|
||||||
if extension.Protocol.Name == "http" {
|
|
||||||
if !disableOASValidation {
|
|
||||||
var httpPair tapApi.HTTPRequestResponsePair
|
|
||||||
if err := json.Unmarshal([]byte(mizuEntry.HTTPPair), &httpPair); err != nil {
|
|
||||||
logger.Log.Error(err)
|
|
||||||
} else {
|
|
||||||
contract := handleOAS(ctx, doc, router, httpPair.Request.Payload.RawRequest, httpPair.Response.Payload.RawResponse, contractContent)
|
|
||||||
mizuEntry.ContractStatus = contract.Status
|
|
||||||
mizuEntry.ContractRequestReason = contract.RequestReason
|
|
||||||
mizuEntry.ContractResponseReason = contract.ResponseReason
|
|
||||||
mizuEntry.ContractContent = contract.Content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
harEntry, err := har.NewEntry(mizuEntry.Request, mizuEntry.Response, mizuEntry.StartTime, mizuEntry.ElapsedTime)
|
|
||||||
if err == nil {
|
|
||||||
rules, _, _ := models.RunValidationRulesState(*harEntry, mizuEntry.Destination.Name)
|
|
||||||
mizuEntry.Rules = rules
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := json.Marshal(mizuEntry)
|
data, err := json.Marshal(mizuEntry)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -161,19 +114,19 @@ BasenineReconnect:
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
providers.EntryAdded(len(data))
|
entryInserter := dependency.GetInstance(dependency.EntriesInserter).(EntryInserter)
|
||||||
|
if err := entryInserter.Insert(mizuEntry); err != nil {
|
||||||
if err = connection.SendText(string(data)); err != nil {
|
logger.Log.Errorf("Error inserting entry, err: %v", err)
|
||||||
logger.Log.Errorf("An error occured while inserting a new record to database: %v", err)
|
|
||||||
connection.Close()
|
|
||||||
time.Sleep(shared.BasenineReconnectInterval * time.Second)
|
|
||||||
goto BasenineReconnect
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
summary := extension.Dissector.Summarize(mizuEntry)
|
||||||
|
providers.EntryAdded(len(data), summary)
|
||||||
|
|
||||||
serviceMapGenerator := dependency.GetInstance(dependency.ServiceMapGeneratorDependency).(servicemap.ServiceMapSink)
|
serviceMapGenerator := dependency.GetInstance(dependency.ServiceMapGeneratorDependency).(servicemap.ServiceMapSink)
|
||||||
serviceMapGenerator.NewTCPEntry(mizuEntry.Source, mizuEntry.Destination, &item.Protocol)
|
serviceMapGenerator.NewTCPEntry(mizuEntry.Source, mizuEntry.Destination, &item.Protocol)
|
||||||
|
|
||||||
elastic.GetInstance().PushEntry(mizuEntry)
|
oasGenerator := dependency.GetInstance(dependency.OasGeneratorDependency).(oas.OasGeneratorSink)
|
||||||
|
oasGenerator.HandleEntry(mizuEntry, &item.Protocol)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
71
agent/pkg/api/socket_data_inserter.go
Normal file
71
agent/pkg/api/socket_data_inserter.go
Normal file
@@ -0,0 +1,71 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
basenine "github.com/up9inc/basenine/client/go"
|
||||||
|
"github.com/up9inc/mizu/logger"
|
||||||
|
"github.com/up9inc/mizu/shared"
|
||||||
|
"github.com/up9inc/mizu/tap/api"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EntryInserter interface {
|
||||||
|
Insert(entry *api.Entry) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type BasenineEntryInserter struct {
|
||||||
|
connection *basenine.Connection
|
||||||
|
}
|
||||||
|
|
||||||
|
var instance *BasenineEntryInserter
|
||||||
|
var once sync.Once
|
||||||
|
|
||||||
|
func GetBasenineEntryInserterInstance() *BasenineEntryInserter {
|
||||||
|
once.Do(func() {
|
||||||
|
instance = &BasenineEntryInserter{}
|
||||||
|
})
|
||||||
|
|
||||||
|
return instance
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *BasenineEntryInserter) Insert(entry *api.Entry) error {
|
||||||
|
if e.connection == nil {
|
||||||
|
e.connection = initializeConnection()
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := json.Marshal(entry)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error marshling entry, err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := e.connection.SendText(string(data)); err != nil {
|
||||||
|
e.connection.Close()
|
||||||
|
e.connection = nil
|
||||||
|
|
||||||
|
return fmt.Errorf("error sending text to database, err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func initializeConnection() *basenine.Connection{
|
||||||
|
for {
|
||||||
|
connection, err := basenine.NewConnection(shared.BasenineHost, shared.BaseninePort)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log.Errorf("Can't establish a new connection to Basenine server: %v", err)
|
||||||
|
time.Sleep(shared.BasenineReconnectInterval * time.Second)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = connection.InsertMode(); err != nil {
|
||||||
|
logger.Log.Errorf("Insert mode call failed: %v", err)
|
||||||
|
connection.Close()
|
||||||
|
time.Sleep(shared.BasenineReconnectInterval * time.Second)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
return connection
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package api
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
|
||||||
basenine "github.com/up9inc/basenine/client/go"
|
basenine "github.com/up9inc/basenine/client/go"
|
||||||
"github.com/up9inc/mizu/agent/pkg/dependency"
|
"github.com/up9inc/mizu/agent/pkg/dependency"
|
||||||
@@ -33,9 +34,18 @@ func (e *BasenineEntryStreamer) Get(ctx context.Context, socketId int, params *W
|
|||||||
meta := make(chan []byte)
|
meta := make(chan []byte)
|
||||||
|
|
||||||
query := params.Query
|
query := params.Query
|
||||||
err = basenine.Validate(shared.BasenineHost, shared.BaseninePort, query)
|
if err = basenine.Validate(shared.BasenineHost, shared.BaseninePort, query); err != nil {
|
||||||
|
if err := entryStreamerSocketConnector.SendToastError(socketId, err); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
entryStreamerSocketConnector.CleanupSocket(socketId)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
leftOff, err := e.fetch(socketId, params, entryStreamerSocketConnector)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
entryStreamerSocketConnector.SendToastError(socketId, err)
|
logger.Log.Errorf("Fetch error: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDataChannel := func(c *basenine.Connection, data chan []byte) {
|
handleDataChannel := func(c *basenine.Connection, data chan []byte) {
|
||||||
@@ -47,13 +57,15 @@ func (e *BasenineEntryStreamer) Get(ctx context.Context, socketId int, params *W
|
|||||||
}
|
}
|
||||||
|
|
||||||
var entry *tapApi.Entry
|
var entry *tapApi.Entry
|
||||||
err = json.Unmarshal(bytes, &entry)
|
if err = json.Unmarshal(bytes, &entry); err != nil {
|
||||||
if err != nil {
|
logger.Log.Debugf("Error unmarshalling entry: %v", err)
|
||||||
logger.Log.Debugf("Error unmarshalling entry: %v", err.Error())
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
entryStreamerSocketConnector.SendEntry(socketId, entry, params)
|
if err := entryStreamerSocketConnector.SendEntry(socketId, entry, params); err != nil {
|
||||||
|
logger.Log.Errorf("Error sending entry to socket, err: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -66,20 +78,22 @@ func (e *BasenineEntryStreamer) Get(ctx context.Context, socketId int, params *W
|
|||||||
}
|
}
|
||||||
|
|
||||||
var metadata *basenine.Metadata
|
var metadata *basenine.Metadata
|
||||||
err = json.Unmarshal(bytes, &metadata)
|
if err = json.Unmarshal(bytes, &metadata); err != nil {
|
||||||
if err != nil {
|
logger.Log.Debugf("Error unmarshalling metadata: %v", err)
|
||||||
logger.Log.Debugf("Error unmarshalling metadata: %v", err.Error())
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
entryStreamerSocketConnector.SendMetadata(socketId, metadata)
|
if err := entryStreamerSocketConnector.SendMetadata(socketId, metadata); err != nil {
|
||||||
|
logger.Log.Errorf("Error sending metadata to socket, err: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
go handleDataChannel(connection, data)
|
go handleDataChannel(connection, data)
|
||||||
go handleMetaChannel(connection, meta)
|
go handleMetaChannel(connection, meta)
|
||||||
|
|
||||||
if err = connection.Query(query, data, meta); err != nil {
|
if err = connection.Query(leftOff, query, data, meta); err != nil {
|
||||||
logger.Log.Errorf("Query mode call failed: %v", err)
|
logger.Log.Errorf("Query mode call failed: %v", err)
|
||||||
entryStreamerSocketConnector.CleanupSocket(socketId)
|
entryStreamerSocketConnector.CleanupSocket(socketId)
|
||||||
return err
|
return err
|
||||||
@@ -94,3 +108,64 @@ func (e *BasenineEntryStreamer) Get(ctx context.Context, socketId int, params *W
|
|||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reverses a []byte slice.
|
||||||
|
func (e *BasenineEntryStreamer) fetch(socketId int, params *WebSocketParams, connector EntryStreamerSocketConnector) (leftOff string, err error) {
|
||||||
|
if params.Fetch <= 0 {
|
||||||
|
leftOff = params.LeftOff
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var data [][]byte
|
||||||
|
var firstMeta []byte
|
||||||
|
var lastMeta []byte
|
||||||
|
data, firstMeta, lastMeta, err = basenine.Fetch(
|
||||||
|
shared.BasenineHost,
|
||||||
|
shared.BaseninePort,
|
||||||
|
params.LeftOff,
|
||||||
|
-1,
|
||||||
|
params.Query,
|
||||||
|
params.Fetch,
|
||||||
|
time.Duration(params.TimeoutMs)*time.Millisecond,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var firstMetadata *basenine.Metadata
|
||||||
|
if err = json.Unmarshal(firstMeta, &firstMetadata); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
leftOff = firstMetadata.LeftOff
|
||||||
|
|
||||||
|
var lastMetadata *basenine.Metadata
|
||||||
|
if err = json.Unmarshal(lastMeta, &lastMetadata); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = connector.SendMetadata(socketId, lastMetadata); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
data = e.reverseBytesSlice(data)
|
||||||
|
for _, row := range data {
|
||||||
|
var entry *tapApi.Entry
|
||||||
|
if err = json.Unmarshal(row, &entry); err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = connector.SendEntry(socketId, entry, params); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reverses a []byte slice.
|
||||||
|
func (e *BasenineEntryStreamer) reverseBytesSlice(arr [][]byte) (newArr [][]byte) {
|
||||||
|
for i := len(arr) - 1; i >= 0; i-- {
|
||||||
|
newArr = append(newArr, arr[i])
|
||||||
|
}
|
||||||
|
return newArr
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,10 +14,14 @@ import (
|
|||||||
tapApi "github.com/up9inc/mizu/tap/api"
|
tapApi "github.com/up9inc/mizu/tap/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
var extensionsMap map[string]*tapApi.Extension // global
|
var (
|
||||||
|
extensionsMap map[string]*tapApi.Extension // global
|
||||||
|
protocolsMap map[string]*tapApi.Protocol //global
|
||||||
|
)
|
||||||
|
|
||||||
func InitExtensionsMap(ref map[string]*tapApi.Extension) {
|
func InitMaps(extensions map[string]*tapApi.Extension, protocols map[string]*tapApi.Protocol) {
|
||||||
extensionsMap = ref
|
extensionsMap = extensions
|
||||||
|
protocolsMap = protocols
|
||||||
}
|
}
|
||||||
|
|
||||||
type EventHandlers interface {
|
type EventHandlers interface {
|
||||||
@@ -34,8 +38,11 @@ type SocketConnection struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type WebSocketParams struct {
|
type WebSocketParams struct {
|
||||||
|
LeftOff string `json:"leftOff"`
|
||||||
Query string `json:"query"`
|
Query string `json:"query"`
|
||||||
EnableFullEntries bool `json:"enableFullEntries"`
|
EnableFullEntries bool `json:"enableFullEntries"`
|
||||||
|
Fetch int `json:"fetch"`
|
||||||
|
TimeoutMs int `json:"timeoutMs"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import (
|
|||||||
"github.com/up9inc/mizu/agent/pkg/models"
|
"github.com/up9inc/mizu/agent/pkg/models"
|
||||||
"github.com/up9inc/mizu/agent/pkg/providers/tappedPods"
|
"github.com/up9inc/mizu/agent/pkg/providers/tappedPods"
|
||||||
"github.com/up9inc/mizu/agent/pkg/providers/tappers"
|
"github.com/up9inc/mizu/agent/pkg/providers/tappers"
|
||||||
"github.com/up9inc/mizu/agent/pkg/up9"
|
|
||||||
|
|
||||||
tapApi "github.com/up9inc/mizu/tap/api"
|
tapApi "github.com/up9inc/mizu/tap/api"
|
||||||
|
|
||||||
@@ -31,10 +30,6 @@ type RoutesEventHandlers struct {
|
|||||||
SocketOutChannel chan<- *tapApi.OutputChannelItem
|
SocketOutChannel chan<- *tapApi.OutputChannelItem
|
||||||
}
|
}
|
||||||
|
|
||||||
func init() {
|
|
||||||
go up9.UpdateAnalyzeStatus(BroadcastToBrowserClients)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (h *RoutesEventHandlers) WebSocketConnect(_ *gin.Context, socketId int, isTapper bool) {
|
func (h *RoutesEventHandlers) WebSocketConnect(_ *gin.Context, socketId int, isTapper bool) {
|
||||||
if isTapper {
|
if isTapper {
|
||||||
logger.Log.Infof("Websocket event - Tapper connected, socket ID: %d", socketId)
|
logger.Log.Infof("Websocket event - Tapper connected, socket ID: %d", socketId)
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ import (
|
|||||||
"github.com/op/go-logging"
|
"github.com/op/go-logging"
|
||||||
basenine "github.com/up9inc/basenine/client/go"
|
basenine "github.com/up9inc/basenine/client/go"
|
||||||
"github.com/up9inc/mizu/agent/pkg/api"
|
"github.com/up9inc/mizu/agent/pkg/api"
|
||||||
|
"github.com/up9inc/mizu/agent/pkg/providers"
|
||||||
"github.com/up9inc/mizu/agent/pkg/utils"
|
"github.com/up9inc/mizu/agent/pkg/utils"
|
||||||
"github.com/up9inc/mizu/logger"
|
"github.com/up9inc/mizu/logger"
|
||||||
tapApi "github.com/up9inc/mizu/tap/api"
|
tapApi "github.com/up9inc/mizu/tap/api"
|
||||||
|
"github.com/up9inc/mizu/tap/dbgctl"
|
||||||
amqpExt "github.com/up9inc/mizu/tap/extensions/amqp"
|
amqpExt "github.com/up9inc/mizu/tap/extensions/amqp"
|
||||||
httpExt "github.com/up9inc/mizu/tap/extensions/http"
|
httpExt "github.com/up9inc/mizu/tap/extensions/http"
|
||||||
kafkaExt "github.com/up9inc/mizu/tap/extensions/kafka"
|
kafkaExt "github.com/up9inc/mizu/tap/extensions/kafka"
|
||||||
@@ -21,45 +23,66 @@ import (
|
|||||||
var (
|
var (
|
||||||
Extensions []*tapApi.Extension // global
|
Extensions []*tapApi.Extension // global
|
||||||
ExtensionsMap map[string]*tapApi.Extension // global
|
ExtensionsMap map[string]*tapApi.Extension // global
|
||||||
|
ProtocolsMap map[string]*tapApi.Protocol //global
|
||||||
)
|
)
|
||||||
|
|
||||||
func LoadExtensions() {
|
func LoadExtensions() {
|
||||||
Extensions = make([]*tapApi.Extension, 4)
|
Extensions = make([]*tapApi.Extension, 0)
|
||||||
ExtensionsMap = make(map[string]*tapApi.Extension)
|
ExtensionsMap = make(map[string]*tapApi.Extension)
|
||||||
|
ProtocolsMap = make(map[string]*tapApi.Protocol)
|
||||||
extensionAmqp := &tapApi.Extension{}
|
|
||||||
dissectorAmqp := amqpExt.NewDissector()
|
|
||||||
dissectorAmqp.Register(extensionAmqp)
|
|
||||||
extensionAmqp.Dissector = dissectorAmqp
|
|
||||||
Extensions[0] = extensionAmqp
|
|
||||||
ExtensionsMap[extensionAmqp.Protocol.Name] = extensionAmqp
|
|
||||||
|
|
||||||
extensionHttp := &tapApi.Extension{}
|
extensionHttp := &tapApi.Extension{}
|
||||||
dissectorHttp := httpExt.NewDissector()
|
dissectorHttp := httpExt.NewDissector()
|
||||||
dissectorHttp.Register(extensionHttp)
|
dissectorHttp.Register(extensionHttp)
|
||||||
extensionHttp.Dissector = dissectorHttp
|
extensionHttp.Dissector = dissectorHttp
|
||||||
Extensions[1] = extensionHttp
|
Extensions = append(Extensions, extensionHttp)
|
||||||
ExtensionsMap[extensionHttp.Protocol.Name] = extensionHttp
|
ExtensionsMap[extensionHttp.Protocol.Name] = extensionHttp
|
||||||
|
protocolsHttp := dissectorHttp.GetProtocols()
|
||||||
|
for k, v := range protocolsHttp {
|
||||||
|
ProtocolsMap[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
extensionKafka := &tapApi.Extension{}
|
if !dbgctl.MizuTapperDisableNonHttpExtensions {
|
||||||
dissectorKafka := kafkaExt.NewDissector()
|
extensionAmqp := &tapApi.Extension{}
|
||||||
dissectorKafka.Register(extensionKafka)
|
dissectorAmqp := amqpExt.NewDissector()
|
||||||
extensionKafka.Dissector = dissectorKafka
|
dissectorAmqp.Register(extensionAmqp)
|
||||||
Extensions[2] = extensionKafka
|
extensionAmqp.Dissector = dissectorAmqp
|
||||||
ExtensionsMap[extensionKafka.Protocol.Name] = extensionKafka
|
Extensions = append(Extensions, extensionAmqp)
|
||||||
|
ExtensionsMap[extensionAmqp.Protocol.Name] = extensionAmqp
|
||||||
|
protocolsAmqp := dissectorAmqp.GetProtocols()
|
||||||
|
for k, v := range protocolsAmqp {
|
||||||
|
ProtocolsMap[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
extensionRedis := &tapApi.Extension{}
|
extensionKafka := &tapApi.Extension{}
|
||||||
dissectorRedis := redisExt.NewDissector()
|
dissectorKafka := kafkaExt.NewDissector()
|
||||||
dissectorRedis.Register(extensionRedis)
|
dissectorKafka.Register(extensionKafka)
|
||||||
extensionRedis.Dissector = dissectorRedis
|
extensionKafka.Dissector = dissectorKafka
|
||||||
Extensions[3] = extensionRedis
|
Extensions = append(Extensions, extensionKafka)
|
||||||
ExtensionsMap[extensionRedis.Protocol.Name] = extensionRedis
|
ExtensionsMap[extensionKafka.Protocol.Name] = extensionKafka
|
||||||
|
protocolsKafka := dissectorKafka.GetProtocols()
|
||||||
|
for k, v := range protocolsKafka {
|
||||||
|
ProtocolsMap[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
extensionRedis := &tapApi.Extension{}
|
||||||
|
dissectorRedis := redisExt.NewDissector()
|
||||||
|
dissectorRedis.Register(extensionRedis)
|
||||||
|
extensionRedis.Dissector = dissectorRedis
|
||||||
|
Extensions = append(Extensions, extensionRedis)
|
||||||
|
ExtensionsMap[extensionRedis.Protocol.Name] = extensionRedis
|
||||||
|
protocolsRedis := dissectorRedis.GetProtocols()
|
||||||
|
for k, v := range protocolsRedis {
|
||||||
|
ProtocolsMap[k] = v
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sort.Slice(Extensions, func(i, j int) bool {
|
sort.Slice(Extensions, func(i, j int) bool {
|
||||||
return Extensions[i].Protocol.Priority < Extensions[j].Protocol.Priority
|
return Extensions[i].Protocol.Priority < Extensions[j].Protocol.Priority
|
||||||
})
|
})
|
||||||
|
|
||||||
api.InitExtensionsMap(ExtensionsMap)
|
api.InitMaps(ExtensionsMap, ProtocolsMap)
|
||||||
|
providers.InitProtocolToColor(ProtocolsMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ConfigureBasenineServer(host string, port string, dbSize int64, logLevel logging.Level, insertionFilter string) {
|
func ConfigureBasenineServer(host string, port string, dbSize int64, logLevel logging.Level, insertionFilter string) {
|
||||||
|
|||||||
@@ -44,10 +44,10 @@ func GetEntries(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
entriesProvider := dependency.GetInstance(dependency.EntriesProvider).(entries.EntriesProvider)
|
entriesProvider := dependency.GetInstance(dependency.EntriesProvider).(entries.EntriesProvider)
|
||||||
entries, metadata, err := entriesProvider.GetEntries(entriesRequest)
|
entryWrappers, metadata, err := entriesProvider.GetEntries(entriesRequest)
|
||||||
if !HandleEntriesError(c, err) {
|
if !HandleEntriesError(c, err) {
|
||||||
baseEntries := make([]interface{}, 0)
|
baseEntries := make([]interface{}, 0)
|
||||||
for _, entry := range entries {
|
for _, entry := range entryWrappers {
|
||||||
baseEntries = append(baseEntries, entry.Base)
|
baseEntries = append(baseEntries, entry.Base)
|
||||||
}
|
}
|
||||||
c.JSON(http.StatusOK, models.EntriesResponse{
|
c.JSON(http.StatusOK, models.EntriesResponse{
|
||||||
|
|||||||
@@ -1,17 +1,12 @@
|
|||||||
package controllers
|
package controllers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
basenine "github.com/up9inc/basenine/client/go"
|
|
||||||
"net"
|
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/up9inc/mizu/agent/pkg/dependency"
|
|
||||||
"github.com/up9inc/mizu/agent/pkg/oas"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/up9inc/mizu/agent/pkg/dependency"
|
||||||
|
"github.com/up9inc/mizu/agent/pkg/oas"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetOASServers(t *testing.T) {
|
func TestGetOASServers(t *testing.T) {
|
||||||
@@ -37,33 +32,14 @@ func TestGetOASSpec(t *testing.T) {
|
|||||||
t.Logf("Written body: %s", recorder.Body.String())
|
t.Logf("Written body: %s", recorder.Body.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
type fakeConn struct {
|
|
||||||
sendBuffer *bytes.Buffer
|
|
||||||
receiveBuffer *bytes.Buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f fakeConn) Read(p []byte) (int, error) { return f.sendBuffer.Read(p) }
|
|
||||||
func (f fakeConn) Write(p []byte) (int, error) { return f.receiveBuffer.Write(p) }
|
|
||||||
func (fakeConn) Close() error { return nil }
|
|
||||||
func (fakeConn) LocalAddr() net.Addr { return nil }
|
|
||||||
func (fakeConn) RemoteAddr() net.Addr { return nil }
|
|
||||||
func (fakeConn) SetDeadline(t time.Time) error { return nil }
|
|
||||||
func (fakeConn) SetReadDeadline(t time.Time) error { return nil }
|
|
||||||
func (fakeConn) SetWriteDeadline(t time.Time) error { return nil }
|
|
||||||
|
|
||||||
func getRecorderAndContext() (*httptest.ResponseRecorder, *gin.Context) {
|
func getRecorderAndContext() (*httptest.ResponseRecorder, *gin.Context) {
|
||||||
dummyConn := new(basenine.Connection)
|
|
||||||
dummyConn.Conn = fakeConn{
|
|
||||||
sendBuffer: bytes.NewBufferString("\n"),
|
|
||||||
receiveBuffer: bytes.NewBufferString("\n"),
|
|
||||||
}
|
|
||||||
dependency.RegisterGenerator(dependency.OasGeneratorDependency, func() interface{} {
|
dependency.RegisterGenerator(dependency.OasGeneratorDependency, func() interface{} {
|
||||||
return oas.GetDefaultOasGeneratorInstance()
|
return oas.GetDefaultOasGeneratorInstance(-1)
|
||||||
})
|
})
|
||||||
|
|
||||||
recorder := httptest.NewRecorder()
|
recorder := httptest.NewRecorder()
|
||||||
c, _ := gin.CreateTestContext(recorder)
|
c, _ := gin.CreateTestContext(recorder)
|
||||||
oas.GetDefaultOasGeneratorInstance().Start(dummyConn)
|
oas.GetDefaultOasGeneratorInstance(-1).Start()
|
||||||
oas.GetDefaultOasGeneratorInstance().GetServiceSpecs().Store("some", oas.NewGen("some"))
|
oas.GetDefaultOasGeneratorInstance(-1).GetServiceSpecs().Store("some", oas.NewGen("some"))
|
||||||
return recorder, c
|
return recorder, c
|
||||||
}
|
}
|
||||||
|
|||||||
34
agent/pkg/controllers/replay_controller.go
Normal file
34
agent/pkg/controllers/replay_controller.go
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/up9inc/mizu/agent/pkg/replay"
|
||||||
|
"github.com/up9inc/mizu/agent/pkg/validation"
|
||||||
|
"github.com/up9inc/mizu/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
replayTimeout = 10 * time.Second
|
||||||
|
)
|
||||||
|
|
||||||
|
func ReplayRequest(c *gin.Context) {
|
||||||
|
logger.Log.Debug("Starting replay")
|
||||||
|
replayDetails := &replay.Details{}
|
||||||
|
if err := c.Bind(replayDetails); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Log.Debugf("Validating replay, %v", replayDetails)
|
||||||
|
if err := validation.Validate(replayDetails); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Log.Debug("Executing replay, %v", replayDetails)
|
||||||
|
result := replay.ExecuteRequest(replayDetails, replayTimeout)
|
||||||
|
c.JSON(http.StatusOK, result)
|
||||||
|
}
|
||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
"github.com/up9inc/mizu/agent/pkg/providers"
|
"github.com/up9inc/mizu/agent/pkg/providers"
|
||||||
"github.com/up9inc/mizu/agent/pkg/providers/tappedPods"
|
"github.com/up9inc/mizu/agent/pkg/providers/tappedPods"
|
||||||
"github.com/up9inc/mizu/agent/pkg/providers/tappers"
|
"github.com/up9inc/mizu/agent/pkg/providers/tappers"
|
||||||
"github.com/up9inc/mizu/agent/pkg/up9"
|
|
||||||
"github.com/up9inc/mizu/agent/pkg/validation"
|
"github.com/up9inc/mizu/agent/pkg/validation"
|
||||||
"github.com/up9inc/mizu/logger"
|
"github.com/up9inc/mizu/logger"
|
||||||
"github.com/up9inc/mizu/shared"
|
"github.com/up9inc/mizu/shared"
|
||||||
@@ -71,29 +70,19 @@ func GetConnectedTappersCount(c *gin.Context) {
|
|||||||
c.JSON(http.StatusOK, tappers.GetConnectedCount())
|
c.JSON(http.StatusOK, tappers.GetConnectedCount())
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAuthStatus(c *gin.Context) {
|
|
||||||
authStatus, err := providers.GetAuthStatus()
|
|
||||||
if err != nil {
|
|
||||||
c.JSON(http.StatusInternalServerError, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, authStatus)
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetTappingStatus(c *gin.Context) {
|
func GetTappingStatus(c *gin.Context) {
|
||||||
tappedPodsStatus := tappedPods.GetTappedPodsStatus()
|
tappedPodsStatus := tappedPods.GetTappedPodsStatus()
|
||||||
c.JSON(http.StatusOK, tappedPodsStatus)
|
c.JSON(http.StatusOK, tappedPodsStatus)
|
||||||
}
|
}
|
||||||
|
|
||||||
func AnalyzeInformation(c *gin.Context) {
|
|
||||||
c.JSON(http.StatusOK, up9.GetAnalyzeInfo())
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetGeneralStats(c *gin.Context) {
|
func GetGeneralStats(c *gin.Context) {
|
||||||
c.JSON(http.StatusOK, providers.GetGeneralStats())
|
c.JSON(http.StatusOK, providers.GetGeneralStats())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GetTrafficStats(c *gin.Context) {
|
||||||
|
c.JSON(http.StatusOK, providers.GetTrafficStats())
|
||||||
|
}
|
||||||
|
|
||||||
func GetCurrentResolvingInformation(c *gin.Context) {
|
func GetCurrentResolvingInformation(c *gin.Context) {
|
||||||
c.JSON(http.StatusOK, holder.GetResolver().GetMap())
|
c.JSON(http.StatusOK, holder.GetResolver().GetMap())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
package dependency
|
package dependency
|
||||||
|
|
||||||
var typeIntializerMap = make(map[DependencyContainerType]func() interface{}, 0)
|
var typeInitializerMap = make(map[ContainerType]func() interface{}, 0)
|
||||||
|
|
||||||
func RegisterGenerator(name DependencyContainerType, fn func() interface{}) {
|
func RegisterGenerator(name ContainerType, fn func() interface{}) {
|
||||||
typeIntializerMap[name] = fn
|
typeInitializerMap[name] = fn
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetInstance(name DependencyContainerType) interface{} {
|
func GetInstance(name ContainerType) interface{} {
|
||||||
return typeIntializerMap[name]()
|
return typeInitializerMap[name]()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
package dependency
|
package dependency
|
||||||
|
|
||||||
type DependencyContainerType string
|
type ContainerType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
ServiceMapGeneratorDependency = "ServiceMapGeneratorDependency"
|
ServiceMapGeneratorDependency ContainerType = "ServiceMapGeneratorDependency"
|
||||||
OasGeneratorDependency = "OasGeneratorDependency"
|
OasGeneratorDependency ContainerType = "OasGeneratorDependency"
|
||||||
EntriesProvider = "EntriesProvider"
|
EntriesInserter ContainerType = "EntriesInserter"
|
||||||
EntriesSocketStreamer = "EntriesSocketStreamer"
|
EntriesProvider ContainerType = "EntriesProvider"
|
||||||
EntryStreamerSocketConnector = "EntryStreamerSocketConnector"
|
EntriesSocketStreamer ContainerType = "EntriesSocketStreamer"
|
||||||
|
EntryStreamerSocketConnector ContainerType = "EntryStreamerSocketConnector"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,116 +0,0 @@
|
|||||||
package elastic
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"crypto/tls"
|
|
||||||
"encoding/json"
|
|
||||||
"net/http"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/elastic/go-elasticsearch/v7"
|
|
||||||
"github.com/up9inc/mizu/logger"
|
|
||||||
"github.com/up9inc/mizu/shared"
|
|
||||||
"github.com/up9inc/mizu/tap/api"
|
|
||||||
)
|
|
||||||
|
|
||||||
type client struct {
|
|
||||||
es *elasticsearch.Client
|
|
||||||
index string
|
|
||||||
insertedCount int
|
|
||||||
}
|
|
||||||
|
|
||||||
var instance *client
|
|
||||||
var once sync.Once
|
|
||||||
|
|
||||||
func GetInstance() *client {
|
|
||||||
once.Do(func() {
|
|
||||||
instance = newClient()
|
|
||||||
})
|
|
||||||
return instance
|
|
||||||
}
|
|
||||||
|
|
||||||
func (client *client) Configure(config shared.ElasticConfig) {
|
|
||||||
if config.Url == "" || config.User == "" || config.Password == "" {
|
|
||||||
if client.es != nil {
|
|
||||||
client.es = nil
|
|
||||||
}
|
|
||||||
logger.Log.Infof("No elastic configuration was supplied, elastic exporter disabled")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
transport := http.DefaultTransport
|
|
||||||
tlsClientConfig := &tls.Config{InsecureSkipVerify: true}
|
|
||||||
transport.(*http.Transport).TLSClientConfig = tlsClientConfig
|
|
||||||
cfg := elasticsearch.Config{
|
|
||||||
Addresses: []string{config.Url},
|
|
||||||
Username: config.User,
|
|
||||||
Password: config.Password,
|
|
||||||
Transport: transport,
|
|
||||||
}
|
|
||||||
|
|
||||||
es, err := elasticsearch.NewClient(cfg)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Errorf("Failed to initialize elastic client %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Have the client instance return a response
|
|
||||||
res, err := es.Info()
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Errorf("Elastic client.Info() ERROR: %v", err)
|
|
||||||
} else {
|
|
||||||
client.es = es
|
|
||||||
client.index = "mizu_traffic_http_" + time.Now().Format("2006_01_02_15_04")
|
|
||||||
client.insertedCount = 0
|
|
||||||
logger.Log.Infof("Elastic client configured, index: %s, cluster info: %v", client.index, res)
|
|
||||||
}
|
|
||||||
defer res.Body.Close()
|
|
||||||
}
|
|
||||||
|
|
||||||
func newClient() *client {
|
|
||||||
return &client{
|
|
||||||
es: nil,
|
|
||||||
index: "",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
type httpEntry struct {
|
|
||||||
Source *api.TCP `json:"src"`
|
|
||||||
Destination *api.TCP `json:"dst"`
|
|
||||||
Outgoing bool `json:"outgoing"`
|
|
||||||
CreatedAt time.Time `json:"createdAt"`
|
|
||||||
Request map[string]interface{} `json:"request"`
|
|
||||||
Response map[string]interface{} `json:"response"`
|
|
||||||
ElapsedTime int64 `json:"elapsedTime"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func (client *client) PushEntry(entry *api.Entry) {
|
|
||||||
if client.es == nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if entry.Protocol.Name != "http" {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
entryToPush := httpEntry{
|
|
||||||
Source: entry.Source,
|
|
||||||
Destination: entry.Destination,
|
|
||||||
Outgoing: entry.Outgoing,
|
|
||||||
CreatedAt: entry.StartTime,
|
|
||||||
Request: entry.Request,
|
|
||||||
Response: entry.Response,
|
|
||||||
ElapsedTime: entry.ElapsedTime,
|
|
||||||
}
|
|
||||||
|
|
||||||
entryJson, err := json.Marshal(entryToPush)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Errorf("json.Marshal ERROR: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
var buffer bytes.Buffer
|
|
||||||
buffer.WriteString(string(entryJson))
|
|
||||||
res, _ := client.es.Index(client.index, &buffer)
|
|
||||||
if res.StatusCode == 201 {
|
|
||||||
client.insertedCount += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -3,11 +3,11 @@ package entries
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
basenine "github.com/up9inc/basenine/client/go"
|
basenine "github.com/up9inc/basenine/client/go"
|
||||||
"github.com/up9inc/mizu/agent/pkg/app"
|
"github.com/up9inc/mizu/agent/pkg/app"
|
||||||
"github.com/up9inc/mizu/agent/pkg/har"
|
|
||||||
"github.com/up9inc/mizu/agent/pkg/models"
|
"github.com/up9inc/mizu/agent/pkg/models"
|
||||||
"github.com/up9inc/mizu/logger"
|
"github.com/up9inc/mizu/logger"
|
||||||
"github.com/up9inc/mizu/shared"
|
"github.com/up9inc/mizu/shared"
|
||||||
@@ -22,7 +22,7 @@ type EntriesProvider interface {
|
|||||||
type BasenineEntriesProvider struct{}
|
type BasenineEntriesProvider struct{}
|
||||||
|
|
||||||
func (e *BasenineEntriesProvider) GetEntries(entriesRequest *models.EntriesRequest) ([]*tapApi.EntryWrapper, *basenine.Metadata, error) {
|
func (e *BasenineEntriesProvider) GetEntries(entriesRequest *models.EntriesRequest) ([]*tapApi.EntryWrapper, *basenine.Metadata, error) {
|
||||||
data, meta, err := basenine.Fetch(shared.BasenineHost, shared.BaseninePort,
|
data, _, lastMeta, err := basenine.Fetch(shared.BasenineHost, shared.BaseninePort,
|
||||||
entriesRequest.LeftOff, entriesRequest.Direction, entriesRequest.Query,
|
entriesRequest.LeftOff, entriesRequest.Direction, entriesRequest.Query,
|
||||||
entriesRequest.Limit, time.Duration(entriesRequest.TimeoutMs)*time.Millisecond)
|
entriesRequest.Limit, time.Duration(entriesRequest.TimeoutMs)*time.Millisecond)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -38,18 +38,27 @@ func (e *BasenineEntriesProvider) GetEntries(entriesRequest *models.EntriesReque
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
extension := app.ExtensionsMap[entry.Protocol.Name]
|
protocol, ok := app.ProtocolsMap[entry.ProtocolId]
|
||||||
|
if !ok {
|
||||||
|
return nil, nil, fmt.Errorf("protocol not found, protocol: %v", protocol)
|
||||||
|
}
|
||||||
|
|
||||||
|
extension, ok := app.ExtensionsMap[protocol.Name]
|
||||||
|
if !ok {
|
||||||
|
return nil, nil, fmt.Errorf("extension not found, extension: %v", protocol.Name)
|
||||||
|
}
|
||||||
|
|
||||||
base := extension.Dissector.Summarize(entry)
|
base := extension.Dissector.Summarize(entry)
|
||||||
|
|
||||||
dataSlice = append(dataSlice, &tapApi.EntryWrapper{
|
dataSlice = append(dataSlice, &tapApi.EntryWrapper{
|
||||||
Protocol: entry.Protocol,
|
Protocol: *protocol,
|
||||||
Data: entry,
|
Data: entry,
|
||||||
Base: base,
|
Base: base,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
var metadata *basenine.Metadata
|
var metadata *basenine.Metadata
|
||||||
err = json.Unmarshal(meta, &metadata)
|
err = json.Unmarshal(lastMeta, &metadata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Log.Debugf("Error recieving metadata: %v", err.Error())
|
logger.Log.Debugf("Error recieving metadata: %v", err.Error())
|
||||||
}
|
}
|
||||||
@@ -68,7 +77,16 @@ func (e *BasenineEntriesProvider) GetEntry(singleEntryRequest *models.SingleEntr
|
|||||||
return nil, errors.New(string(bytes))
|
return nil, errors.New(string(bytes))
|
||||||
}
|
}
|
||||||
|
|
||||||
extension := app.ExtensionsMap[entry.Protocol.Name]
|
protocol, ok := app.ProtocolsMap[entry.ProtocolId]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("protocol not found, protocol: %v", protocol)
|
||||||
|
}
|
||||||
|
|
||||||
|
extension, ok := app.ExtensionsMap[protocol.Name]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("extension not found, extension: %v", protocol.Name)
|
||||||
|
}
|
||||||
|
|
||||||
base := extension.Dissector.Summarize(entry)
|
base := extension.Dissector.Summarize(entry)
|
||||||
var representation []byte
|
var representation []byte
|
||||||
representation, err = extension.Dissector.Represent(entry.Request, entry.Response)
|
representation, err = extension.Dissector.Represent(entry.Request, entry.Response)
|
||||||
@@ -76,24 +94,10 @@ func (e *BasenineEntriesProvider) GetEntry(singleEntryRequest *models.SingleEntr
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var rules []map[string]interface{}
|
|
||||||
var isRulesEnabled bool
|
|
||||||
if entry.Protocol.Name == "http" {
|
|
||||||
harEntry, _ := har.NewEntry(entry.Request, entry.Response, entry.StartTime, entry.ElapsedTime)
|
|
||||||
_, rulesMatched, _isRulesEnabled := models.RunValidationRulesState(*harEntry, entry.Destination.Name)
|
|
||||||
isRulesEnabled = _isRulesEnabled
|
|
||||||
inrec, _ := json.Marshal(rulesMatched)
|
|
||||||
if err := json.Unmarshal(inrec, &rules); err != nil {
|
|
||||||
logger.Log.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return &tapApi.EntryWrapper{
|
return &tapApi.EntryWrapper{
|
||||||
Protocol: entry.Protocol,
|
Protocol: *protocol,
|
||||||
Representation: string(representation),
|
Representation: string(representation),
|
||||||
Data: entry,
|
Data: entry,
|
||||||
Base: base,
|
Base: base,
|
||||||
Rules: rules,
|
|
||||||
IsRulesEnabled: isRulesEnabled,
|
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -124,8 +124,8 @@ func NewRequest(request map[string]interface{}) (harRequest *Request, err error)
|
|||||||
|
|
||||||
postData, _ := request["postData"].(map[string]interface{})
|
postData, _ := request["postData"].(map[string]interface{})
|
||||||
mimeType := postData["mimeType"]
|
mimeType := postData["mimeType"]
|
||||||
if mimeType == nil || len(mimeType.(string)) == 0 {
|
if mimeType == nil {
|
||||||
mimeType = "text/html"
|
mimeType = ""
|
||||||
}
|
}
|
||||||
text := postData["text"]
|
text := postData["text"]
|
||||||
postDataText := ""
|
postDataText := ""
|
||||||
@@ -177,8 +177,8 @@ func NewResponse(response map[string]interface{}) (harResponse *Response, err er
|
|||||||
|
|
||||||
content, _ := response["content"].(map[string]interface{})
|
content, _ := response["content"].(map[string]interface{})
|
||||||
mimeType := content["mimeType"]
|
mimeType := content["mimeType"]
|
||||||
if mimeType == nil || len(mimeType.(string)) == 0 {
|
if mimeType == nil {
|
||||||
mimeType = "text/html"
|
mimeType = ""
|
||||||
}
|
}
|
||||||
encoding := content["encoding"]
|
encoding := content["encoding"]
|
||||||
text := content["text"]
|
text := content["text"]
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
|
||||||
"github.com/up9inc/mizu/agent/pkg/har"
|
"github.com/up9inc/mizu/agent/pkg/har"
|
||||||
"github.com/up9inc/mizu/agent/pkg/rules"
|
|
||||||
tapApi "github.com/up9inc/mizu/tap/api"
|
tapApi "github.com/up9inc/mizu/tap/api"
|
||||||
|
|
||||||
basenine "github.com/up9inc/basenine/client/go"
|
basenine "github.com/up9inc/basenine/client/go"
|
||||||
@@ -43,11 +42,6 @@ type WebSocketTappedEntryMessage struct {
|
|||||||
Data *tapApi.OutputChannelItem
|
Data *tapApi.OutputChannelItem
|
||||||
}
|
}
|
||||||
|
|
||||||
type AuthStatus struct {
|
|
||||||
Email string `json:"email"`
|
|
||||||
Model string `json:"model"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ToastMessage struct {
|
type ToastMessage struct {
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
AutoClose uint `json:"autoClose"`
|
AutoClose uint `json:"autoClose"`
|
||||||
@@ -148,9 +142,3 @@ type ExtendedCreator struct {
|
|||||||
*har.Creator
|
*har.Creator
|
||||||
Source *string `json:"_source"`
|
Source *string `json:"_source"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func RunValidationRulesState(harEntry har.Entry, service string) (tapApi.ApplicableRules, []rules.RulesMatched, bool) {
|
|
||||||
resultPolicyToSend, isEnabled := rules.MatchRequestPolicy(harEntry, service)
|
|
||||||
statusPolicyToSend, latency, numberOfRules := rules.PassedValidationRules(resultPolicyToSend)
|
|
||||||
return tapApi.ApplicableRules{Status: statusPolicyToSend, Latency: latency, NumberOfRules: numberOfRules}, resultPolicyToSend, isEnabled
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ var ignoredCtypes = []string{"application/javascript", "application/x-javascript
|
|||||||
|
|
||||||
var ignoredHeaders = []string{
|
var ignoredHeaders = []string{
|
||||||
"a-im", "accept",
|
"a-im", "accept",
|
||||||
"authorization", "cache-control", "connection", "content-encoding", "content-length", "content-type", "cookie",
|
"authorization", "cache-control", "connection", "content-encoding", "content-length", "content-range", "content-type", "cookie",
|
||||||
"date", "dnt", "expect", "forwarded", "from", "front-end-https", "host", "http2-settings",
|
"date", "dnt", "expect", "forwarded", "from", "front-end-https", "host", "http2-settings",
|
||||||
"max-forwards", "origin", "pragma", "proxy-authorization", "proxy-connection", "range", "referer",
|
"max-forwards", "origin", "pragma", "proxy-authorization", "proxy-connection", "range", "referer",
|
||||||
"save-data", "te", "trailer", "transfer-encoding", "upgrade", "upgrade-insecure-requests", "x-download-options",
|
"save-data", "te", "trailer", "transfer-encoding", "upgrade", "upgrade-insecure-requests", "x-download-options",
|
||||||
|
|||||||
@@ -1,17 +1,13 @@
|
|||||||
package oas
|
package oas
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/url"
|
"net/url"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
basenine "github.com/up9inc/basenine/client/go"
|
|
||||||
"github.com/up9inc/mizu/agent/pkg/har"
|
"github.com/up9inc/mizu/agent/pkg/har"
|
||||||
"github.com/up9inc/mizu/shared"
|
|
||||||
"github.com/up9inc/mizu/tap/api"
|
|
||||||
|
|
||||||
"github.com/up9inc/mizu/logger"
|
"github.com/up9inc/mizu/logger"
|
||||||
|
"github.com/up9inc/mizu/tap/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -19,129 +15,55 @@ var (
|
|||||||
instance *defaultOasGenerator
|
instance *defaultOasGenerator
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type OasGeneratorSink interface {
|
||||||
|
HandleEntry(mizuEntry *api.Entry, protocol *api.Protocol)
|
||||||
|
}
|
||||||
|
|
||||||
type OasGenerator interface {
|
type OasGenerator interface {
|
||||||
Start(conn *basenine.Connection)
|
Start()
|
||||||
Stop()
|
Stop()
|
||||||
IsStarted() bool
|
IsStarted() bool
|
||||||
GetServiceSpecs() *sync.Map
|
GetServiceSpecs() *sync.Map
|
||||||
SetEntriesQuery(query string) bool
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type defaultOasGenerator struct {
|
type defaultOasGenerator struct {
|
||||||
started bool
|
started bool
|
||||||
ctx context.Context
|
serviceSpecs *sync.Map
|
||||||
cancel context.CancelFunc
|
maxExampleLen int
|
||||||
serviceSpecs *sync.Map
|
|
||||||
dbConn *basenine.Connection
|
|
||||||
dbMutex sync.Mutex
|
|
||||||
entriesQuery string
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetDefaultOasGeneratorInstance() *defaultOasGenerator {
|
func GetDefaultOasGeneratorInstance(maxExampleLen int) *defaultOasGenerator {
|
||||||
syncOnce.Do(func() {
|
syncOnce.Do(func() {
|
||||||
instance = NewDefaultOasGenerator()
|
instance = NewDefaultOasGenerator(maxExampleLen)
|
||||||
logger.Log.Debug("OAS Generator Initialized")
|
logger.Log.Debug("OAS Generator Initialized")
|
||||||
})
|
})
|
||||||
return instance
|
return instance
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *defaultOasGenerator) Start(conn *basenine.Connection) {
|
func (g *defaultOasGenerator) Start() {
|
||||||
if g.started {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if g.dbConn == nil {
|
|
||||||
if conn == nil {
|
|
||||||
logger.Log.Infof("Creating new DB connection for OAS generator to address %s:%s", shared.BasenineHost, shared.BaseninePort)
|
|
||||||
newConn, err := basenine.NewConnection(shared.BasenineHost, shared.BaseninePort)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Error("Error connecting to DB for OAS generator, err: %v", err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
conn = newConn
|
|
||||||
}
|
|
||||||
|
|
||||||
g.dbConn = conn
|
|
||||||
}
|
|
||||||
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
|
||||||
g.cancel = cancel
|
|
||||||
g.ctx = ctx
|
|
||||||
g.serviceSpecs = &sync.Map{}
|
|
||||||
|
|
||||||
g.started = true
|
g.started = true
|
||||||
|
|
||||||
go g.runGenerator()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *defaultOasGenerator) Stop() {
|
func (g *defaultOasGenerator) Stop() {
|
||||||
if !g.started {
|
if !g.started {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
g.started = false
|
g.started = false
|
||||||
|
|
||||||
g.cancel()
|
|
||||||
g.reset()
|
g.reset()
|
||||||
|
|
||||||
g.dbMutex.Lock()
|
|
||||||
defer g.dbMutex.Unlock()
|
|
||||||
if g.dbConn != nil {
|
|
||||||
g.dbConn.Close()
|
|
||||||
g.dbConn = nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *defaultOasGenerator) IsStarted() bool {
|
func (g *defaultOasGenerator) IsStarted() bool {
|
||||||
return g.started
|
return g.started
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *defaultOasGenerator) runGenerator() {
|
func (g *defaultOasGenerator) HandleEntry(mizuEntry *api.Entry, protocol *api.Protocol) {
|
||||||
// Make []byte channels to receive the data and the meta
|
if !g.started {
|
||||||
dataChan := make(chan []byte)
|
return
|
||||||
metaChan := make(chan []byte)
|
|
||||||
|
|
||||||
g.dbMutex.Lock()
|
|
||||||
defer g.dbMutex.Unlock()
|
|
||||||
logger.Log.Infof("Querying DB for OAS generator with query '%s'", g.entriesQuery)
|
|
||||||
if err := g.dbConn.Query(g.entriesQuery, dataChan, metaChan); err != nil {
|
|
||||||
logger.Log.Errorf("Query mode call failed: %v", err)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for {
|
if protocol.Name == "http" {
|
||||||
select {
|
|
||||||
case <-g.ctx.Done():
|
|
||||||
logger.Log.Infof("OAS Generator was canceled")
|
|
||||||
close(dataChan)
|
|
||||||
close(metaChan)
|
|
||||||
return
|
|
||||||
|
|
||||||
case metaBytes, ok := <-metaChan:
|
|
||||||
if !ok {
|
|
||||||
logger.Log.Infof("OAS Generator - meta channel closed")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
logger.Log.Debugf("Meta: %s", metaBytes)
|
|
||||||
|
|
||||||
case dataBytes, ok := <-dataChan:
|
|
||||||
if !ok {
|
|
||||||
logger.Log.Infof("OAS Generator - entries channel closed")
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Log.Debugf("Data: %s", dataBytes)
|
|
||||||
e := new(api.Entry)
|
|
||||||
err := json.Unmarshal(dataBytes, e)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
g.handleEntry(e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (g *defaultOasGenerator) handleEntry(mizuEntry *api.Entry) {
|
|
||||||
if mizuEntry.Protocol.Name == "http" {
|
|
||||||
dest := mizuEntry.Destination.Name
|
dest := mizuEntry.Destination.Name
|
||||||
if dest == "" {
|
if dest == "" {
|
||||||
logger.Log.Debugf("OAS: Unresolved entry %d", mizuEntry.Id)
|
logger.Log.Debugf("OAS: Unresolved entry %d", mizuEntry.Id)
|
||||||
@@ -163,7 +85,7 @@ func (g *defaultOasGenerator) handleEntry(mizuEntry *api.Entry) {
|
|||||||
|
|
||||||
g.handleHARWithSource(entryWSource)
|
g.handleHARWithSource(entryWSource)
|
||||||
} else {
|
} else {
|
||||||
logger.Log.Debugf("OAS: Unsupported protocol in entry %d: %s", mizuEntry.Id, mizuEntry.Protocol.Name)
|
logger.Log.Debugf("OAS: Unsupported protocol in entry %d: %s", mizuEntry.Id, protocol.Name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,6 +117,7 @@ func (g *defaultOasGenerator) getGen(dest string, urlStr string) *SpecGen {
|
|||||||
var gen *SpecGen
|
var gen *SpecGen
|
||||||
if !found {
|
if !found {
|
||||||
gen = NewGen(u.Scheme + "://" + dest)
|
gen = NewGen(u.Scheme + "://" + dest)
|
||||||
|
gen.MaxExampleLen = g.maxExampleLen
|
||||||
g.serviceSpecs.Store(dest, gen)
|
g.serviceSpecs.Store(dest, gen)
|
||||||
} else {
|
} else {
|
||||||
gen = val.(*SpecGen)
|
gen = val.(*SpecGen)
|
||||||
@@ -210,18 +133,10 @@ func (g *defaultOasGenerator) GetServiceSpecs() *sync.Map {
|
|||||||
return g.serviceSpecs
|
return g.serviceSpecs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *defaultOasGenerator) SetEntriesQuery(query string) bool {
|
func NewDefaultOasGenerator(maxExampleLen int) *defaultOasGenerator {
|
||||||
changed := g.entriesQuery != query
|
|
||||||
g.entriesQuery = query
|
|
||||||
return changed
|
|
||||||
}
|
|
||||||
|
|
||||||
func NewDefaultOasGenerator() *defaultOasGenerator {
|
|
||||||
return &defaultOasGenerator{
|
return &defaultOasGenerator{
|
||||||
started: false,
|
started: false,
|
||||||
ctx: nil,
|
serviceSpecs: &sync.Map{},
|
||||||
cancel: nil,
|
maxExampleLen: maxExampleLen,
|
||||||
serviceSpecs: nil,
|
|
||||||
dbConn: nil,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestOASGen(t *testing.T) {
|
func TestOASGen(t *testing.T) {
|
||||||
gen := new(defaultOasGenerator)
|
gen := GetDefaultOasGeneratorInstance(-1)
|
||||||
|
|
||||||
e := new(har.Entry)
|
e := new(har.Entry)
|
||||||
err := json.Unmarshal([]byte(`{"startedDateTime": "20000101","request": {"url": "https://host/path", "method": "GET"}, "response": {"status": 200}}`), e)
|
err := json.Unmarshal([]byte(`{"startedDateTime": "20000101","request": {"url": "https://host/path", "method": "GET"}, "response": {"status": 200}}`), e)
|
||||||
@@ -21,8 +21,7 @@ func TestOASGen(t *testing.T) {
|
|||||||
Entry: *e,
|
Entry: *e,
|
||||||
}
|
}
|
||||||
|
|
||||||
dummyConn := GetFakeDBConn(`{"startedDateTime": "20000101","request": {"url": "https://host/path", "method": "GET"}, "response": {"status": 200}}`)
|
gen.Start()
|
||||||
gen.Start(dummyConn)
|
|
||||||
gen.handleHARWithSource(ews)
|
gen.handleHARWithSource(ews)
|
||||||
g, ok := gen.serviceSpecs.Load("some")
|
g, ok := gen.serviceSpecs.Load("some")
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ type reqResp struct { // hello, generics in Go
|
|||||||
}
|
}
|
||||||
|
|
||||||
type SpecGen struct {
|
type SpecGen struct {
|
||||||
|
MaxExampleLen int // -1 unlimited, 0 and above sets limit
|
||||||
|
|
||||||
oas *openapi.OpenAPI
|
oas *openapi.OpenAPI
|
||||||
tree *Node
|
tree *Node
|
||||||
lock sync.Mutex
|
lock sync.Mutex
|
||||||
@@ -59,7 +61,11 @@ func NewGen(server string) *SpecGen {
|
|||||||
spec.Servers = make([]*openapi.Server, 0)
|
spec.Servers = make([]*openapi.Server, 0)
|
||||||
spec.Servers = append(spec.Servers, &openapi.Server{URL: server})
|
spec.Servers = append(spec.Servers, &openapi.Server{URL: server})
|
||||||
|
|
||||||
gen := SpecGen{oas: spec, tree: new(Node)}
|
gen := SpecGen{
|
||||||
|
oas: spec,
|
||||||
|
tree: new(Node),
|
||||||
|
MaxExampleLen: -1,
|
||||||
|
}
|
||||||
return &gen
|
return &gen
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,7 +234,7 @@ func (g *SpecGen) handlePathObj(entryWithSource *EntryWithSource) (string, error
|
|||||||
split = strings.Split(urlParsed.Path, "/")
|
split = strings.Split(urlParsed.Path, "/")
|
||||||
}
|
}
|
||||||
node := g.tree.getOrSet(split, new(openapi.PathObj), entryWithSource.Id)
|
node := g.tree.getOrSet(split, new(openapi.PathObj), entryWithSource.Id)
|
||||||
opObj, err := handleOpObj(entryWithSource, node.pathObj)
|
opObj, err := handleOpObj(entryWithSource, node.pathObj, g.MaxExampleLen)
|
||||||
|
|
||||||
if opObj != nil {
|
if opObj != nil {
|
||||||
return opObj.OperationID, err
|
return opObj.OperationID, err
|
||||||
@@ -237,7 +243,7 @@ func (g *SpecGen) handlePathObj(entryWithSource *EntryWithSource) (string, error
|
|||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleOpObj(entryWithSource *EntryWithSource, pathObj *openapi.PathObj) (*openapi.Operation, error) {
|
func handleOpObj(entryWithSource *EntryWithSource, pathObj *openapi.PathObj, limit int) (*openapi.Operation, error) {
|
||||||
entry := entryWithSource.Entry
|
entry := entryWithSource.Entry
|
||||||
isSuccess := 100 <= entry.Response.Status && entry.Response.Status < 400
|
isSuccess := 100 <= entry.Response.Status && entry.Response.Status < 400
|
||||||
opObj, wasMissing, err := getOpObj(pathObj, entry.Request.Method, isSuccess)
|
opObj, wasMissing, err := getOpObj(pathObj, entry.Request.Method, isSuccess)
|
||||||
@@ -250,12 +256,12 @@ func handleOpObj(entryWithSource *EntryWithSource, pathObj *openapi.PathObj) (*o
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err = handleRequest(&entry.Request, opObj, isSuccess, entryWithSource.Id)
|
err = handleRequest(&entry.Request, opObj, isSuccess, entryWithSource.Id, limit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = handleResponse(&entry.Response, opObj, isSuccess, entryWithSource.Id)
|
err = handleResponse(&entry.Response, opObj, isSuccess, entryWithSource.Id, limit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -342,7 +348,7 @@ func handleCounters(opObj *openapi.Operation, success bool, entryWithSource *Ent
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleRequest(req *har.Request, opObj *openapi.Operation, isSuccess bool, sampleId string) error {
|
func handleRequest(req *har.Request, opObj *openapi.Operation, isSuccess bool, sampleId string, limit int) error {
|
||||||
// TODO: we don't handle the situation when header/qstr param can be defined on pathObj level. Also the path param defined on opObj
|
// TODO: we don't handle the situation when header/qstr param can be defined on pathObj level. Also the path param defined on opObj
|
||||||
urlParsed, err := url.Parse(req.URL)
|
urlParsed, err := url.Parse(req.URL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -390,7 +396,7 @@ func handleRequest(req *har.Request, opObj *openapi.Operation, isSuccess bool, s
|
|||||||
} else {
|
} else {
|
||||||
|
|
||||||
reqCtype, _ := getReqCtype(req)
|
reqCtype, _ := getReqCtype(req)
|
||||||
reqMedia, err := fillContent(reqResp{Req: req}, reqBody.Content, reqCtype, sampleId)
|
reqMedia, err := fillContent(reqResp{Req: req}, reqBody.Content, reqCtype, sampleId, limit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -402,7 +408,7 @@ func handleRequest(req *har.Request, opObj *openapi.Operation, isSuccess bool, s
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleResponse(resp *har.Response, opObj *openapi.Operation, isSuccess bool, sampleId string) error {
|
func handleResponse(resp *har.Response, opObj *openapi.Operation, isSuccess bool, sampleId string, limit int) error {
|
||||||
// TODO: we don't support "default" response
|
// TODO: we don't support "default" response
|
||||||
respObj, err := getResponseObj(resp, opObj, isSuccess)
|
respObj, err := getResponseObj(resp, opObj, isSuccess)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -415,7 +421,7 @@ func handleResponse(resp *har.Response, opObj *openapi.Operation, isSuccess bool
|
|||||||
|
|
||||||
respCtype := getRespCtype(resp)
|
respCtype := getRespCtype(resp)
|
||||||
respContent := respObj.Content
|
respContent := respObj.Content
|
||||||
respMedia, err := fillContent(reqResp{Resp: resp}, respContent, respCtype, sampleId)
|
respMedia, err := fillContent(reqResp{Resp: resp}, respContent, respCtype, sampleId, limit)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -467,7 +473,7 @@ func handleRespHeaders(reqHeaders []har.Header, respObj *openapi.ResponseObj, sa
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fillContent(reqResp reqResp, respContent openapi.Content, ctype string, sampleId string) (*openapi.MediaType, error) {
|
func fillContent(reqResp reqResp, respContent openapi.Content, ctype string, sampleId string, limit int) (*openapi.MediaType, error) {
|
||||||
content, found := respContent[ctype]
|
content, found := respContent[ctype]
|
||||||
if !found {
|
if !found {
|
||||||
respContent[ctype] = &openapi.MediaType{}
|
respContent[ctype] = &openapi.MediaType{}
|
||||||
@@ -510,7 +516,7 @@ func fillContent(reqResp reqResp, respContent openapi.Content, ctype string, sam
|
|||||||
handleFormDataMultipart(text, content, params)
|
handleFormDataMultipart(text, content, params)
|
||||||
}
|
}
|
||||||
|
|
||||||
if content.Example == nil && len(exampleMsg) > len(content.Example) {
|
if len(exampleMsg) > len(content.Example) && (limit < 0 || len(exampleMsg) <= limit) {
|
||||||
content.Example = exampleMsg
|
content.Example = exampleMsg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
package oas
|
package oas
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net"
|
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -13,22 +11,11 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/chanced/openapi"
|
"github.com/chanced/openapi"
|
||||||
|
"github.com/up9inc/mizu/agent/pkg/har"
|
||||||
"github.com/up9inc/mizu/logger"
|
"github.com/up9inc/mizu/logger"
|
||||||
"github.com/wI2L/jsondiff"
|
"github.com/wI2L/jsondiff"
|
||||||
|
|
||||||
basenine "github.com/up9inc/basenine/client/go"
|
|
||||||
"github.com/up9inc/mizu/agent/pkg/har"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetFakeDBConn(send string) *basenine.Connection {
|
|
||||||
dummyConn := new(basenine.Connection)
|
|
||||||
dummyConn.Conn = FakeConn{
|
|
||||||
sendBuffer: bytes.NewBufferString(send),
|
|
||||||
receiveBuffer: bytes.NewBufferString(""),
|
|
||||||
}
|
|
||||||
return dummyConn
|
|
||||||
}
|
|
||||||
|
|
||||||
// if started via env, write file into subdir
|
// if started via env, write file into subdir
|
||||||
func outputSpec(label string, spec *openapi.OpenAPI, t *testing.T) string {
|
func outputSpec(label string, spec *openapi.OpenAPI, t *testing.T) string {
|
||||||
content, err := json.MarshalIndent(spec, "", " ")
|
content, err := json.MarshalIndent(spec, "", " ")
|
||||||
@@ -61,7 +48,7 @@ func TestEntries(t *testing.T) {
|
|||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
|
|
||||||
gen := NewDefaultOasGenerator()
|
gen := NewDefaultOasGenerator(-1)
|
||||||
gen.serviceSpecs = new(sync.Map)
|
gen.serviceSpecs = new(sync.Map)
|
||||||
loadStartingOAS("test_artifacts/catalogue.json", "catalogue", gen.serviceSpecs)
|
loadStartingOAS("test_artifacts/catalogue.json", "catalogue", gen.serviceSpecs)
|
||||||
loadStartingOAS("test_artifacts/trcc.json", "trcc-api-service", gen.serviceSpecs)
|
loadStartingOAS("test_artifacts/trcc.json", "trcc-api-service", gen.serviceSpecs)
|
||||||
@@ -135,7 +122,7 @@ func TestEntries(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFileSingle(t *testing.T) {
|
func TestFileSingle(t *testing.T) {
|
||||||
gen := NewDefaultOasGenerator()
|
gen := NewDefaultOasGenerator(-1)
|
||||||
gen.serviceSpecs = new(sync.Map)
|
gen.serviceSpecs = new(sync.Map)
|
||||||
// loadStartingOAS()
|
// loadStartingOAS()
|
||||||
file := "test_artifacts/params.har"
|
file := "test_artifacts/params.har"
|
||||||
@@ -225,7 +212,7 @@ func loadStartingOAS(file string, label string, specs *sync.Map) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestEntriesNegative(t *testing.T) {
|
func TestEntriesNegative(t *testing.T) {
|
||||||
gen := NewDefaultOasGenerator()
|
gen := NewDefaultOasGenerator(-1)
|
||||||
gen.serviceSpecs = new(sync.Map)
|
gen.serviceSpecs = new(sync.Map)
|
||||||
files := []string{"invalid"}
|
files := []string{"invalid"}
|
||||||
_, err := feedEntries(files, false, gen)
|
_, err := feedEntries(files, false, gen)
|
||||||
@@ -236,7 +223,7 @@ func TestEntriesNegative(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestEntriesPositive(t *testing.T) {
|
func TestEntriesPositive(t *testing.T) {
|
||||||
gen := NewDefaultOasGenerator()
|
gen := NewDefaultOasGenerator(-1)
|
||||||
gen.serviceSpecs = new(sync.Map)
|
gen.serviceSpecs = new(sync.Map)
|
||||||
files := []string{"test_artifacts/params.har"}
|
files := []string{"test_artifacts/params.har"}
|
||||||
_, err := feedEntries(files, false, gen)
|
_, err := feedEntries(files, false, gen)
|
||||||
@@ -278,17 +265,3 @@ func TestLoadValid3_1(t *testing.T) {
|
|||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type FakeConn struct {
|
|
||||||
sendBuffer *bytes.Buffer
|
|
||||||
receiveBuffer *bytes.Buffer
|
|
||||||
}
|
|
||||||
|
|
||||||
func (f FakeConn) Read(p []byte) (int, error) { return f.sendBuffer.Read(p) }
|
|
||||||
func (f FakeConn) Write(p []byte) (int, error) { return f.receiveBuffer.Write(p) }
|
|
||||||
func (FakeConn) Close() error { return nil }
|
|
||||||
func (FakeConn) LocalAddr() net.Addr { return nil }
|
|
||||||
func (FakeConn) RemoteAddr() net.Addr { return nil }
|
|
||||||
func (FakeConn) SetDeadline(t time.Time) error { return nil }
|
|
||||||
func (FakeConn) SetReadDeadline(t time.Time) error { return nil }
|
|
||||||
func (FakeConn) SetWriteDeadline(t time.Time) error { return nil }
|
|
||||||
|
|||||||
@@ -333,7 +333,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"example": "agent-id=ade\u0026callback-url=\u0026token=sometoken",
|
"example": "agent-id=ade\u0026callback-url=\u0026token=sometoken-second-val\u0026optional=another",
|
||||||
"x-sample-entry": "000000000000000000000008"
|
"x-sample-entry": "000000000000000000000008"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,8 +1,17 @@
|
|||||||
package providers
|
package providers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/md5"
|
||||||
|
"encoding/hex"
|
||||||
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/jinzhu/copier"
|
||||||
|
"github.com/up9inc/mizu/logger"
|
||||||
|
"github.com/up9inc/mizu/tap/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
type GeneralStats struct {
|
type GeneralStats struct {
|
||||||
@@ -12,17 +21,83 @@ type GeneralStats struct {
|
|||||||
LastEntryTimestamp int
|
LastEntryTimestamp int
|
||||||
}
|
}
|
||||||
|
|
||||||
var generalStats = GeneralStats{}
|
type BucketStats []*TimeFrameStatsValue
|
||||||
|
|
||||||
|
type TimeFrameStatsValue struct {
|
||||||
|
BucketTime time.Time `json:"timestamp"`
|
||||||
|
ProtocolStats map[string]ProtocolStats `json:"protocols"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProtocolStats struct {
|
||||||
|
MethodsStats map[string]*SizeAndEntriesCount `json:"methods"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type SizeAndEntriesCount struct {
|
||||||
|
EntriesCount int `json:"entriesCount"`
|
||||||
|
VolumeInBytes int `json:"volumeInBytes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccumulativeStatsCounter struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Color string `json:"color"`
|
||||||
|
EntriesCount int `json:"entriesCount"`
|
||||||
|
VolumeSizeBytes int `json:"volumeSizeBytes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccumulativeStatsProtocol struct {
|
||||||
|
AccumulativeStatsCounter
|
||||||
|
Methods []*AccumulativeStatsCounter `json:"methods"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type AccumulativeStatsProtocolTime struct {
|
||||||
|
ProtocolsData []*AccumulativeStatsProtocol `json:"protocols"`
|
||||||
|
Time int64 `json:"timestamp"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type TrafficStatsResponse struct {
|
||||||
|
Protocols []string `json:"protocols"`
|
||||||
|
PieStats []*AccumulativeStatsProtocol `json:"pie"`
|
||||||
|
TimelineStats []*AccumulativeStatsProtocolTime `json:"timeline"`
|
||||||
|
}
|
||||||
|
|
||||||
|
var (
|
||||||
|
generalStats = GeneralStats{}
|
||||||
|
bucketsStats = BucketStats{}
|
||||||
|
bucketStatsLocker = sync.Mutex{}
|
||||||
|
protocolToColor = map[string]string{}
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
InternalBucketThreshold = time.Minute * 1
|
||||||
|
MaxNumberOfBars = 30
|
||||||
|
)
|
||||||
|
|
||||||
func ResetGeneralStats() {
|
func ResetGeneralStats() {
|
||||||
generalStats = GeneralStats{}
|
generalStats = GeneralStats{}
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetGeneralStats() GeneralStats {
|
func GetGeneralStats() *GeneralStats {
|
||||||
return generalStats
|
return &generalStats
|
||||||
}
|
}
|
||||||
|
|
||||||
func EntryAdded(size int) {
|
func InitProtocolToColor(protocolMap map[string]*api.Protocol) {
|
||||||
|
for item, value := range protocolMap {
|
||||||
|
splitted := strings.SplitN(item, "/", 3)
|
||||||
|
protocolToColor[splitted[len(splitted)-1]] = value.BackgroundColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetTrafficStats() *TrafficStatsResponse {
|
||||||
|
bucketsStatsCopy := getBucketStatsCopy()
|
||||||
|
|
||||||
|
return &TrafficStatsResponse{
|
||||||
|
Protocols: getAvailableProtocols(bucketsStatsCopy),
|
||||||
|
PieStats: getAccumulativeStats(bucketsStatsCopy),
|
||||||
|
TimelineStats: getAccumulativeStatsTiming(bucketsStatsCopy),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func EntryAdded(size int, summery *api.BaseEntry) {
|
||||||
generalStats.EntriesCount++
|
generalStats.EntriesCount++
|
||||||
generalStats.EntriesVolumeInGB += float64(size) / (1 << 30)
|
generalStats.EntriesVolumeInGB += float64(size) / (1 << 30)
|
||||||
|
|
||||||
@@ -32,5 +107,251 @@ func EntryAdded(size int) {
|
|||||||
generalStats.FirstEntryTimestamp = currentTimestamp
|
generalStats.FirstEntryTimestamp = currentTimestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addToBucketStats(size, summery)
|
||||||
|
|
||||||
generalStats.LastEntryTimestamp = currentTimestamp
|
generalStats.LastEntryTimestamp = currentTimestamp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func calculateInterval(firstTimestamp int64, lastTimestamp int64) time.Duration {
|
||||||
|
validDurations := []time.Duration{
|
||||||
|
time.Minute,
|
||||||
|
time.Minute * 2,
|
||||||
|
time.Minute * 3,
|
||||||
|
time.Minute * 5,
|
||||||
|
time.Minute * 10,
|
||||||
|
time.Minute * 15,
|
||||||
|
time.Minute * 20,
|
||||||
|
time.Minute * 30,
|
||||||
|
time.Minute * 45,
|
||||||
|
time.Minute * 60,
|
||||||
|
time.Minute * 75,
|
||||||
|
time.Minute * 90, // 1.5 minutes
|
||||||
|
time.Minute * 120, // 2 hours
|
||||||
|
time.Minute * 150, // 2.5 hours
|
||||||
|
time.Minute * 180, // 3 hours
|
||||||
|
time.Minute * 240, // 4 hours
|
||||||
|
time.Minute * 300, // 5 hours
|
||||||
|
time.Minute * 360, // 6 hours
|
||||||
|
time.Minute * 420, // 7 hours
|
||||||
|
time.Minute * 480, // 8 hours
|
||||||
|
time.Minute * 540, // 9 hours
|
||||||
|
time.Minute * 600, // 10 hours
|
||||||
|
time.Minute * 660, // 11 hours
|
||||||
|
time.Minute * 720, // 12 hours
|
||||||
|
time.Minute * 1440, // 24 hours
|
||||||
|
}
|
||||||
|
duration := time.Duration(lastTimestamp-firstTimestamp) * time.Second / time.Duration(MaxNumberOfBars)
|
||||||
|
for _, validDuration := range validDurations {
|
||||||
|
if validDuration-duration >= 0 {
|
||||||
|
return validDuration
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return duration.Round(validDurations[len(validDurations)-1])
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAccumulativeStats(stats BucketStats) []*AccumulativeStatsProtocol {
|
||||||
|
if len(stats) == 0 {
|
||||||
|
return make([]*AccumulativeStatsProtocol, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
methodsPerProtocolAggregated := getAggregatedStats(stats)
|
||||||
|
|
||||||
|
return convertAccumulativeStatsDictToArray(methodsPerProtocolAggregated)
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAccumulativeStatsTiming(stats BucketStats) []*AccumulativeStatsProtocolTime {
|
||||||
|
if len(stats) == 0 {
|
||||||
|
return make([]*AccumulativeStatsProtocolTime, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
interval := calculateInterval(stats[0].BucketTime.Unix(), stats[len(stats)-1].BucketTime.Unix()) // in seconds
|
||||||
|
methodsPerProtocolPerTimeAggregated := getAggregatedResultTiming(stats, interval)
|
||||||
|
|
||||||
|
return convertAccumulativeStatsTimelineDictToArray(methodsPerProtocolPerTimeAggregated)
|
||||||
|
}
|
||||||
|
|
||||||
|
func addToBucketStats(size int, summery *api.BaseEntry) {
|
||||||
|
entryTimeBucketRounded := getBucketFromTimeStamp(summery.Timestamp)
|
||||||
|
|
||||||
|
if len(bucketsStats) == 0 {
|
||||||
|
bucketsStats = append(bucketsStats, &TimeFrameStatsValue{
|
||||||
|
BucketTime: entryTimeBucketRounded,
|
||||||
|
ProtocolStats: map[string]ProtocolStats{},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
bucketOfEntry := bucketsStats[len(bucketsStats)-1]
|
||||||
|
if bucketOfEntry.BucketTime != entryTimeBucketRounded {
|
||||||
|
bucketOfEntry = &TimeFrameStatsValue{
|
||||||
|
BucketTime: entryTimeBucketRounded,
|
||||||
|
ProtocolStats: map[string]ProtocolStats{},
|
||||||
|
}
|
||||||
|
bucketsStats = append(bucketsStats, bucketOfEntry)
|
||||||
|
}
|
||||||
|
if _, found := bucketOfEntry.ProtocolStats[summery.Protocol.Abbreviation]; !found {
|
||||||
|
bucketOfEntry.ProtocolStats[summery.Protocol.Abbreviation] = ProtocolStats{
|
||||||
|
MethodsStats: map[string]*SizeAndEntriesCount{},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if _, found := bucketOfEntry.ProtocolStats[summery.Protocol.Abbreviation].MethodsStats[summery.Method]; !found {
|
||||||
|
bucketOfEntry.ProtocolStats[summery.Protocol.Abbreviation].MethodsStats[summery.Method] = &SizeAndEntriesCount{
|
||||||
|
VolumeInBytes: 0,
|
||||||
|
EntriesCount: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bucketOfEntry.ProtocolStats[summery.Protocol.Abbreviation].MethodsStats[summery.Method].EntriesCount += 1
|
||||||
|
bucketOfEntry.ProtocolStats[summery.Protocol.Abbreviation].MethodsStats[summery.Method].VolumeInBytes += size
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBucketFromTimeStamp(timestamp int64) time.Time {
|
||||||
|
entryTimeStampAsTime := time.UnixMilli(timestamp)
|
||||||
|
return entryTimeStampAsTime.Add(-1 * InternalBucketThreshold / 2).Round(InternalBucketThreshold)
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertAccumulativeStatsTimelineDictToArray(methodsPerProtocolPerTimeAggregated map[time.Time]map[string]map[string]*AccumulativeStatsCounter) []*AccumulativeStatsProtocolTime {
|
||||||
|
finalResult := make([]*AccumulativeStatsProtocolTime, 0)
|
||||||
|
for timeKey, item := range methodsPerProtocolPerTimeAggregated {
|
||||||
|
protocolsData := make([]*AccumulativeStatsProtocol, 0)
|
||||||
|
for protocolName, value := range item {
|
||||||
|
entriesCount := 0
|
||||||
|
volumeSizeBytes := 0
|
||||||
|
methods := make([]*AccumulativeStatsCounter, 0)
|
||||||
|
for _, methodAccData := range value {
|
||||||
|
entriesCount += methodAccData.EntriesCount
|
||||||
|
volumeSizeBytes += methodAccData.VolumeSizeBytes
|
||||||
|
methods = append(methods, methodAccData)
|
||||||
|
}
|
||||||
|
protocolsData = append(protocolsData, &AccumulativeStatsProtocol{
|
||||||
|
AccumulativeStatsCounter: AccumulativeStatsCounter{
|
||||||
|
Name: protocolName,
|
||||||
|
Color: protocolToColor[protocolName],
|
||||||
|
EntriesCount: entriesCount,
|
||||||
|
VolumeSizeBytes: volumeSizeBytes,
|
||||||
|
},
|
||||||
|
Methods: methods,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
finalResult = append(finalResult, &AccumulativeStatsProtocolTime{
|
||||||
|
Time: timeKey.UnixMilli(),
|
||||||
|
ProtocolsData: protocolsData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return finalResult
|
||||||
|
}
|
||||||
|
|
||||||
|
func convertAccumulativeStatsDictToArray(methodsPerProtocolAggregated map[string]map[string]*AccumulativeStatsCounter) []*AccumulativeStatsProtocol {
|
||||||
|
protocolsData := make([]*AccumulativeStatsProtocol, 0)
|
||||||
|
for protocolName, value := range methodsPerProtocolAggregated {
|
||||||
|
entriesCount := 0
|
||||||
|
volumeSizeBytes := 0
|
||||||
|
methods := make([]*AccumulativeStatsCounter, 0)
|
||||||
|
for _, methodAccData := range value {
|
||||||
|
entriesCount += methodAccData.EntriesCount
|
||||||
|
volumeSizeBytes += methodAccData.VolumeSizeBytes
|
||||||
|
methods = append(methods, methodAccData)
|
||||||
|
}
|
||||||
|
protocolsData = append(protocolsData, &AccumulativeStatsProtocol{
|
||||||
|
AccumulativeStatsCounter: AccumulativeStatsCounter{
|
||||||
|
Name: protocolName,
|
||||||
|
Color: protocolToColor[protocolName],
|
||||||
|
EntriesCount: entriesCount,
|
||||||
|
VolumeSizeBytes: volumeSizeBytes,
|
||||||
|
},
|
||||||
|
Methods: methods,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return protocolsData
|
||||||
|
}
|
||||||
|
|
||||||
|
func getBucketStatsCopy() BucketStats {
|
||||||
|
bucketStatsCopy := BucketStats{}
|
||||||
|
bucketStatsLocker.Lock()
|
||||||
|
if err := copier.Copy(&bucketStatsCopy, bucketsStats); err != nil {
|
||||||
|
logger.Log.Errorf("Error while copying src stats into temporary copied object")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
bucketStatsLocker.Unlock()
|
||||||
|
return bucketStatsCopy
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAggregatedResultTiming(stats BucketStats, interval time.Duration) map[time.Time]map[string]map[string]*AccumulativeStatsCounter {
|
||||||
|
methodsPerProtocolPerTimeAggregated := map[time.Time]map[string]map[string]*AccumulativeStatsCounter{}
|
||||||
|
|
||||||
|
bucketStatsIndex := len(stats) - 1
|
||||||
|
for bucketStatsIndex >= 0 {
|
||||||
|
currentBucketTime := stats[bucketStatsIndex].BucketTime
|
||||||
|
resultBucketRoundedKey := currentBucketTime.Add(-1 * interval / 2).Round(interval)
|
||||||
|
|
||||||
|
for protocolName, data := range stats[bucketStatsIndex].ProtocolStats {
|
||||||
|
for methodName, dataOfMethod := range data.MethodsStats {
|
||||||
|
|
||||||
|
if _, ok := methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey]; !ok {
|
||||||
|
methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey] = map[string]map[string]*AccumulativeStatsCounter{}
|
||||||
|
}
|
||||||
|
if _, ok := methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey][protocolName]; !ok {
|
||||||
|
methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey][protocolName] = map[string]*AccumulativeStatsCounter{}
|
||||||
|
}
|
||||||
|
if _, ok := methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey][protocolName][methodName]; !ok {
|
||||||
|
methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey][protocolName][methodName] = &AccumulativeStatsCounter{
|
||||||
|
Name: methodName,
|
||||||
|
Color: getColorForMethod(protocolName, methodName),
|
||||||
|
EntriesCount: 0,
|
||||||
|
VolumeSizeBytes: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey][protocolName][methodName].EntriesCount += dataOfMethod.EntriesCount
|
||||||
|
methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey][protocolName][methodName].VolumeSizeBytes += dataOfMethod.VolumeInBytes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bucketStatsIndex--
|
||||||
|
}
|
||||||
|
return methodsPerProtocolPerTimeAggregated
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAggregatedStats(stats BucketStats) map[string]map[string]*AccumulativeStatsCounter {
|
||||||
|
methodsPerProtocolAggregated := make(map[string]map[string]*AccumulativeStatsCounter, 0)
|
||||||
|
for _, countersOfTimeFrame := range stats {
|
||||||
|
for protocolName, value := range countersOfTimeFrame.ProtocolStats {
|
||||||
|
for method, countersValue := range value.MethodsStats {
|
||||||
|
if _, found := methodsPerProtocolAggregated[protocolName]; !found {
|
||||||
|
methodsPerProtocolAggregated[protocolName] = map[string]*AccumulativeStatsCounter{}
|
||||||
|
}
|
||||||
|
if _, found := methodsPerProtocolAggregated[protocolName][method]; !found {
|
||||||
|
methodsPerProtocolAggregated[protocolName][method] = &AccumulativeStatsCounter{
|
||||||
|
Name: method,
|
||||||
|
Color: getColorForMethod(protocolName, method),
|
||||||
|
EntriesCount: 0,
|
||||||
|
VolumeSizeBytes: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
methodsPerProtocolAggregated[protocolName][method].EntriesCount += countersValue.EntriesCount
|
||||||
|
methodsPerProtocolAggregated[protocolName][method].VolumeSizeBytes += countersValue.VolumeInBytes
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return methodsPerProtocolAggregated
|
||||||
|
}
|
||||||
|
|
||||||
|
func getColorForMethod(protocolName string, methodName string) string {
|
||||||
|
hash := md5.Sum([]byte(fmt.Sprintf("%v_%v", protocolName, methodName)))
|
||||||
|
input := hex.EncodeToString(hash[:])
|
||||||
|
return fmt.Sprintf("#%v", input[:6])
|
||||||
|
}
|
||||||
|
|
||||||
|
func getAvailableProtocols(stats BucketStats) []string {
|
||||||
|
protocols := map[string]bool{}
|
||||||
|
for _, countersOfTimeFrame := range stats {
|
||||||
|
for protocolName := range countersOfTimeFrame.ProtocolStats {
|
||||||
|
protocols[protocolName] = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result := make([]string, 0)
|
||||||
|
for protocol := range protocols {
|
||||||
|
result = append(result, protocol)
|
||||||
|
}
|
||||||
|
result = append(result, "ALL")
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|||||||
298
agent/pkg/providers/stats_provider_internal_test.go
Normal file
298
agent/pkg/providers/stats_provider_internal_test.go
Normal file
@@ -0,0 +1,298 @@
|
|||||||
|
package providers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetBucketOfTimeStamp(t *testing.T) {
|
||||||
|
tests := map[int64]time.Time{
|
||||||
|
time.Date(2022, time.Month(1), 1, 10, 34, 45, 0, time.Local).UnixMilli(): time.Date(2022, time.Month(1), 1, 10, 34, 00, 0, time.Local),
|
||||||
|
time.Date(2022, time.Month(1), 1, 10, 34, 00, 0, time.Local).UnixMilli(): time.Date(2022, time.Month(1), 1, 10, 34, 00, 0, time.Local),
|
||||||
|
time.Date(2022, time.Month(1), 1, 10, 59, 01, 0, time.Local).UnixMilli(): time.Date(2022, time.Month(1), 1, 10, 59, 00, 0, time.Local),
|
||||||
|
}
|
||||||
|
|
||||||
|
for key, value := range tests {
|
||||||
|
t.Run(fmt.Sprintf("%v", key), func(t *testing.T) {
|
||||||
|
|
||||||
|
actual := getBucketFromTimeStamp(key)
|
||||||
|
|
||||||
|
if actual != value {
|
||||||
|
t.Errorf("unexpected result - expected: %v, actual: %v", value, actual)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetAggregatedStatsAllTime(t *testing.T) {
|
||||||
|
bucketStatsForTest := BucketStats{
|
||||||
|
&TimeFrameStatsValue{
|
||||||
|
BucketTime: time.Date(2022, time.Month(1), 1, 10, 00, 00, 0, time.UTC),
|
||||||
|
ProtocolStats: map[string]ProtocolStats{
|
||||||
|
"http": {
|
||||||
|
MethodsStats: map[string]*SizeAndEntriesCount{
|
||||||
|
"get": {
|
||||||
|
EntriesCount: 1,
|
||||||
|
VolumeInBytes: 2,
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
EntriesCount: 2,
|
||||||
|
VolumeInBytes: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"kafka": {
|
||||||
|
MethodsStats: map[string]*SizeAndEntriesCount{
|
||||||
|
"listTopics": {
|
||||||
|
EntriesCount: 5,
|
||||||
|
VolumeInBytes: 6,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&TimeFrameStatsValue{
|
||||||
|
BucketTime: time.Date(2022, time.Month(1), 1, 10, 01, 00, 0, time.UTC),
|
||||||
|
ProtocolStats: map[string]ProtocolStats{
|
||||||
|
"http": {
|
||||||
|
MethodsStats: map[string]*SizeAndEntriesCount{
|
||||||
|
"get": {
|
||||||
|
EntriesCount: 1,
|
||||||
|
VolumeInBytes: 2,
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
EntriesCount: 2,
|
||||||
|
VolumeInBytes: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"redis": {
|
||||||
|
MethodsStats: map[string]*SizeAndEntriesCount{
|
||||||
|
"set": {
|
||||||
|
EntriesCount: 5,
|
||||||
|
VolumeInBytes: 6,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := map[string]map[string]*AccumulativeStatsCounter{
|
||||||
|
"http": {
|
||||||
|
"post": {
|
||||||
|
Name: "post",
|
||||||
|
EntriesCount: 4,
|
||||||
|
VolumeSizeBytes: 6,
|
||||||
|
},
|
||||||
|
"get": {
|
||||||
|
Name: "get",
|
||||||
|
EntriesCount: 2,
|
||||||
|
VolumeSizeBytes: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"kafka": {
|
||||||
|
"listTopics": {
|
||||||
|
Name: "listTopics",
|
||||||
|
EntriesCount: 5,
|
||||||
|
VolumeSizeBytes: 6,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"redis": {
|
||||||
|
"set": {
|
||||||
|
Name: "set",
|
||||||
|
EntriesCount: 5,
|
||||||
|
VolumeSizeBytes: 6,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
actual := getAggregatedStats(bucketStatsForTest)
|
||||||
|
|
||||||
|
if len(actual) != len(expected) {
|
||||||
|
t.Errorf("unexpected result - expected: %v, actual: %v", len(expected), len(actual))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetAggregatedStatsFromSpecificTime(t *testing.T) {
|
||||||
|
bucketStatsForTest := BucketStats{
|
||||||
|
&TimeFrameStatsValue{
|
||||||
|
BucketTime: time.Date(2022, time.Month(1), 1, 10, 00, 00, 0, time.UTC),
|
||||||
|
ProtocolStats: map[string]ProtocolStats{
|
||||||
|
"http": {
|
||||||
|
MethodsStats: map[string]*SizeAndEntriesCount{
|
||||||
|
"get": {
|
||||||
|
EntriesCount: 1,
|
||||||
|
VolumeInBytes: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"kafka": {
|
||||||
|
MethodsStats: map[string]*SizeAndEntriesCount{
|
||||||
|
"listTopics": {
|
||||||
|
EntriesCount: 5,
|
||||||
|
VolumeInBytes: 6,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&TimeFrameStatsValue{
|
||||||
|
BucketTime: time.Date(2022, time.Month(1), 1, 10, 01, 00, 0, time.UTC),
|
||||||
|
ProtocolStats: map[string]ProtocolStats{
|
||||||
|
"http": {
|
||||||
|
MethodsStats: map[string]*SizeAndEntriesCount{
|
||||||
|
"get": {
|
||||||
|
EntriesCount: 1,
|
||||||
|
VolumeInBytes: 2,
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
EntriesCount: 2,
|
||||||
|
VolumeInBytes: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"redis": {
|
||||||
|
MethodsStats: map[string]*SizeAndEntriesCount{
|
||||||
|
"set": {
|
||||||
|
EntriesCount: 5,
|
||||||
|
VolumeInBytes: 6,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := map[time.Time]map[string]map[string]*AccumulativeStatsCounter{
|
||||||
|
time.Date(2022, time.Month(1), 1, 10, 00, 00, 0, time.UTC): {
|
||||||
|
"http": {
|
||||||
|
"post": {
|
||||||
|
Name: "post",
|
||||||
|
EntriesCount: 2,
|
||||||
|
VolumeSizeBytes: 3,
|
||||||
|
},
|
||||||
|
"get": {
|
||||||
|
Name: "get",
|
||||||
|
EntriesCount: 2,
|
||||||
|
VolumeSizeBytes: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"kafka": {
|
||||||
|
"listTopics": {
|
||||||
|
Name: "listTopics",
|
||||||
|
EntriesCount: 5,
|
||||||
|
VolumeSizeBytes: 6,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"redis": {
|
||||||
|
"set": {
|
||||||
|
Name: "set",
|
||||||
|
EntriesCount: 5,
|
||||||
|
VolumeSizeBytes: 6,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
actual := getAggregatedResultTiming(bucketStatsForTest, time.Minute*5)
|
||||||
|
|
||||||
|
if len(actual) != len(expected) {
|
||||||
|
t.Errorf("unexpected result - expected: %v, actual: %v", len(expected), len(actual))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestGetAggregatedStatsFromSpecificTimeMultipleBuckets(t *testing.T) {
|
||||||
|
bucketStatsForTest := BucketStats{
|
||||||
|
&TimeFrameStatsValue{
|
||||||
|
BucketTime: time.Date(2022, time.Month(1), 1, 10, 00, 00, 0, time.UTC),
|
||||||
|
ProtocolStats: map[string]ProtocolStats{
|
||||||
|
"http": {
|
||||||
|
MethodsStats: map[string]*SizeAndEntriesCount{
|
||||||
|
"get": {
|
||||||
|
EntriesCount: 1,
|
||||||
|
VolumeInBytes: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"kafka": {
|
||||||
|
MethodsStats: map[string]*SizeAndEntriesCount{
|
||||||
|
"listTopics": {
|
||||||
|
EntriesCount: 5,
|
||||||
|
VolumeInBytes: 6,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
&TimeFrameStatsValue{
|
||||||
|
BucketTime: time.Date(2022, time.Month(1), 1, 10, 01, 00, 0, time.UTC),
|
||||||
|
ProtocolStats: map[string]ProtocolStats{
|
||||||
|
"http": {
|
||||||
|
MethodsStats: map[string]*SizeAndEntriesCount{
|
||||||
|
"get": {
|
||||||
|
EntriesCount: 1,
|
||||||
|
VolumeInBytes: 2,
|
||||||
|
},
|
||||||
|
"post": {
|
||||||
|
EntriesCount: 2,
|
||||||
|
VolumeInBytes: 3,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"redis": {
|
||||||
|
MethodsStats: map[string]*SizeAndEntriesCount{
|
||||||
|
"set": {
|
||||||
|
EntriesCount: 5,
|
||||||
|
VolumeInBytes: 6,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expected := map[time.Time]map[string]map[string]*AccumulativeStatsCounter{
|
||||||
|
time.Date(2022, time.Month(1), 1, 10, 00, 00, 0, time.UTC): {
|
||||||
|
"http": {
|
||||||
|
"get": {
|
||||||
|
Name: "get",
|
||||||
|
EntriesCount: 1,
|
||||||
|
VolumeSizeBytes: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"kafka": {
|
||||||
|
"listTopics": {
|
||||||
|
Name: "listTopics",
|
||||||
|
EntriesCount: 5,
|
||||||
|
VolumeSizeBytes: 6,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
time.Date(2022, time.Month(1), 1, 10, 01, 00, 0, time.UTC): {
|
||||||
|
"http": {
|
||||||
|
"post": {
|
||||||
|
Name: "post",
|
||||||
|
EntriesCount: 2,
|
||||||
|
VolumeSizeBytes: 3,
|
||||||
|
},
|
||||||
|
"get": {
|
||||||
|
Name: "get",
|
||||||
|
EntriesCount: 1,
|
||||||
|
VolumeSizeBytes: 2,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"redis": {
|
||||||
|
"set": {
|
||||||
|
Name: "set",
|
||||||
|
EntriesCount: 5,
|
||||||
|
VolumeSizeBytes: 6,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
actual := getAggregatedResultTiming(bucketStatsForTest, time.Minute)
|
||||||
|
|
||||||
|
if len(actual) != len(expected) {
|
||||||
|
t.Errorf("unexpected result - expected: %v, actual: %v", len(expected), len(actual))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,8 +3,10 @@ package providers_test
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
"github.com/up9inc/mizu/agent/pkg/providers"
|
"github.com/up9inc/mizu/agent/pkg/providers"
|
||||||
|
"github.com/up9inc/mizu/tap/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestNoEntryAddedCount(t *testing.T) {
|
func TestNoEntryAddedCount(t *testing.T) {
|
||||||
@@ -22,10 +24,13 @@ func TestNoEntryAddedCount(t *testing.T) {
|
|||||||
func TestEntryAddedCount(t *testing.T) {
|
func TestEntryAddedCount(t *testing.T) {
|
||||||
tests := []int{1, 5, 10, 100, 500, 1000}
|
tests := []int{1, 5, 10, 100, 500, 1000}
|
||||||
|
|
||||||
|
entryBucketKey := time.Date(2021, 1, 1, 10, 0, 0, 0, time.UTC)
|
||||||
|
valueLessThanBucketThreshold := time.Second * 130
|
||||||
|
mockSummery := &api.BaseEntry{Protocol: api.Protocol{Name: "mock"}, Method: "mock-method", Timestamp: entryBucketKey.Add(valueLessThanBucketThreshold).UnixNano()}
|
||||||
for _, entriesCount := range tests {
|
for _, entriesCount := range tests {
|
||||||
t.Run(fmt.Sprintf("%d", entriesCount), func(t *testing.T) {
|
t.Run(fmt.Sprintf("%d", entriesCount), func(t *testing.T) {
|
||||||
for i := 0; i < entriesCount; i++ {
|
for i := 0; i < entriesCount; i++ {
|
||||||
providers.EntryAdded(0)
|
providers.EntryAdded(0, mockSummery)
|
||||||
}
|
}
|
||||||
|
|
||||||
entriesStats := providers.GetGeneralStats()
|
entriesStats := providers.GetGeneralStats()
|
||||||
@@ -38,7 +43,14 @@ func TestEntryAddedCount(t *testing.T) {
|
|||||||
t.Errorf("unexpected result - expected: %v, actual: %v", 0, entriesStats.EntriesVolumeInGB)
|
t.Errorf("unexpected result - expected: %v, actual: %v", 0, entriesStats.EntriesVolumeInGB)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Cleanup(providers.ResetGeneralStats)
|
t.Cleanup(func() {
|
||||||
|
providers.ResetGeneralStats()
|
||||||
|
generalStats := providers.GetGeneralStats()
|
||||||
|
if generalStats.EntriesCount != 0 {
|
||||||
|
t.Errorf("unexpected result - expected: %v, actual: %v", 0, generalStats.EntriesCount)
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49,12 +61,14 @@ func TestEntryAddedVolume(t *testing.T) {
|
|||||||
var expectedEntriesCount int
|
var expectedEntriesCount int
|
||||||
var expectedVolumeInGB float64
|
var expectedVolumeInGB float64
|
||||||
|
|
||||||
|
mockSummery := &api.BaseEntry{Protocol: api.Protocol{Name: "mock"}, Method: "mock-method", Timestamp: time.Date(2021, 1, 1, 10, 0, 0, 0, time.UTC).UnixNano()}
|
||||||
|
|
||||||
for _, data := range tests {
|
for _, data := range tests {
|
||||||
t.Run(fmt.Sprintf("%d", len(data)), func(t *testing.T) {
|
t.Run(fmt.Sprintf("%d", len(data)), func(t *testing.T) {
|
||||||
expectedEntriesCount++
|
expectedEntriesCount++
|
||||||
expectedVolumeInGB += float64(len(data)) / (1 << 30)
|
expectedVolumeInGB += float64(len(data)) / (1 << 30)
|
||||||
|
|
||||||
providers.EntryAdded(len(data))
|
providers.EntryAdded(len(data), mockSummery)
|
||||||
|
|
||||||
entriesStats := providers.GetGeneralStats()
|
entriesStats := providers.GetGeneralStats()
|
||||||
|
|
||||||
@@ -67,5 +81,4 @@ func TestEntryAddedVolume(t *testing.T) {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,47 +0,0 @@
|
|||||||
package providers
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/up9inc/mizu/agent/pkg/models"
|
|
||||||
"github.com/up9inc/mizu/shared"
|
|
||||||
)
|
|
||||||
|
|
||||||
var (
|
|
||||||
authStatus *models.AuthStatus
|
|
||||||
)
|
|
||||||
|
|
||||||
func GetAuthStatus() (*models.AuthStatus, error) {
|
|
||||||
if authStatus == nil {
|
|
||||||
syncEntriesConfigJson := os.Getenv(shared.SyncEntriesConfigEnvVar)
|
|
||||||
if syncEntriesConfigJson == "" {
|
|
||||||
authStatus = &models.AuthStatus{}
|
|
||||||
return authStatus, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
syncEntriesConfig := &shared.SyncEntriesConfig{}
|
|
||||||
err := json.Unmarshal([]byte(syncEntriesConfigJson), syncEntriesConfig)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to marshal sync entries config, err: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if syncEntriesConfig.Token == "" {
|
|
||||||
authStatus = &models.AuthStatus{}
|
|
||||||
return authStatus, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
tokenEmail, err := shared.GetTokenEmail(syncEntriesConfig.Token)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to get token email, err: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
authStatus = &models.AuthStatus{
|
|
||||||
Email: tokenEmail,
|
|
||||||
Model: syncEntriesConfig.Workspace,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return authStatus, nil
|
|
||||||
}
|
|
||||||
@@ -44,9 +44,10 @@ func Set(tappedPodsToSet []*shared.PodInfo) {
|
|||||||
|
|
||||||
func GetTappedPodsStatus() []shared.TappedPodStatus {
|
func GetTappedPodsStatus() []shared.TappedPodStatus {
|
||||||
tappedPodsStatus := make([]shared.TappedPodStatus, 0)
|
tappedPodsStatus := make([]shared.TappedPodStatus, 0)
|
||||||
|
tapperStatus := tappers.GetStatus()
|
||||||
for _, pod := range Get() {
|
for _, pod := range Get() {
|
||||||
var status string
|
var status string
|
||||||
if tapperStatus, ok := tappers.GetStatus()[pod.NodeName]; ok {
|
if tapperStatus, ok := tapperStatus[pod.NodeName]; ok {
|
||||||
status = strings.ToLower(tapperStatus.Status)
|
status = strings.ToLower(tapperStatus.Status)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +60,7 @@ func GetTappedPodsStatus() []shared.TappedPodStatus {
|
|||||||
|
|
||||||
func SetNodeToTappedPodMap(nodeToTappedPodsMap shared.NodeToPodsMap) {
|
func SetNodeToTappedPodMap(nodeToTappedPodsMap shared.NodeToPodsMap) {
|
||||||
summary := nodeToTappedPodsMap.Summary()
|
summary := nodeToTappedPodsMap.Summary()
|
||||||
logger.Log.Infof("Setting node to tapped pods map to %v", summary)
|
logger.Log.Debugf("Setting node to tapped pods map to %v", summary)
|
||||||
|
|
||||||
nodeHostToTappedPodsMap = nodeToTappedPodsMap
|
nodeHostToTappedPodsMap = nodeToTappedPodsMap
|
||||||
}
|
}
|
||||||
|
|||||||
184
agent/pkg/replay/replay.go
Normal file
184
agent/pkg/replay/replay.go
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
package replay
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"sync"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/up9inc/mizu/agent/pkg/app"
|
||||||
|
tapApi "github.com/up9inc/mizu/tap/api"
|
||||||
|
mizuhttp "github.com/up9inc/mizu/tap/extensions/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
inProcessRequestsLocker = sync.Mutex{}
|
||||||
|
inProcessRequests = 0
|
||||||
|
)
|
||||||
|
|
||||||
|
const maxParallelAction = 5
|
||||||
|
|
||||||
|
type Details struct {
|
||||||
|
Method string `json:"method"`
|
||||||
|
Url string `json:"url"`
|
||||||
|
Body string `json:"body"`
|
||||||
|
Headers map[string]string `json:"headers"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type Response struct {
|
||||||
|
Success bool `json:"status"`
|
||||||
|
Data interface{} `json:"data"`
|
||||||
|
ErrorMessage string `json:"errorMessage"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func incrementCounter() bool {
|
||||||
|
result := false
|
||||||
|
inProcessRequestsLocker.Lock()
|
||||||
|
if inProcessRequests < maxParallelAction {
|
||||||
|
inProcessRequests++
|
||||||
|
result = true
|
||||||
|
}
|
||||||
|
inProcessRequestsLocker.Unlock()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
func decrementCounter() {
|
||||||
|
inProcessRequestsLocker.Lock()
|
||||||
|
inProcessRequests--
|
||||||
|
inProcessRequestsLocker.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func getEntryFromRequestResponse(extension *tapApi.Extension, request *http.Request, response *http.Response) *tapApi.Entry {
|
||||||
|
captureTime := time.Now()
|
||||||
|
|
||||||
|
itemTmp := tapApi.OutputChannelItem{
|
||||||
|
Protocol: *extension.Protocol,
|
||||||
|
ConnectionInfo: &tapApi.ConnectionInfo{
|
||||||
|
ClientIP: "",
|
||||||
|
ClientPort: "1",
|
||||||
|
ServerIP: "",
|
||||||
|
ServerPort: "1",
|
||||||
|
IsOutgoing: false,
|
||||||
|
},
|
||||||
|
Capture: "",
|
||||||
|
Timestamp: time.Now().UnixMilli(),
|
||||||
|
Pair: &tapApi.RequestResponsePair{
|
||||||
|
Request: tapApi.GenericMessage{
|
||||||
|
IsRequest: true,
|
||||||
|
CaptureTime: captureTime,
|
||||||
|
CaptureSize: 0,
|
||||||
|
Payload: &mizuhttp.HTTPPayload{
|
||||||
|
Type: mizuhttp.TypeHttpRequest,
|
||||||
|
Data: request,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Response: tapApi.GenericMessage{
|
||||||
|
IsRequest: false,
|
||||||
|
CaptureTime: captureTime,
|
||||||
|
CaptureSize: 0,
|
||||||
|
Payload: &mizuhttp.HTTPPayload{
|
||||||
|
Type: mizuhttp.TypeHttpResponse,
|
||||||
|
Data: response,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// Analyze is expecting an item that's marshalled and unmarshalled
|
||||||
|
itemMarshalled, err := json.Marshal(itemTmp)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
var finalItem *tapApi.OutputChannelItem
|
||||||
|
if err := json.Unmarshal(itemMarshalled, &finalItem); err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return extension.Dissector.Analyze(finalItem, "", "", "")
|
||||||
|
}
|
||||||
|
|
||||||
|
func ExecuteRequest(replayData *Details, timeout time.Duration) *Response {
|
||||||
|
if incrementCounter() {
|
||||||
|
defer decrementCounter()
|
||||||
|
|
||||||
|
client := &http.Client{
|
||||||
|
Timeout: timeout,
|
||||||
|
}
|
||||||
|
|
||||||
|
request, err := http.NewRequest(strings.ToUpper(replayData.Method), replayData.Url, bytes.NewBufferString(replayData.Body))
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
Success: false,
|
||||||
|
Data: nil,
|
||||||
|
ErrorMessage: err.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for headerKey, headerValue := range replayData.Headers {
|
||||||
|
request.Header.Add(headerKey, headerValue)
|
||||||
|
}
|
||||||
|
request.Header.Add("x-mizu", uuid.New().String())
|
||||||
|
response, requestErr := client.Do(request)
|
||||||
|
|
||||||
|
if requestErr != nil {
|
||||||
|
return &Response{
|
||||||
|
Success: false,
|
||||||
|
Data: nil,
|
||||||
|
ErrorMessage: requestErr.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension := app.ExtensionsMap["http"] // # TODO: maybe pass the extension to the function so it can be tested
|
||||||
|
entry := getEntryFromRequestResponse(extension, request, response)
|
||||||
|
base := extension.Dissector.Summarize(entry)
|
||||||
|
var representation []byte
|
||||||
|
|
||||||
|
// Represent is expecting an entry that's marshalled and unmarshalled
|
||||||
|
entryMarshalled, err := json.Marshal(entry)
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
Success: false,
|
||||||
|
Data: nil,
|
||||||
|
ErrorMessage: err.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var entryUnmarshalled *tapApi.Entry
|
||||||
|
if err := json.Unmarshal(entryMarshalled, &entryUnmarshalled); err != nil {
|
||||||
|
return &Response{
|
||||||
|
Success: false,
|
||||||
|
Data: nil,
|
||||||
|
ErrorMessage: err.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
representation, err = extension.Dissector.Represent(entryUnmarshalled.Request, entryUnmarshalled.Response)
|
||||||
|
if err != nil {
|
||||||
|
return &Response{
|
||||||
|
Success: false,
|
||||||
|
Data: nil,
|
||||||
|
ErrorMessage: err.Error(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Response{
|
||||||
|
Success: true,
|
||||||
|
Data: &tapApi.EntryWrapper{
|
||||||
|
Protocol: *extension.Protocol,
|
||||||
|
Representation: string(representation),
|
||||||
|
Data: entryUnmarshalled,
|
||||||
|
Base: base,
|
||||||
|
},
|
||||||
|
ErrorMessage: "",
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return &Response{
|
||||||
|
Success: false,
|
||||||
|
Data: nil,
|
||||||
|
ErrorMessage: fmt.Sprintf("reached threshold of %d requests", maxParallelAction),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
106
agent/pkg/replay/replay_internal_test.go
Normal file
106
agent/pkg/replay/replay_internal_test.go
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
package replay
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"fmt"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
tapApi "github.com/up9inc/mizu/tap/api"
|
||||||
|
mizuhttp "github.com/up9inc/mizu/tap/extensions/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestValid(t *testing.T) {
|
||||||
|
client := &http.Client{
|
||||||
|
Timeout: 10 * time.Second,
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := map[string]*Details{
|
||||||
|
"40x": {
|
||||||
|
Method: "GET",
|
||||||
|
Url: "http://httpbin.org/status/404",
|
||||||
|
Body: "",
|
||||||
|
Headers: map[string]string{},
|
||||||
|
},
|
||||||
|
"20x": {
|
||||||
|
Method: "GET",
|
||||||
|
Url: "http://httpbin.org/status/200",
|
||||||
|
Body: "",
|
||||||
|
Headers: map[string]string{},
|
||||||
|
},
|
||||||
|
"50x": {
|
||||||
|
Method: "GET",
|
||||||
|
Url: "http://httpbin.org/status/500",
|
||||||
|
Body: "",
|
||||||
|
Headers: map[string]string{},
|
||||||
|
},
|
||||||
|
// TODO: this should be fixes, currently not working because of header name with ":"
|
||||||
|
//":path-header": {
|
||||||
|
// Method: "GET",
|
||||||
|
// Url: "http://httpbin.org/get",
|
||||||
|
// Body: "",
|
||||||
|
// Headers: map[string]string{
|
||||||
|
// ":path": "/get",
|
||||||
|
// },
|
||||||
|
// },
|
||||||
|
}
|
||||||
|
|
||||||
|
for testCaseName, replayData := range tests {
|
||||||
|
t.Run(fmt.Sprintf("%+v", testCaseName), func(t *testing.T) {
|
||||||
|
request, err := http.NewRequest(strings.ToUpper(replayData.Method), replayData.Url, bytes.NewBufferString(replayData.Body))
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("Error executing request")
|
||||||
|
}
|
||||||
|
|
||||||
|
for headerKey, headerValue := range replayData.Headers {
|
||||||
|
request.Header.Add(headerKey, headerValue)
|
||||||
|
}
|
||||||
|
request.Header.Add("x-mizu", uuid.New().String())
|
||||||
|
response, requestErr := client.Do(request)
|
||||||
|
|
||||||
|
if requestErr != nil {
|
||||||
|
t.Errorf("failed: %v, ", requestErr)
|
||||||
|
}
|
||||||
|
|
||||||
|
extensionHttp := &tapApi.Extension{}
|
||||||
|
dissectorHttp := mizuhttp.NewDissector()
|
||||||
|
dissectorHttp.Register(extensionHttp)
|
||||||
|
extensionHttp.Dissector = dissectorHttp
|
||||||
|
extension := extensionHttp
|
||||||
|
|
||||||
|
entry := getEntryFromRequestResponse(extension, request, response)
|
||||||
|
base := extension.Dissector.Summarize(entry)
|
||||||
|
|
||||||
|
// Represent is expecting an entry that's marshalled and unmarshalled
|
||||||
|
entryMarshalled, err := json.Marshal(entry)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed marshaling entry: %v, ", err)
|
||||||
|
}
|
||||||
|
var entryUnmarshalled *tapApi.Entry
|
||||||
|
if err := json.Unmarshal(entryMarshalled, &entryUnmarshalled); err != nil {
|
||||||
|
t.Errorf("failed unmarshaling entry: %v, ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var representation []byte
|
||||||
|
representation, err = extension.Dissector.Represent(entryUnmarshalled.Request, entryUnmarshalled.Response)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed: %v, ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
result := &tapApi.EntryWrapper{
|
||||||
|
Protocol: *extension.Protocol,
|
||||||
|
Representation: string(representation),
|
||||||
|
Data: entry,
|
||||||
|
Base: base,
|
||||||
|
}
|
||||||
|
t.Logf("%+v", result)
|
||||||
|
//data, _ := json.MarshalIndent(result, "", " ")
|
||||||
|
//t.Logf("%+v", string(data))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,524 +0,0 @@
|
|||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
|
||||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
|
||||||
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
|
|
||||||
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
|
|
||||||
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
|
|
||||||
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
|
|
||||||
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
|
|
||||||
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
|
|
||||||
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
|
|
||||||
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
|
|
||||||
cloud.google.com/go v0.54.0 h1:3ithwDMr7/3vpAMXiH+ZQnYbuIsh+OPhUPMFC9enmn0=
|
|
||||||
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
|
|
||||||
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
|
|
||||||
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
|
|
||||||
cloud.google.com/go/bigquery v1.4.0 h1:xE3CPsOgttP4ACBePh79zTKALtXwn/Edhcr16R5hMWU=
|
|
||||||
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
|
|
||||||
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
|
|
||||||
cloud.google.com/go/datastore v1.1.0 h1:/May9ojXjRkPBNVrq+oWLqmWCkr4OU5uRY29bu0mRyQ=
|
|
||||||
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
|
|
||||||
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
|
|
||||||
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
|
|
||||||
cloud.google.com/go/pubsub v1.2.0 h1:Lpy6hKgdcl7a3WGSfJIFmxmcdjSpP6OmBEfcOv1Y680=
|
|
||||||
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
|
|
||||||
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
|
|
||||||
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
|
|
||||||
cloud.google.com/go/storage v1.6.0 h1:UDpwYIwla4jHGzZJaEJYx1tOejbgSoNqsAfHAUYe2r8=
|
|
||||||
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
|
|
||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9 h1:VpgP7xuJadIUuKccphEpTJnWhS2jkQyMt6Y7pJCD7fY=
|
|
||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
|
||||||
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
|
|
||||||
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
|
||||||
github.com/Azure/go-autorest/autorest v0.11.12 h1:gI8ytXbxMfI+IVbI9mP2JGCTXIuhHLgRlvQ9X4PsnHE=
|
|
||||||
github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw=
|
|
||||||
github.com/Azure/go-autorest/autorest/adal v0.9.5 h1:Y3bBUV4rTuxenJJs41HU3qmqsb+auo+a3Lz+PlJPpL0=
|
|
||||||
github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A=
|
|
||||||
github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=
|
|
||||||
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
|
|
||||||
github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk=
|
|
||||||
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
|
|
||||||
github.com/Azure/go-autorest/logger v0.2.0 h1:e4RVHVZKC5p6UANLJHkM4OfR1UKZPj8Wt8Pcx+3oqrE=
|
|
||||||
github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
|
|
||||||
github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
|
|
||||||
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
|
|
||||||
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
|
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc=
|
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
|
||||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46 h1:lsxEuwrXEAokXB9qhlbKWPpo3KMLZQ5WB5WLQRW1uq0=
|
|
||||||
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
|
|
||||||
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/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
|
|
||||||
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
|
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
|
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
|
||||||
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
|
|
||||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
|
||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
|
|
||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
|
||||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
|
|
||||||
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
|
|
||||||
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
|
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
|
||||||
github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=
|
|
||||||
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/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ=
|
|
||||||
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
|
|
||||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
|
|
||||||
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
|
|
||||||
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633 h1:H2pdYOb3KQ1/YsqVWoWNLQO+fusocsw354rqGTZtAgw=
|
|
||||||
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473 h1:4cmBvAEBNJaGARUEs3/suWRyfyBfhf7I60WBZq+bv2w=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
|
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A=
|
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
|
||||||
github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses=
|
|
||||||
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
|
|
||||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk=
|
|
||||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
|
||||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0=
|
|
||||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe6ZudgnXrq0barxBImvnnJoMEhXAzcbM0I=
|
|
||||||
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
|
|
||||||
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
|
|
||||||
github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc=
|
|
||||||
github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
|
|
||||||
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
|
|
||||||
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
|
|
||||||
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
|
||||||
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
|
|
||||||
github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o=
|
|
||||||
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
|
|
||||||
github.com/go-openapi/spec v0.19.3 h1:0XRyw8kguri6Yw4SxhsQA/atC88yqrk0+G4YhI2wabc=
|
|
||||||
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
|
|
||||||
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
|
||||||
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
|
|
||||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
|
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
|
||||||
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 h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
|
|
||||||
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
|
||||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
|
||||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
|
||||||
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
|
||||||
github.com/golang/mock v1.4.1 h1:ocYkMQY5RrXTYgXl7ICpV0IXwlEQGwKIsery4gyXa1U=
|
|
||||||
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
|
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
|
||||||
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
|
||||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
|
||||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
|
||||||
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
|
|
||||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
|
||||||
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
|
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
|
|
||||||
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
|
||||||
github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
|
|
||||||
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
|
||||||
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
|
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
|
||||||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
|
||||||
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
|
|
||||||
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
|
||||||
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
|
||||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3 h1:SRgJV+IoxM5MKyFdlSUeNy6/ycRUF2yBAKdAQswoHUk=
|
|
||||||
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
|
|
||||||
github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=
|
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
|
||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
|
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
|
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
|
|
||||||
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
|
|
||||||
github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I=
|
|
||||||
github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
|
|
||||||
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/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
|
|
||||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
|
||||||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
|
||||||
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
|
|
||||||
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
|
|
||||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 h1:UDMh68UUwekSh5iP2OMhRRZJiiBccgV7axzUG8vi56c=
|
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
|
||||||
github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q=
|
|
||||||
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
|
||||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
|
||||||
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
|
|
||||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
|
||||||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
|
|
||||||
github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o=
|
|
||||||
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
|
|
||||||
github.com/kisielk/errcheck v1.5.0 h1:e8esj/e4R+SAOwFwN+n3zr0nYeCyeweozKfO23MvHzY=
|
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
|
||||||
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
|
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
|
||||||
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
|
|
||||||
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|
||||||
github.com/kr/pty v1.1.5 h1:hyz3dwM5QLc1Rfoz4FuWJQG5BN7tc6K1MndAUnGpQr4=
|
|
||||||
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
|
|
||||||
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/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
|
||||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
|
|
||||||
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
|
|
||||||
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
|
|
||||||
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
|
|
||||||
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
|
|
||||||
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
|
||||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
|
||||||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d h1:7PxY7LVfSZm7PEeBTyK1rj1gABdCO2mbri6GKO1cMDs=
|
|
||||||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
|
||||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
|
|
||||||
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
|
||||||
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/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
|
||||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
|
||||||
github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw=
|
|
||||||
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
|
||||||
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
|
||||||
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
|
|
||||||
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
|
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc=
|
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ=
|
|
||||||
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
|
|
||||||
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
|
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
|
||||||
github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk=
|
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
|
||||||
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
|
|
||||||
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
|
|
||||||
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
|
||||||
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
|
|
||||||
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
|
||||||
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
|
|
||||||
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
|
||||||
github.com/yuin/goldmark v1.2.1 h1:ruQGxdhGHe7FWOJPT0mKs5+pD2Xs1Bm/kdGlHO04FmM=
|
|
||||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
|
||||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
|
||||||
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
|
||||||
go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
|
|
||||||
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
|
||||||
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
|
|
||||||
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
|
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
|
||||||
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
|
||||||
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
|
|
||||||
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
|
|
||||||
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
|
|
||||||
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
|
||||||
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
|
||||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
|
||||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
|
||||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y=
|
|
||||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
|
||||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4=
|
|
||||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
|
||||||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
|
|
||||||
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
|
||||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
|
|
||||||
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
|
||||||
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
|
|
||||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs=
|
|
||||||
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
|
|
||||||
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
|
|
||||||
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
|
|
||||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
|
||||||
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
|
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/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=
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
|
|
||||||
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
|
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
|
||||||
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7 h1:OgUuv8lsRpBibGNbSizVwKWlysjaNzmC9gYMhPVfqFM=
|
|
||||||
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
|
|
||||||
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=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
|
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/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-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073 h1:8qxJSnu+7dRq6upnbntrmriWByIakBuct5OM/MdQC1M=
|
|
||||||
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
|
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
|
||||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE=
|
|
||||||
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
|
||||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
|
||||||
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 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
|
|
||||||
golang.org/x/text v0.3.4/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/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
|
|
||||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
|
||||||
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=
|
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
|
|
||||||
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
|
|
||||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a h1:CB3a9Nez8M13wwlr/E2YtwoU+qYHKfC+JrDa45RXXoQ=
|
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
|
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
|
|
||||||
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
|
|
||||||
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
|
||||||
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
|
|
||||||
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
|
||||||
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
|
||||||
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
|
|
||||||
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
|
||||||
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
|
||||||
google.golang.org/api v0.20.0 h1:jz2KixHX7EcCPiQrySzPdnYT7DbINAypCqKZ1Z7GM40=
|
|
||||||
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
|
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
|
||||||
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
|
||||||
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
|
|
||||||
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
|
|
||||||
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
|
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
|
||||||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
|
|
||||||
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
|
||||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
|
||||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
|
||||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
|
||||||
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
|
||||||
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
|
||||||
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
|
||||||
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
|
||||||
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
|
||||||
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
|
|
||||||
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
|
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
|
||||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
|
||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
|
||||||
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
|
||||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
|
||||||
google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk=
|
|
||||||
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
|
||||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
|
||||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
|
||||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
|
|
||||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
|
||||||
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=
|
|
||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
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 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8=
|
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
|
||||||
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
|
|
||||||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
|
|
||||||
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
|
|
||||||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
|
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
|
|
||||||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
|
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
|
||||||
honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U=
|
|
||||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
|
||||||
k8s.io/api v0.21.0 h1:gu5iGF4V6tfVCQ/R+8Hc0h7H1JuEhzyEi9S4R5LM8+Y=
|
|
||||||
k8s.io/api v0.21.0/go.mod h1:+YbrhBBGgsxbF6o6Kj4KJPJnBmAKuXDeS3E18bgHNVU=
|
|
||||||
k8s.io/apimachinery v0.21.0 h1:3Fx+41if+IRavNcKOz09FwEXDBG6ORh6iMsTSelhkMA=
|
|
||||||
k8s.io/apimachinery v0.21.0/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY=
|
|
||||||
k8s.io/client-go v0.21.0 h1:n0zzzJsAQmJngpC0IhgFcApZyoGXPrDIAD601HD09ag=
|
|
||||||
k8s.io/client-go v0.21.0/go.mod h1:nNBytTF9qPFDEhoqgEPaarobC8QPae13bElIVHzIglA=
|
|
||||||
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac h1:sAvhNk5RRuc6FNYGqe7Ygz3PSo/2wGWbulskmzRX8Vs=
|
|
||||||
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
|
||||||
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
|
|
||||||
k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts=
|
|
||||||
k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec=
|
|
||||||
k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 h1:vEx13qjvaZ4yfObSSXW7BrMc/KQBBT/Jyee8XtLf4x0=
|
|
||||||
k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE=
|
|
||||||
k8s.io/utils v0.0.0-20201110183641-67b214c5f920 h1:CbnUZsM497iRC5QMVkHwyl8s2tB3g7yaSHkYPkpgelw=
|
|
||||||
k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
|
||||||
rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE=
|
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
|
||||||
rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY=
|
|
||||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
|
||||||
rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4=
|
|
||||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
|
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.1.0 h1:C4r9BgJ98vrKnnVCjwCSXcWjWe0NKcUQkmzDXZXGwH8=
|
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
|
|
||||||
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
|
|
||||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
|
||||||
@@ -15,9 +15,9 @@ func NewFromInCluster(errOut chan error, namespace string) (*Resolver, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
clientset, err := kubernetes.NewForConfig(config)
|
clientSet, err := kubernetes.NewForConfig(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
return &Resolver{clientConfig: config, clientSet: clientset, nameMap: cmap.New(), serviceMap: cmap.New(), errOut: errOut, namespace: namespace}, nil
|
return &Resolver{clientConfig: config, clientSet: clientSet, nameMap: cmap.New(), serviceMap: cmap.New(), errOut: errOut, namespace: namespace}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
13
agent/pkg/routes/replay_routes.go
Normal file
13
agent/pkg/routes/replay_routes.go
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
package routes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/up9inc/mizu/agent/pkg/controllers"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ReplayRoutes defines the group of replay routes.
|
||||||
|
func ReplayRoutes(app *gin.Engine) {
|
||||||
|
routeGroup := app.Group("/replay")
|
||||||
|
|
||||||
|
routeGroup.POST("/", controllers.ReplayRequest)
|
||||||
|
}
|
||||||
@@ -15,11 +15,8 @@ func StatusRoutes(ginApp *gin.Engine) {
|
|||||||
routeGroup.GET("/connectedTappersCount", controllers.GetConnectedTappersCount)
|
routeGroup.GET("/connectedTappersCount", controllers.GetConnectedTappersCount)
|
||||||
routeGroup.GET("/tap", controllers.GetTappingStatus)
|
routeGroup.GET("/tap", controllers.GetTappingStatus)
|
||||||
|
|
||||||
routeGroup.GET("/auth", controllers.GetAuthStatus)
|
routeGroup.GET("/general", controllers.GetGeneralStats)
|
||||||
|
routeGroup.GET("/trafficStats", controllers.GetTrafficStats)
|
||||||
routeGroup.GET("/analyze", controllers.AnalyzeInformation)
|
|
||||||
|
|
||||||
routeGroup.GET("/general", controllers.GetGeneralStats) // get general stats about entries in DB
|
|
||||||
|
|
||||||
routeGroup.GET("/resolving", controllers.GetCurrentResolvingInformation)
|
routeGroup.GET("/resolving", controllers.GetCurrentResolvingInformation)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,124 +0,0 @@
|
|||||||
package rules
|
|
||||||
|
|
||||||
import (
|
|
||||||
"encoding/base64"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"reflect"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/up9inc/mizu/agent/pkg/har"
|
|
||||||
|
|
||||||
"github.com/up9inc/mizu/logger"
|
|
||||||
|
|
||||||
"github.com/up9inc/mizu/shared"
|
|
||||||
"github.com/yalp/jsonpath"
|
|
||||||
)
|
|
||||||
|
|
||||||
type RulesMatched struct {
|
|
||||||
Matched bool `json:"matched"`
|
|
||||||
Rule shared.RulePolicy `json:"rule"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func appendRulesMatched(rulesMatched []RulesMatched, matched bool, rule shared.RulePolicy) []RulesMatched {
|
|
||||||
return append(rulesMatched, RulesMatched{Matched: matched, Rule: rule})
|
|
||||||
}
|
|
||||||
|
|
||||||
func ValidatePath(URLFromRule string, URL string) bool {
|
|
||||||
if URLFromRule != "" {
|
|
||||||
matchPath, err := regexp.MatchString(URLFromRule, URL)
|
|
||||||
if err != nil || !matchPath {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func ValidateService(serviceFromRule string, service string) bool {
|
|
||||||
if serviceFromRule != "" {
|
|
||||||
matchService, err := regexp.MatchString(serviceFromRule, service)
|
|
||||||
if err != nil || !matchService {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func MatchRequestPolicy(harEntry har.Entry, service string) (resultPolicyToSend []RulesMatched, isEnabled bool) {
|
|
||||||
enforcePolicy, err := shared.DecodeEnforcePolicy(fmt.Sprintf("%s%s", shared.ConfigDirPath, shared.ValidationRulesFileName))
|
|
||||||
if err == nil && len(enforcePolicy.Rules) > 0 {
|
|
||||||
isEnabled = true
|
|
||||||
}
|
|
||||||
for _, rule := range enforcePolicy.Rules {
|
|
||||||
if !ValidatePath(rule.Path, harEntry.Request.URL) || !ValidateService(rule.Service, service) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if rule.Type == "json" {
|
|
||||||
var bodyJsonMap interface{}
|
|
||||||
contentTextDecoded, _ := base64.StdEncoding.DecodeString(string(harEntry.Response.Content.Text))
|
|
||||||
if err := json.Unmarshal(contentTextDecoded, &bodyJsonMap); err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
out, err := jsonpath.Read(bodyJsonMap, rule.Key)
|
|
||||||
if err != nil || out == nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
var matchValue bool
|
|
||||||
if reflect.TypeOf(out).Kind() == reflect.String {
|
|
||||||
matchValue, err = regexp.MatchString(rule.Value, out.(string))
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
logger.Log.Info(matchValue, rule.Value)
|
|
||||||
} else {
|
|
||||||
val := fmt.Sprint(out)
|
|
||||||
matchValue, err = regexp.MatchString(rule.Value, val)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
resultPolicyToSend = appendRulesMatched(resultPolicyToSend, matchValue, rule)
|
|
||||||
} else if rule.Type == "header" {
|
|
||||||
for j := range harEntry.Response.Headers {
|
|
||||||
matchKey, err := regexp.MatchString(rule.Key, harEntry.Response.Headers[j].Name)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if matchKey {
|
|
||||||
matchValue, err := regexp.MatchString(rule.Value, harEntry.Response.Headers[j].Value)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
resultPolicyToSend = appendRulesMatched(resultPolicyToSend, matchValue, rule)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
resultPolicyToSend = appendRulesMatched(resultPolicyToSend, true, rule)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
func PassedValidationRules(rulesMatched []RulesMatched) (bool, int64, int) {
|
|
||||||
var numberOfRulesMatched = len(rulesMatched)
|
|
||||||
var responseTime int64 = -1
|
|
||||||
|
|
||||||
if numberOfRulesMatched == 0 {
|
|
||||||
return false, 0, numberOfRulesMatched
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, rule := range rulesMatched {
|
|
||||||
if !rule.Matched {
|
|
||||||
return false, responseTime, numberOfRulesMatched
|
|
||||||
} else {
|
|
||||||
if strings.ToLower(rule.Rule.Type) == "slo" {
|
|
||||||
if rule.Rule.ResponseTime < responseTime || responseTime == -1 {
|
|
||||||
responseTime = rule.Rule.ResponseTime
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true, responseTime, numberOfRulesMatched
|
|
||||||
}
|
|
||||||
@@ -1,353 +0,0 @@
|
|||||||
package up9
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bytes"
|
|
||||||
"compress/zlib"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
"regexp"
|
|
||||||
"strings"
|
|
||||||
"sync"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/up9inc/mizu/agent/pkg/har"
|
|
||||||
"github.com/up9inc/mizu/agent/pkg/utils"
|
|
||||||
|
|
||||||
basenine "github.com/up9inc/basenine/client/go"
|
|
||||||
"github.com/up9inc/mizu/logger"
|
|
||||||
"github.com/up9inc/mizu/shared"
|
|
||||||
tapApi "github.com/up9inc/mizu/tap/api"
|
|
||||||
)
|
|
||||||
|
|
||||||
const (
|
|
||||||
AnalyzeCheckSleepTime = 5 * time.Second
|
|
||||||
SentCountLogInterval = 100
|
|
||||||
)
|
|
||||||
|
|
||||||
type GuestToken struct {
|
|
||||||
Token string `json:"token"`
|
|
||||||
Model string `json:"model"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ModelStatus struct {
|
|
||||||
LastMajorGeneration float64 `json:"lastMajorGeneration"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetRemoteUrl(analyzeDestination string, analyzeModel string, analyzeToken string, guestMode bool) string {
|
|
||||||
if guestMode {
|
|
||||||
return fmt.Sprintf("https://%s/share/%s", analyzeDestination, analyzeToken)
|
|
||||||
}
|
|
||||||
|
|
||||||
return fmt.Sprintf("https://%s/app/workspaces/%s", analyzeDestination, analyzeModel)
|
|
||||||
}
|
|
||||||
|
|
||||||
func CheckIfModelReady(analyzeDestination string, analyzeModel string, analyzeToken string, guestMode bool) bool {
|
|
||||||
statusUrl, _ := url.Parse(fmt.Sprintf("https://trcc.%s/models/%s/status", analyzeDestination, analyzeModel))
|
|
||||||
|
|
||||||
authHeader := getAuthHeader(guestMode)
|
|
||||||
req := &http.Request{
|
|
||||||
Method: http.MethodGet,
|
|
||||||
URL: statusUrl,
|
|
||||||
Header: map[string][]string{
|
|
||||||
"Content-Type": {"application/json"},
|
|
||||||
authHeader: {analyzeToken},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
statusResp, err := http.DefaultClient.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
defer statusResp.Body.Close()
|
|
||||||
|
|
||||||
target := &ModelStatus{}
|
|
||||||
_ = json.NewDecoder(statusResp.Body).Decode(&target)
|
|
||||||
|
|
||||||
return target.LastMajorGeneration > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func getAuthHeader(guestMode bool) string {
|
|
||||||
if guestMode {
|
|
||||||
return "Guest-Auth"
|
|
||||||
}
|
|
||||||
|
|
||||||
return "Authorization"
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetTrafficDumpUrl(analyzeDestination string, analyzeModel string) *url.URL {
|
|
||||||
strUrl := fmt.Sprintf("https://traffic.%s/dumpTrafficBulk/%s", analyzeDestination, analyzeModel)
|
|
||||||
postUrl, _ := url.Parse(strUrl)
|
|
||||||
return postUrl
|
|
||||||
}
|
|
||||||
|
|
||||||
type AnalyzeInformation struct {
|
|
||||||
IsAnalyzing bool
|
|
||||||
GuestMode bool
|
|
||||||
SentCount int
|
|
||||||
AnalyzedModel string
|
|
||||||
AnalyzeToken string
|
|
||||||
AnalyzeDestination string
|
|
||||||
}
|
|
||||||
|
|
||||||
func (info *AnalyzeInformation) Reset() {
|
|
||||||
info.IsAnalyzing = false
|
|
||||||
info.GuestMode = true
|
|
||||||
info.AnalyzedModel = ""
|
|
||||||
info.AnalyzeToken = ""
|
|
||||||
info.AnalyzeDestination = ""
|
|
||||||
info.SentCount = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
var analyzeInformation = &AnalyzeInformation{}
|
|
||||||
|
|
||||||
func GetAnalyzeInfo() *shared.AnalyzeStatus {
|
|
||||||
return &shared.AnalyzeStatus{
|
|
||||||
IsAnalyzing: analyzeInformation.IsAnalyzing,
|
|
||||||
RemoteUrl: GetRemoteUrl(analyzeInformation.AnalyzeDestination, analyzeInformation.AnalyzedModel, analyzeInformation.AnalyzeToken, analyzeInformation.GuestMode),
|
|
||||||
IsRemoteReady: CheckIfModelReady(analyzeInformation.AnalyzeDestination, analyzeInformation.AnalyzedModel, analyzeInformation.AnalyzeToken, analyzeInformation.GuestMode),
|
|
||||||
SentCount: analyzeInformation.SentCount,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func SyncEntries(syncEntriesConfig *shared.SyncEntriesConfig) error {
|
|
||||||
logger.Log.Infof("Sync entries - started")
|
|
||||||
|
|
||||||
var (
|
|
||||||
token, model string
|
|
||||||
guestMode bool
|
|
||||||
)
|
|
||||||
if syncEntriesConfig.Token == "" {
|
|
||||||
logger.Log.Infof("Sync entries - creating anonymous token. env %s", syncEntriesConfig.Env)
|
|
||||||
guestToken, err := createAnonymousToken(syncEntriesConfig.Env)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed creating anonymous token, err: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
token = guestToken.Token
|
|
||||||
model = guestToken.Model
|
|
||||||
guestMode = true
|
|
||||||
} else {
|
|
||||||
token = fmt.Sprintf("bearer %s", syncEntriesConfig.Token)
|
|
||||||
model = syncEntriesConfig.Workspace
|
|
||||||
guestMode = false
|
|
||||||
|
|
||||||
logger.Log.Infof("Sync entries - upserting model. env %s, model %s", syncEntriesConfig.Env, model)
|
|
||||||
if err := upsertModel(token, model, syncEntriesConfig.Env); err != nil {
|
|
||||||
return fmt.Errorf("failed upserting model, err: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
modelRegex, _ := regexp.Compile("[A-Za-z0-9][-A-Za-z0-9_.]*[A-Za-z0-9]+$")
|
|
||||||
if len(model) > 63 || !modelRegex.MatchString(model) {
|
|
||||||
return fmt.Errorf("invalid model name, model name: %s", model)
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Log.Infof("Sync entries - syncing. token: %s, model: %s, guest mode: %v", token, model, guestMode)
|
|
||||||
go syncEntriesImpl(token, model, syncEntriesConfig.Env, syncEntriesConfig.UploadIntervalSec, guestMode)
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func upsertModel(token string, model string, envPrefix string) error {
|
|
||||||
upsertModelUrl, _ := url.Parse(fmt.Sprintf("https://trcc.%s/models/%s", envPrefix, model))
|
|
||||||
|
|
||||||
authHeader := getAuthHeader(false)
|
|
||||||
req := &http.Request{
|
|
||||||
Method: http.MethodPost,
|
|
||||||
URL: upsertModelUrl,
|
|
||||||
Header: map[string][]string{
|
|
||||||
authHeader: {token},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
response, err := http.DefaultClient.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed request to upsert model, err: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
// In case the model is not created (not 201) and doesn't exists (not 409)
|
|
||||||
if response.StatusCode != 201 && response.StatusCode != 409 {
|
|
||||||
return fmt.Errorf("failed request to upsert model, status code: %v", response.StatusCode)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createAnonymousToken(envPrefix string) (*GuestToken, error) {
|
|
||||||
tokenUrl := fmt.Sprintf("https://trcc.%s/anonymous/token", envPrefix)
|
|
||||||
if strings.HasPrefix(envPrefix, "http") {
|
|
||||||
tokenUrl = fmt.Sprintf("%s/api/token", envPrefix)
|
|
||||||
}
|
|
||||||
token := &GuestToken{}
|
|
||||||
if err := getGuestToken(tokenUrl, token); err != nil {
|
|
||||||
logger.Log.Infof("Failed to get token, %s", err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return token, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getGuestToken(url string, target *GuestToken) error {
|
|
||||||
resp, err := http.Get(url)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
logger.Log.Infof("Got token from the server, starting to json decode... status code: %v", resp.StatusCode)
|
|
||||||
return json.NewDecoder(resp.Body).Decode(target)
|
|
||||||
}
|
|
||||||
|
|
||||||
func syncEntriesImpl(token string, model string, envPrefix string, uploadIntervalSec int, guestMode bool) {
|
|
||||||
analyzeInformation.IsAnalyzing = true
|
|
||||||
analyzeInformation.GuestMode = guestMode
|
|
||||||
analyzeInformation.AnalyzedModel = model
|
|
||||||
analyzeInformation.AnalyzeToken = token
|
|
||||||
analyzeInformation.AnalyzeDestination = envPrefix
|
|
||||||
analyzeInformation.SentCount = 0
|
|
||||||
|
|
||||||
// "http or grpc" filter indicates that we're only interested in HTTP and gRPC entries
|
|
||||||
query := "http or grpc"
|
|
||||||
|
|
||||||
logger.Log.Infof("Getting entries from the database")
|
|
||||||
|
|
||||||
BasenineReconnect:
|
|
||||||
var connection *basenine.Connection
|
|
||||||
var err error
|
|
||||||
connection, err = basenine.NewConnection(shared.BasenineHost, shared.BaseninePort)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Errorf("Can't establish a new connection to Basenine server: %v", err)
|
|
||||||
connection.Close()
|
|
||||||
time.Sleep(shared.BasenineReconnectInterval * time.Second)
|
|
||||||
goto BasenineReconnect
|
|
||||||
}
|
|
||||||
|
|
||||||
data := make(chan []byte)
|
|
||||||
meta := make(chan []byte)
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
data <- []byte(basenine.CloseChannel)
|
|
||||||
meta <- []byte(basenine.CloseChannel)
|
|
||||||
connection.Close()
|
|
||||||
}()
|
|
||||||
|
|
||||||
lastTimeSynced := time.Time{}
|
|
||||||
|
|
||||||
batch := make([]har.Entry, 0)
|
|
||||||
|
|
||||||
handleDataChannel := func(wg *sync.WaitGroup, connection *basenine.Connection, data chan []byte) {
|
|
||||||
defer wg.Done()
|
|
||||||
for {
|
|
||||||
dataBytes := <-data
|
|
||||||
|
|
||||||
if string(dataBytes) == basenine.CloseChannel {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var dataMap map[string]interface{}
|
|
||||||
err = json.Unmarshal(dataBytes, &dataMap)
|
|
||||||
|
|
||||||
var entry tapApi.Entry
|
|
||||||
if err := json.Unmarshal([]byte(dataBytes), &entry); err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
harEntry, err := har.NewEntry(entry.Request, entry.Response, entry.StartTime, entry.ElapsedTime)
|
|
||||||
if err != nil {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if entry.Source.Name != "" {
|
|
||||||
harEntry.Request.Headers = append(harEntry.Request.Headers, har.Header{Name: "x-mizu-source", Value: entry.Source.Name})
|
|
||||||
}
|
|
||||||
if entry.Destination.Name != "" {
|
|
||||||
harEntry.Request.Headers = append(harEntry.Request.Headers, har.Header{Name: "x-mizu-destination", Value: entry.Destination.Name})
|
|
||||||
harEntry.Request.URL = utils.SetHostname(harEntry.Request.URL, entry.Destination.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
batch = append(batch, *harEntry)
|
|
||||||
|
|
||||||
now := time.Now()
|
|
||||||
if lastTimeSynced.Add(time.Duration(uploadIntervalSec) * time.Second).After(now) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
lastTimeSynced = now
|
|
||||||
|
|
||||||
body, jMarshalErr := json.Marshal(batch)
|
|
||||||
batchSize := len(batch)
|
|
||||||
if jMarshalErr != nil {
|
|
||||||
analyzeInformation.Reset()
|
|
||||||
logger.Log.Infof("Stopping sync entries")
|
|
||||||
logger.Log.Fatal(jMarshalErr)
|
|
||||||
}
|
|
||||||
batch = make([]har.Entry, 0)
|
|
||||||
|
|
||||||
var in bytes.Buffer
|
|
||||||
w := zlib.NewWriter(&in)
|
|
||||||
_, _ = w.Write(body)
|
|
||||||
_ = w.Close()
|
|
||||||
reqBody := ioutil.NopCloser(bytes.NewReader(in.Bytes()))
|
|
||||||
|
|
||||||
authHeader := getAuthHeader(guestMode)
|
|
||||||
req := &http.Request{
|
|
||||||
Method: http.MethodPost,
|
|
||||||
URL: GetTrafficDumpUrl(envPrefix, model),
|
|
||||||
Header: map[string][]string{
|
|
||||||
"Content-Encoding": {"deflate"},
|
|
||||||
"Content-Type": {"application/octet-stream"},
|
|
||||||
authHeader: {token},
|
|
||||||
},
|
|
||||||
Body: reqBody,
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, postErr := http.DefaultClient.Do(req); postErr != nil {
|
|
||||||
analyzeInformation.Reset()
|
|
||||||
logger.Log.Info("Stopping sync entries")
|
|
||||||
logger.Log.Fatal(postErr)
|
|
||||||
}
|
|
||||||
analyzeInformation.SentCount += batchSize
|
|
||||||
|
|
||||||
if analyzeInformation.SentCount%SentCountLogInterval == 0 {
|
|
||||||
logger.Log.Infof("Uploaded %v entries until now", analyzeInformation.SentCount)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleMetaChannel := func(wg *sync.WaitGroup, connection *basenine.Connection, meta chan []byte) {
|
|
||||||
defer wg.Done()
|
|
||||||
for {
|
|
||||||
metaBytes := <-meta
|
|
||||||
|
|
||||||
if string(metaBytes) == basenine.CloseChannel {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var wg sync.WaitGroup
|
|
||||||
go handleDataChannel(&wg, connection, data)
|
|
||||||
go handleMetaChannel(&wg, connection, meta)
|
|
||||||
wg.Add(2)
|
|
||||||
|
|
||||||
if err = connection.Query(query, data, meta); err != nil {
|
|
||||||
logger.Log.Errorf("Query mode call failed: %v", err)
|
|
||||||
connection.Close()
|
|
||||||
time.Sleep(shared.BasenineReconnectInterval * time.Second)
|
|
||||||
goto BasenineReconnect
|
|
||||||
}
|
|
||||||
|
|
||||||
wg.Wait()
|
|
||||||
}
|
|
||||||
|
|
||||||
func UpdateAnalyzeStatus(callback func(data []byte)) {
|
|
||||||
for {
|
|
||||||
if !analyzeInformation.IsAnalyzing {
|
|
||||||
time.Sleep(AnalyzeCheckSleepTime)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
analyzeStatus := GetAnalyzeInfo()
|
|
||||||
socketMessage := shared.CreateWebSocketMessageTypeAnalyzeStatus(*analyzeStatus)
|
|
||||||
|
|
||||||
jsonMessage, _ := json.Marshal(socketMessage)
|
|
||||||
callback(jsonMessage)
|
|
||||||
time.Sleep(AnalyzeCheckSleepTime)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,9 @@
|
|||||||
package utils
|
package utils
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/djherbis/atime"
|
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
|
"github.com/djherbis/atime"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ByModTime []os.FileInfo
|
type ByModTime []os.FileInfo
|
||||||
@@ -19,7 +20,6 @@ func (fis ByModTime) Less(i, j int) bool {
|
|||||||
return fis[i].ModTime().Before(fis[j].ModTime())
|
return fis[i].ModTime().Before(fis[j].ModTime())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type ByName []os.FileInfo
|
type ByName []os.FileInfo
|
||||||
|
|
||||||
func (fis ByName) Len() int {
|
func (fis ByName) Len() int {
|
||||||
@@ -34,7 +34,6 @@ func (fis ByName) Less(i, j int) bool {
|
|||||||
return fis[i].Name() < fis[j].Name()
|
return fis[i].Name() < fis[j].Name()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type ByCreationTime []os.FileInfo
|
type ByCreationTime []os.FileInfo
|
||||||
|
|
||||||
func (fis ByCreationTime) Len() int {
|
func (fis ByCreationTime) Len() int {
|
||||||
@@ -47,4 +46,4 @@ func (fis ByCreationTime) Swap(i, j int) {
|
|||||||
|
|
||||||
func (fis ByCreationTime) Less(i, j int) bool {
|
func (fis ByCreationTime) Less(i, j int) bool {
|
||||||
return atime.Get(fis[i]).Unix() < atime.Get(fis[j]).Unix()
|
return atime.Get(fis[i]).Unix() < atime.Get(fis[j]).Unix()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
|
||||||
"os"
|
"os"
|
||||||
"os/signal"
|
"os/signal"
|
||||||
"syscall"
|
"syscall"
|
||||||
@@ -59,17 +58,6 @@ func CheckErr(e error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetHostname(address, newHostname string) string {
|
|
||||||
replacedUrl, err := url.Parse(address)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Errorf("error replacing hostname to %s in address %s, returning original %v", newHostname, address, err)
|
|
||||||
return address
|
|
||||||
}
|
|
||||||
replacedUrl.Host = newHostname
|
|
||||||
return replacedUrl.String()
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func ReadJsonFile(filePath string, value interface{}) error {
|
func ReadJsonFile(filePath string, value interface{}) error {
|
||||||
if content, err := ioutil.ReadFile(filePath); err != nil {
|
if content, err := ioutil.ReadFile(filePath); err != nil {
|
||||||
return err
|
return err
|
||||||
|
|||||||
@@ -1,147 +0,0 @@
|
|||||||
package auth
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"net"
|
|
||||||
"net/http"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/google/uuid"
|
|
||||||
"github.com/up9inc/mizu/cli/config"
|
|
||||||
"github.com/up9inc/mizu/cli/config/configStructs"
|
|
||||||
"github.com/up9inc/mizu/cli/uiUtils"
|
|
||||||
"github.com/up9inc/mizu/logger"
|
|
||||||
"golang.org/x/oauth2"
|
|
||||||
)
|
|
||||||
|
|
||||||
const loginTimeoutInMin = 2
|
|
||||||
|
|
||||||
// Ports are configured in keycloak "cli" client as valid redirect URIs. A change here must be reflected there as well.
|
|
||||||
var listenPorts = []int{3141, 4001, 5002, 6003, 7004, 8005, 9006, 10007}
|
|
||||||
|
|
||||||
func Login() error {
|
|
||||||
token, loginErr := loginInteractively()
|
|
||||||
if loginErr != nil {
|
|
||||||
return fmt.Errorf("failed login interactively, err: %v", loginErr)
|
|
||||||
}
|
|
||||||
|
|
||||||
authConfig := configStructs.AuthConfig{
|
|
||||||
EnvName: config.Config.Auth.EnvName,
|
|
||||||
Token: token.AccessToken,
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := config.UpdateConfig(func(configStruct *config.ConfigStruct) { configStruct.Auth = authConfig }); err != nil {
|
|
||||||
return fmt.Errorf("failed updating config with auth, err: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
config.Config.Auth = authConfig
|
|
||||||
|
|
||||||
logger.Log.Infof("Login successfully, token stored in config path: %s", fmt.Sprintf(uiUtils.Purple, config.Config.ConfigFilePath))
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func loginInteractively() (*oauth2.Token, error) {
|
|
||||||
tokenChannel := make(chan *oauth2.Token)
|
|
||||||
errorChannel := make(chan error)
|
|
||||||
|
|
||||||
server := http.Server{}
|
|
||||||
go startLoginServer(tokenChannel, errorChannel, &server)
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
if err := server.Shutdown(context.Background()); err != nil {
|
|
||||||
logger.Log.Debugf("Error shutting down server, err: %v", err)
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
select {
|
|
||||||
case <-time.After(loginTimeoutInMin * time.Minute):
|
|
||||||
return nil, errors.New("auth timed out")
|
|
||||||
case err := <-errorChannel:
|
|
||||||
return nil, err
|
|
||||||
case token := <-tokenChannel:
|
|
||||||
return token, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func startLoginServer(tokenChannel chan *oauth2.Token, errorChannel chan error, server *http.Server) {
|
|
||||||
for _, port := range listenPorts {
|
|
||||||
var authConfig = &oauth2.Config{
|
|
||||||
ClientID: "cli",
|
|
||||||
RedirectURL: fmt.Sprintf("http://localhost:%v/callback", port),
|
|
||||||
Endpoint: oauth2.Endpoint{
|
|
||||||
AuthURL: fmt.Sprintf("https://auth.%s/auth/realms/testr/protocol/openid-connect/auth", config.Config.Auth.EnvName),
|
|
||||||
TokenURL: fmt.Sprintf("https://auth.%s/auth/realms/testr/protocol/openid-connect/token", config.Config.Auth.EnvName),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
state := uuid.New()
|
|
||||||
|
|
||||||
mux := http.NewServeMux()
|
|
||||||
server.Handler = mux
|
|
||||||
mux.Handle("/callback", loginCallbackHandler(tokenChannel, errorChannel, authConfig, state))
|
|
||||||
|
|
||||||
listener, listenErr := net.Listen("tcp", fmt.Sprintf("%s:%d", "127.0.0.1", port))
|
|
||||||
if listenErr != nil {
|
|
||||||
logger.Log.Debugf("failed to start listening on port %v, err: %v", port, listenErr)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
authorizationUrl := authConfig.AuthCodeURL(state.String())
|
|
||||||
uiUtils.OpenBrowser(authorizationUrl)
|
|
||||||
|
|
||||||
serveErr := server.Serve(listener)
|
|
||||||
if serveErr == http.ErrServerClosed {
|
|
||||||
logger.Log.Debugf("received server shutdown, server on port %v is closed", port)
|
|
||||||
return
|
|
||||||
} else if serveErr != nil {
|
|
||||||
logger.Log.Debugf("failed to start serving on port %v, err: %v", port, serveErr)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Log.Debugf("didn't receive server closed on port %v", port)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
errorChannel <- fmt.Errorf("failed to start serving on all listen ports, ports: %v", listenPorts)
|
|
||||||
}
|
|
||||||
|
|
||||||
func loginCallbackHandler(tokenChannel chan *oauth2.Token, errorChannel chan error, authConfig *oauth2.Config, state uuid.UUID) http.Handler {
|
|
||||||
return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) {
|
|
||||||
if err := request.ParseForm(); err != nil {
|
|
||||||
errorMsg := fmt.Sprintf("failed to parse form, err: %v", err)
|
|
||||||
http.Error(writer, errorMsg, http.StatusBadRequest)
|
|
||||||
errorChannel <- fmt.Errorf(errorMsg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
requestState := request.Form.Get("state")
|
|
||||||
if requestState != state.String() {
|
|
||||||
errorMsg := fmt.Sprintf("state invalid, requestState: %v, authState:%v", requestState, state.String())
|
|
||||||
http.Error(writer, errorMsg, http.StatusBadRequest)
|
|
||||||
errorChannel <- fmt.Errorf(errorMsg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
code := request.Form.Get("code")
|
|
||||||
if code == "" {
|
|
||||||
errorMsg := "code not found"
|
|
||||||
http.Error(writer, errorMsg, http.StatusBadRequest)
|
|
||||||
errorChannel <- fmt.Errorf(errorMsg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
token, err := authConfig.Exchange(context.Background(), code)
|
|
||||||
if err != nil {
|
|
||||||
errorMsg := fmt.Sprintf("failed to create token, err: %v", err)
|
|
||||||
http.Error(writer, errorMsg, http.StatusInternalServerError)
|
|
||||||
errorChannel <- fmt.Errorf(errorMsg)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
tokenChannel <- token
|
|
||||||
|
|
||||||
http.Redirect(writer, request, fmt.Sprintf("https://%s/CliLogin", config.Config.Auth.EnvName), http.StatusFound)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -1,8 +1,11 @@
|
|||||||
package cmd
|
package cmd
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/creasty/defaults"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/up9inc/mizu/cli/config/configStructs"
|
||||||
"github.com/up9inc/mizu/cli/telemetry"
|
"github.com/up9inc/mizu/cli/telemetry"
|
||||||
|
"github.com/up9inc/mizu/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
var installCmd = &cobra.Command{
|
var installCmd = &cobra.Command{
|
||||||
@@ -17,4 +20,11 @@ var installCmd = &cobra.Command{
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rootCmd.AddCommand(installCmd)
|
rootCmd.AddCommand(installCmd)
|
||||||
|
|
||||||
|
defaultInstallConfig := configStructs.InstallConfig{}
|
||||||
|
if err := defaults.Set(&defaultInstallConfig); err != nil {
|
||||||
|
logger.Log.Debug(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
installCmd.Flags().BoolP(configStructs.OutInstallName, "o", defaultInstallConfig.Out, "print (to stdout) Kubernetes manifest used to install Mizu Pro edition")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/up9inc/mizu/cli/bucket"
|
"github.com/up9inc/mizu/cli/bucket"
|
||||||
"github.com/up9inc/mizu/cli/config"
|
"github.com/up9inc/mizu/cli/config"
|
||||||
@@ -9,12 +10,23 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func runMizuInstall() {
|
func runMizuInstall() {
|
||||||
bucketProvider := bucket.NewProvider(config.Config.Install.TemplateUrl, bucket.DefaultTimeout)
|
if config.Config.Install.Out {
|
||||||
installTemplate, err := bucketProvider.GetInstallTemplate(config.Config.Install.TemplateName)
|
bucketProvider := bucket.NewProvider(config.Config.Install.TemplateUrl, bucket.DefaultTimeout)
|
||||||
if err != nil {
|
installTemplate, err := bucketProvider.GetInstallTemplate(config.Config.Install.TemplateName)
|
||||||
logger.Log.Errorf("Failed getting install template, err: %v", err)
|
if err != nil {
|
||||||
|
logger.Log.Errorf("Failed getting install template, err: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Print(installTemplate)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Print(installTemplate)
|
var sb strings.Builder
|
||||||
|
sb.WriteString("Hello! This command can be used to install Mizu Pro edition on your Kubernetes cluster.")
|
||||||
|
sb.WriteString("\nPlease run:")
|
||||||
|
sb.WriteString("\n\tmizu install -o | kubectl apply -n mizu -f -")
|
||||||
|
sb.WriteString("\n\nor use helm chart as described in https://getmizu.io/docs/installing-mizu/centralized-installation\n")
|
||||||
|
|
||||||
|
fmt.Print(sb.String())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,24 +2,15 @@ package cmd
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
|
|
||||||
"github.com/up9inc/mizu/cli/up9"
|
|
||||||
|
|
||||||
"github.com/creasty/defaults"
|
"github.com/creasty/defaults"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"github.com/up9inc/mizu/cli/auth"
|
|
||||||
"github.com/up9inc/mizu/cli/config"
|
"github.com/up9inc/mizu/cli/config"
|
||||||
"github.com/up9inc/mizu/cli/config/configStructs"
|
"github.com/up9inc/mizu/cli/config/configStructs"
|
||||||
"github.com/up9inc/mizu/cli/errormessage"
|
"github.com/up9inc/mizu/cli/errormessage"
|
||||||
"github.com/up9inc/mizu/cli/uiUtils"
|
|
||||||
"github.com/up9inc/mizu/logger"
|
"github.com/up9inc/mizu/logger"
|
||||||
"github.com/up9inc/mizu/shared"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const uploadTrafficMessageToConfirm = `NOTE: running mizu with --%s flag will upload recorded traffic for further analysis and enriched presentation options.`
|
|
||||||
|
|
||||||
var tapCmd = &cobra.Command{
|
var tapCmd = &cobra.Command{
|
||||||
Use: "tap [POD REGEX]",
|
Use: "tap [POD REGEX]",
|
||||||
Short: "Record ingoing traffic of a kubernetes pod",
|
Short: "Record ingoing traffic of a kubernetes pod",
|
||||||
@@ -40,67 +31,12 @@ Supported protocols are HTTP and gRPC.`,
|
|||||||
return errormessage.FormatError(err)
|
return errormessage.FormatError(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.Config.Tap.Workspace != "" {
|
|
||||||
askConfirmation(configStructs.WorkspaceTapName)
|
|
||||||
|
|
||||||
if config.Config.Auth.Token == "" {
|
|
||||||
logger.Log.Infof("This action requires authentication, please log in to continue")
|
|
||||||
if err := auth.Login(); err != nil {
|
|
||||||
logger.Log.Errorf("failed to log in, err: %v", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tokenExpired, err := shared.IsTokenExpired(config.Config.Auth.Token)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Errorf("failed to check if token is expired, err: %v", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
if tokenExpired {
|
|
||||||
logger.Log.Infof("Token expired, please log in again to continue")
|
|
||||||
if err := auth.Login(); err != nil {
|
|
||||||
logger.Log.Errorf("failed to log in, err: %v", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
} else if isValidToken := up9.IsTokenValid(config.Config.Auth.Token, config.Config.Auth.EnvName); !isValidToken {
|
|
||||||
logger.Log.Errorf("Token is not valid, please log in again to continue")
|
|
||||||
if err := auth.Login(); err != nil {
|
|
||||||
logger.Log.Errorf("failed to log in, err: %v", err)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.Config.Tap.Analysis {
|
|
||||||
askConfirmation(configStructs.AnalysisTapName)
|
|
||||||
|
|
||||||
config.Config.Auth.Token = ""
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Log.Infof("Mizu will store up to %s of traffic, old traffic will be cleared once the limit is reached.", config.Config.Tap.HumanMaxEntriesDBSize)
|
logger.Log.Infof("Mizu will store up to %s of traffic, old traffic will be cleared once the limit is reached.", config.Config.Tap.HumanMaxEntriesDBSize)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
func askConfirmation(flagName string) {
|
|
||||||
logger.Log.Infof(fmt.Sprintf(uploadTrafficMessageToConfirm, flagName))
|
|
||||||
|
|
||||||
if !config.Config.Tap.AskUploadConfirmation {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if !uiUtils.AskForConfirmation("Would you like to proceed [Y/n]: ") {
|
|
||||||
logger.Log.Infof("You can always run mizu without %s, aborting", flagName)
|
|
||||||
os.Exit(0)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := config.UpdateConfig(func(configStruct *config.ConfigStruct) { configStruct.Tap.AskUploadConfirmation = false }); err != nil {
|
|
||||||
logger.Log.Debugf("failed updating config with upload confirmation, err: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
rootCmd.AddCommand(tapCmd)
|
rootCmd.AddCommand(tapCmd)
|
||||||
|
|
||||||
@@ -111,16 +47,14 @@ func init() {
|
|||||||
|
|
||||||
tapCmd.Flags().Uint16P(configStructs.GuiPortTapName, "p", defaultTapConfig.GuiPort, "Provide a custom port for the web interface webserver")
|
tapCmd.Flags().Uint16P(configStructs.GuiPortTapName, "p", defaultTapConfig.GuiPort, "Provide a custom port for the web interface webserver")
|
||||||
tapCmd.Flags().StringSliceP(configStructs.NamespacesTapName, "n", defaultTapConfig.Namespaces, "Namespaces selector")
|
tapCmd.Flags().StringSliceP(configStructs.NamespacesTapName, "n", defaultTapConfig.Namespaces, "Namespaces selector")
|
||||||
tapCmd.Flags().Bool(configStructs.AnalysisTapName, defaultTapConfig.Analysis, "Uploads traffic to UP9 for further analysis (Beta)")
|
|
||||||
tapCmd.Flags().BoolP(configStructs.AllNamespacesTapName, "A", defaultTapConfig.AllNamespaces, "Tap all namespaces")
|
tapCmd.Flags().BoolP(configStructs.AllNamespacesTapName, "A", defaultTapConfig.AllNamespaces, "Tap all namespaces")
|
||||||
tapCmd.Flags().StringSliceP(configStructs.PlainTextFilterRegexesTapName, "r", defaultTapConfig.PlainTextFilterRegexes, "List of regex expressions that are used to filter matching values from text/plain http bodies")
|
tapCmd.Flags().StringSliceP(configStructs.PlainTextFilterRegexesTapName, "r", defaultTapConfig.PlainTextFilterRegexes, "List of regex expressions that are used to filter matching values from text/plain http bodies")
|
||||||
tapCmd.Flags().Bool(configStructs.DisableRedactionTapName, defaultTapConfig.DisableRedaction, "Disables redaction of potentially sensitive request/response headers and body values")
|
tapCmd.Flags().Bool(configStructs.EnableRedactionTapName, defaultTapConfig.EnableRedaction, "Enables redaction of potentially sensitive request/response headers and body values")
|
||||||
tapCmd.Flags().String(configStructs.HumanMaxEntriesDBSizeTapName, defaultTapConfig.HumanMaxEntriesDBSize, "Override the default max entries db size")
|
tapCmd.Flags().String(configStructs.HumanMaxEntriesDBSizeTapName, defaultTapConfig.HumanMaxEntriesDBSize, "Override the default max entries db size")
|
||||||
tapCmd.Flags().String(configStructs.InsertionFilterName, defaultTapConfig.InsertionFilter, "Set the insertion filter. Accepts string or a file path.")
|
tapCmd.Flags().String(configStructs.InsertionFilterName, defaultTapConfig.InsertionFilter, "Set the insertion filter. Accepts string or a file path.")
|
||||||
tapCmd.Flags().Bool(configStructs.DryRunTapName, defaultTapConfig.DryRun, "Preview of all pods matching the regex, without tapping them")
|
tapCmd.Flags().Bool(configStructs.DryRunTapName, defaultTapConfig.DryRun, "Preview of all pods matching the regex, without tapping them")
|
||||||
tapCmd.Flags().StringP(configStructs.WorkspaceTapName, "w", defaultTapConfig.Workspace, "Uploads traffic to your UP9 workspace for further analysis (requires auth)")
|
|
||||||
tapCmd.Flags().String(configStructs.EnforcePolicyFile, defaultTapConfig.EnforcePolicyFile, "Yaml file path with policy rules")
|
|
||||||
tapCmd.Flags().String(configStructs.ContractFile, defaultTapConfig.ContractFile, "OAS/Swagger file to validate to monitor the contracts")
|
|
||||||
tapCmd.Flags().Bool(configStructs.ServiceMeshName, defaultTapConfig.ServiceMesh, "Record decrypted traffic if the cluster is configured with a service mesh and with mtls")
|
tapCmd.Flags().Bool(configStructs.ServiceMeshName, defaultTapConfig.ServiceMesh, "Record decrypted traffic if the cluster is configured with a service mesh and with mtls")
|
||||||
tapCmd.Flags().Bool(configStructs.TlsName, defaultTapConfig.Tls, "Record tls traffic")
|
tapCmd.Flags().Bool(configStructs.TlsName, defaultTapConfig.Tls, "Record tls traffic")
|
||||||
|
tapCmd.Flags().Bool(configStructs.ProfilerName, defaultTapConfig.Profiler, "Run pprof server")
|
||||||
|
tapCmd.Flags().Int(configStructs.MaxLiveStreamsName, defaultTapConfig.MaxLiveStreams, "Maximum live tcp streams to handle concurrently")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@@ -13,8 +12,6 @@ import (
|
|||||||
"github.com/up9inc/mizu/cli/telemetry"
|
"github.com/up9inc/mizu/cli/telemetry"
|
||||||
"github.com/up9inc/mizu/cli/utils"
|
"github.com/up9inc/mizu/cli/utils"
|
||||||
|
|
||||||
"github.com/getkin/kin-openapi/openapi3"
|
|
||||||
"gopkg.in/yaml.v3"
|
|
||||||
core "k8s.io/api/core/v1"
|
core "k8s.io/api/core/v1"
|
||||||
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
k8serrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
@@ -47,40 +44,6 @@ func RunMizuTap() {
|
|||||||
|
|
||||||
apiProvider = apiserver.NewProvider(GetApiServerUrl(config.Config.Tap.GuiPort), apiserver.DefaultRetries, apiserver.DefaultTimeout)
|
apiProvider = apiserver.NewProvider(GetApiServerUrl(config.Config.Tap.GuiPort), apiserver.DefaultRetries, apiserver.DefaultTimeout)
|
||||||
|
|
||||||
var err error
|
|
||||||
var serializedValidationRules string
|
|
||||||
if config.Config.Tap.EnforcePolicyFile != "" {
|
|
||||||
serializedValidationRules, err = readValidationRules(config.Config.Tap.EnforcePolicyFile)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error reading policy file: %v", errormessage.FormatError(err)))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read and validate the OAS file
|
|
||||||
var serializedContract string
|
|
||||||
if config.Config.Tap.ContractFile != "" {
|
|
||||||
bytes, err := ioutil.ReadFile(config.Config.Tap.ContractFile)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error reading contract file: %v", errormessage.FormatError(err)))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
serializedContract = string(bytes)
|
|
||||||
|
|
||||||
ctx := context.Background()
|
|
||||||
loader := &openapi3.Loader{Context: ctx}
|
|
||||||
doc, err := loader.LoadFromData(bytes)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error loading contract file: %v", errormessage.FormatError(err)))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
err = doc.Validate(ctx)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error validating contract file: %v", errormessage.FormatError(err)))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
kubernetesProvider, err := getKubernetesProviderForCli()
|
kubernetesProvider, err := getKubernetesProviderForCli()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@@ -124,7 +87,7 @@ func RunMizuTap() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
logger.Log.Infof("Waiting for Mizu Agent to start...")
|
logger.Log.Infof("Waiting for Mizu Agent to start...")
|
||||||
if state.mizuServiceAccountExists, err = resources.CreateTapMizuResources(ctx, kubernetesProvider, serializedValidationRules, serializedContract, serializedMizuConfig, config.Config.IsNsRestrictedMode(), config.Config.MizuResourcesNamespace, config.Config.AgentImage, getSyncEntriesConfig(), config.Config.Tap.MaxEntriesDBSizeBytes(), config.Config.Tap.ApiServerResources, config.Config.ImagePullPolicy(), config.Config.LogLevel()); err != nil {
|
if state.mizuServiceAccountExists, err = resources.CreateTapMizuResources(ctx, kubernetesProvider, serializedMizuConfig, config.Config.IsNsRestrictedMode(), config.Config.MizuResourcesNamespace, config.Config.AgentImage, config.Config.Tap.MaxEntriesDBSizeBytes(), config.Config.Tap.ApiServerResources, config.Config.ImagePullPolicy(), config.Config.LogLevel(), config.Config.Tap.Profiler); err != nil {
|
||||||
var statusError *k8serrors.StatusError
|
var statusError *k8serrors.StatusError
|
||||||
if errors.As(err, &statusError) && (statusError.ErrStatus.Reason == metav1.StatusReasonAlreadyExists) {
|
if errors.As(err, &statusError) && (statusError.ErrStatus.Reason == metav1.StatusReasonAlreadyExists) {
|
||||||
logger.Log.Info("Mizu is already running in this namespace, change the `mizu-resources-namespace` configuration or run `mizu clean` to remove the currently running Mizu instance")
|
logger.Log.Info("Mizu is already running in this namespace, change the `mizu-resources-namespace` configuration or run `mizu clean` to remove the currently running Mizu instance")
|
||||||
@@ -164,7 +127,6 @@ func getTapMizuAgentConfig() *shared.MizuAgentConfig {
|
|||||||
ServiceMap: config.Config.ServiceMap,
|
ServiceMap: config.Config.ServiceMap,
|
||||||
OAS: config.Config.OAS,
|
OAS: config.Config.OAS,
|
||||||
Telemetry: config.Config.Telemetry,
|
Telemetry: config.Config.Telemetry,
|
||||||
Elastic: config.Config.Elastic,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return &mizuAgentConfig
|
return &mizuAgentConfig
|
||||||
@@ -203,6 +165,7 @@ func startTapperSyncer(ctx context.Context, cancel context.CancelFunc, provider
|
|||||||
MizuServiceAccountExists: state.mizuServiceAccountExists,
|
MizuServiceAccountExists: state.mizuServiceAccountExists,
|
||||||
ServiceMesh: config.Config.Tap.ServiceMesh,
|
ServiceMesh: config.Config.Tap.ServiceMesh,
|
||||||
Tls: config.Config.Tap.Tls,
|
Tls: config.Config.Tap.Tls,
|
||||||
|
MaxLiveStreams: config.Config.Tap.MaxLiveStreams,
|
||||||
}, startTime)
|
}, startTime)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -266,15 +229,6 @@ func getErrorDisplayTextForK8sTapManagerError(err kubernetes.K8sTapManagerError)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func readValidationRules(file string) (string, error) {
|
|
||||||
rules, err := shared.DecodeEnforcePolicy(file)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
newContent, _ := yaml.Marshal(&rules)
|
|
||||||
return string(newContent), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func getMizuApiFilteringOptions() (*api.TrafficFilteringOptions, error) {
|
func getMizuApiFilteringOptions() (*api.TrafficFilteringOptions, error) {
|
||||||
var compiledRegexSlice []*api.SerializableRegexp
|
var compiledRegexSlice []*api.SerializableRegexp
|
||||||
|
|
||||||
@@ -292,23 +246,10 @@ func getMizuApiFilteringOptions() (*api.TrafficFilteringOptions, error) {
|
|||||||
return &api.TrafficFilteringOptions{
|
return &api.TrafficFilteringOptions{
|
||||||
PlainTextMaskingRegexes: compiledRegexSlice,
|
PlainTextMaskingRegexes: compiledRegexSlice,
|
||||||
IgnoredUserAgents: config.Config.Tap.IgnoredUserAgents,
|
IgnoredUserAgents: config.Config.Tap.IgnoredUserAgents,
|
||||||
DisableRedaction: config.Config.Tap.DisableRedaction,
|
EnableRedaction: config.Config.Tap.EnableRedaction,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getSyncEntriesConfig() *shared.SyncEntriesConfig {
|
|
||||||
if !config.Config.Tap.Analysis && config.Config.Tap.Workspace == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return &shared.SyncEntriesConfig{
|
|
||||||
Token: config.Config.Auth.Token,
|
|
||||||
Env: config.Config.Auth.EnvName,
|
|
||||||
Workspace: config.Config.Tap.Workspace,
|
|
||||||
UploadIntervalSec: config.Config.Tap.UploadIntervalSec,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func watchApiServerPod(ctx context.Context, kubernetesProvider *kubernetes.Provider, cancel context.CancelFunc) {
|
func watchApiServerPod(ctx context.Context, kubernetesProvider *kubernetes.Provider, cancel context.CancelFunc) {
|
||||||
podExactRegex := regexp.MustCompile(fmt.Sprintf("^%s$", kubernetes.ApiServerPodName))
|
podExactRegex := regexp.MustCompile(fmt.Sprintf("^%s$", kubernetes.ApiServerPodName))
|
||||||
podWatchHelper := kubernetes.NewPodWatchHelper(kubernetesProvider, podExactRegex)
|
podWatchHelper := kubernetes.NewPodWatchHelper(kubernetesProvider, podExactRegex)
|
||||||
|
|||||||
@@ -85,27 +85,6 @@ func WriteConfig(config *ConfigStruct) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
type updateConfigStruct func(*ConfigStruct)
|
|
||||||
|
|
||||||
func UpdateConfig(updateConfigStruct updateConfigStruct) error {
|
|
||||||
configFile, err := GetConfigWithDefaults()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("failed getting config with defaults, err: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := loadConfigFile(Config.ConfigFilePath, configFile); err != nil && !os.IsNotExist(err) {
|
|
||||||
return fmt.Errorf("failed getting config file, err: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
updateConfigStruct(configFile)
|
|
||||||
|
|
||||||
if err := WriteConfig(configFile); err != nil {
|
|
||||||
return fmt.Errorf("failed writing config, err: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadConfigFile(configFilePath string, config *ConfigStruct) error {
|
func loadConfigFile(configFilePath string, config *ConfigStruct) error {
|
||||||
reader, openErr := os.Open(configFilePath)
|
reader, openErr := os.Open(configFilePath)
|
||||||
if openErr != nil {
|
if openErr != nil {
|
||||||
|
|||||||
@@ -27,7 +27,6 @@ type ConfigStruct struct {
|
|||||||
Version configStructs.VersionConfig `yaml:"version"`
|
Version configStructs.VersionConfig `yaml:"version"`
|
||||||
View configStructs.ViewConfig `yaml:"view"`
|
View configStructs.ViewConfig `yaml:"view"`
|
||||||
Logs configStructs.LogsConfig `yaml:"logs"`
|
Logs configStructs.LogsConfig `yaml:"logs"`
|
||||||
Auth configStructs.AuthConfig `yaml:"auth"`
|
|
||||||
Config configStructs.ConfigConfig `yaml:"config,omitempty"`
|
Config configStructs.ConfigConfig `yaml:"config,omitempty"`
|
||||||
AgentImage string `yaml:"agent-image,omitempty" readonly:""`
|
AgentImage string `yaml:"agent-image,omitempty" readonly:""`
|
||||||
ImagePullPolicyStr string `yaml:"image-pull-policy" default:"Always"`
|
ImagePullPolicyStr string `yaml:"image-pull-policy" default:"Always"`
|
||||||
@@ -40,8 +39,7 @@ type ConfigStruct struct {
|
|||||||
HeadlessMode bool `yaml:"headless" default:"false"`
|
HeadlessMode bool `yaml:"headless" default:"false"`
|
||||||
LogLevelStr string `yaml:"log-level,omitempty" default:"INFO" readonly:""`
|
LogLevelStr string `yaml:"log-level,omitempty" default:"INFO" readonly:""`
|
||||||
ServiceMap bool `yaml:"service-map" default:"true"`
|
ServiceMap bool `yaml:"service-map" default:"true"`
|
||||||
OAS bool `yaml:"oas" default:"true"`
|
OAS shared.OASConfig `yaml:"oas"`
|
||||||
Elastic shared.ElasticConfig `yaml:"elastic"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (config *ConfigStruct) validate() error {
|
func (config *ConfigStruct) validate() error {
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
package configStructs
|
|
||||||
|
|
||||||
type AuthConfig struct {
|
|
||||||
EnvName string `yaml:"env-name" default:"up9.app"`
|
|
||||||
Token string `yaml:"token"`
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,11 @@
|
|||||||
package configStructs
|
package configStructs
|
||||||
|
|
||||||
|
const (
|
||||||
|
OutInstallName = "out"
|
||||||
|
)
|
||||||
|
|
||||||
type InstallConfig struct {
|
type InstallConfig struct {
|
||||||
TemplateUrl string `yaml:"template-url" default:"https://storage.googleapis.com/static.up9.io/mizu/helm-template"`
|
TemplateUrl string `yaml:"template-url" default:"https://storage.googleapis.com/static.up9.io/mizu/helm-template"`
|
||||||
TemplateName string `yaml:"template-name" default:"helm-template.yaml"`
|
TemplateName string `yaml:"template-name" default:"helm-template.yaml"`
|
||||||
|
Out bool `yaml:"out"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package configStructs
|
package configStructs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/fs"
|
"io/fs"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@@ -18,42 +17,36 @@ import (
|
|||||||
const (
|
const (
|
||||||
GuiPortTapName = "gui-port"
|
GuiPortTapName = "gui-port"
|
||||||
NamespacesTapName = "namespaces"
|
NamespacesTapName = "namespaces"
|
||||||
AnalysisTapName = "analysis"
|
|
||||||
AllNamespacesTapName = "all-namespaces"
|
AllNamespacesTapName = "all-namespaces"
|
||||||
PlainTextFilterRegexesTapName = "regex-masking"
|
PlainTextFilterRegexesTapName = "regex-masking"
|
||||||
DisableRedactionTapName = "no-redact"
|
EnableRedactionTapName = "redact"
|
||||||
HumanMaxEntriesDBSizeTapName = "max-entries-db-size"
|
HumanMaxEntriesDBSizeTapName = "max-entries-db-size"
|
||||||
InsertionFilterName = "insertion-filter"
|
InsertionFilterName = "insertion-filter"
|
||||||
DryRunTapName = "dry-run"
|
DryRunTapName = "dry-run"
|
||||||
WorkspaceTapName = "workspace"
|
|
||||||
EnforcePolicyFile = "traffic-validation-file"
|
|
||||||
ContractFile = "contract"
|
|
||||||
ServiceMeshName = "service-mesh"
|
ServiceMeshName = "service-mesh"
|
||||||
TlsName = "tls"
|
TlsName = "tls"
|
||||||
|
ProfilerName = "profiler"
|
||||||
|
MaxLiveStreamsName = "max-live-streams"
|
||||||
)
|
)
|
||||||
|
|
||||||
type TapConfig struct {
|
type TapConfig struct {
|
||||||
UploadIntervalSec int `yaml:"upload-interval" default:"10"`
|
|
||||||
PodRegexStr string `yaml:"regex" default:".*"`
|
PodRegexStr string `yaml:"regex" default:".*"`
|
||||||
GuiPort uint16 `yaml:"gui-port" default:"8899"`
|
GuiPort uint16 `yaml:"gui-port" default:"8899"`
|
||||||
ProxyHost string `yaml:"proxy-host" default:"127.0.0.1"`
|
ProxyHost string `yaml:"proxy-host" default:"127.0.0.1"`
|
||||||
Namespaces []string `yaml:"namespaces"`
|
Namespaces []string `yaml:"namespaces"`
|
||||||
Analysis bool `yaml:"analysis" default:"false"`
|
|
||||||
AllNamespaces bool `yaml:"all-namespaces" default:"false"`
|
AllNamespaces bool `yaml:"all-namespaces" default:"false"`
|
||||||
PlainTextFilterRegexes []string `yaml:"regex-masking"`
|
PlainTextFilterRegexes []string `yaml:"regex-masking"`
|
||||||
IgnoredUserAgents []string `yaml:"ignored-user-agents"`
|
IgnoredUserAgents []string `yaml:"ignored-user-agents"`
|
||||||
DisableRedaction bool `yaml:"no-redact" default:"false"`
|
EnableRedaction bool `yaml:"redact" default:"false"`
|
||||||
HumanMaxEntriesDBSize string `yaml:"max-entries-db-size" default:"200MB"`
|
HumanMaxEntriesDBSize string `yaml:"max-entries-db-size" default:"200MB"`
|
||||||
InsertionFilter string `yaml:"insertion-filter" default:""`
|
InsertionFilter string `yaml:"insertion-filter" default:""`
|
||||||
DryRun bool `yaml:"dry-run" default:"false"`
|
DryRun bool `yaml:"dry-run" default:"false"`
|
||||||
Workspace string `yaml:"workspace"`
|
|
||||||
EnforcePolicyFile string `yaml:"traffic-validation-file"`
|
|
||||||
ContractFile string `yaml:"contract"`
|
|
||||||
AskUploadConfirmation bool `yaml:"ask-upload-confirmation" default:"true"`
|
|
||||||
ApiServerResources shared.Resources `yaml:"api-server-resources"`
|
ApiServerResources shared.Resources `yaml:"api-server-resources"`
|
||||||
TapperResources shared.Resources `yaml:"tapper-resources"`
|
TapperResources shared.Resources `yaml:"tapper-resources"`
|
||||||
ServiceMesh bool `yaml:"service-mesh" default:"false"`
|
ServiceMesh bool `yaml:"service-mesh" default:"false"`
|
||||||
Tls bool `yaml:"tls" default:"false"`
|
Tls bool `yaml:"tls" default:"false"`
|
||||||
|
Profiler bool `yaml:"profiler" default:"false"`
|
||||||
|
MaxLiveStreams int `yaml:"max-live-streams" default:"500"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (config *TapConfig) PodRegex() *regexp.Regexp {
|
func (config *TapConfig) PodRegex() *regexp.Regexp {
|
||||||
@@ -92,16 +85,5 @@ func (config *TapConfig) Validate() error {
|
|||||||
return fmt.Errorf("Could not parse --%s value %s", HumanMaxEntriesDBSizeTapName, config.HumanMaxEntriesDBSize)
|
return fmt.Errorf("Could not parse --%s value %s", HumanMaxEntriesDBSizeTapName, config.HumanMaxEntriesDBSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.Workspace != "" {
|
|
||||||
workspaceRegex, _ := regexp.Compile("[A-Za-z0-9][-A-Za-z0-9_.]*[A-Za-z0-9]+$")
|
|
||||||
if len(config.Workspace) > 63 || !workspaceRegex.MatchString(config.Workspace) {
|
|
||||||
return errors.New("invalid workspace name")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if config.Analysis && config.Workspace != "" {
|
|
||||||
return fmt.Errorf("Can't run with both --%s and --%s flags", AnalysisTapName, WorkspaceTapName)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
10
cli/go.mod
10
cli/go.mod
@@ -5,16 +5,13 @@ go 1.17
|
|||||||
require (
|
require (
|
||||||
github.com/creasty/defaults v1.5.2
|
github.com/creasty/defaults v1.5.2
|
||||||
github.com/denisbrodbeck/machineid v1.0.1
|
github.com/denisbrodbeck/machineid v1.0.1
|
||||||
github.com/getkin/kin-openapi v0.89.0
|
|
||||||
github.com/google/go-github/v37 v37.0.0
|
github.com/google/go-github/v37 v37.0.0
|
||||||
github.com/google/uuid v1.3.0
|
|
||||||
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
|
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
|
||||||
github.com/spf13/cobra v1.3.0
|
github.com/spf13/cobra v1.3.0
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
github.com/up9inc/mizu/logger v0.0.0
|
github.com/up9inc/mizu/logger v0.0.0
|
||||||
github.com/up9inc/mizu/shared v0.0.0
|
github.com/up9inc/mizu/shared v0.0.0
|
||||||
github.com/up9inc/mizu/tap/api v0.0.0
|
github.com/up9inc/mizu/tap/api v0.0.0
|
||||||
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||||
k8s.io/api v0.23.3
|
k8s.io/api v0.23.3
|
||||||
k8s.io/apimachinery v0.23.3
|
k8s.io/apimachinery v0.23.3
|
||||||
@@ -39,7 +36,6 @@ require (
|
|||||||
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
|
github.com/evanphx/json-patch v5.6.0+incompatible // indirect
|
||||||
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
|
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
|
||||||
github.com/fvbommel/sortorder v1.0.2 // indirect
|
github.com/fvbommel/sortorder v1.0.2 // indirect
|
||||||
github.com/ghodss/yaml v1.0.0 // indirect
|
|
||||||
github.com/go-errors/errors v1.4.2 // indirect
|
github.com/go-errors/errors v1.4.2 // indirect
|
||||||
github.com/go-logr/logr v1.2.2 // indirect
|
github.com/go-logr/logr v1.2.2 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
github.com/go-openapi/jsonpointer v0.19.5 // indirect
|
||||||
@@ -52,8 +48,8 @@ require (
|
|||||||
github.com/google/go-cmp v0.5.7 // indirect
|
github.com/google/go-cmp v0.5.7 // indirect
|
||||||
github.com/google/go-querystring v1.1.0 // indirect
|
github.com/google/go-querystring v1.1.0 // indirect
|
||||||
github.com/google/gofuzz v1.2.0 // indirect
|
github.com/google/gofuzz v1.2.0 // indirect
|
||||||
github.com/google/martian v2.1.0+incompatible // indirect
|
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||||
|
github.com/google/uuid v1.3.0 // indirect
|
||||||
github.com/googleapis/gnostic v0.5.5 // indirect
|
github.com/googleapis/gnostic v0.5.5 // indirect
|
||||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
|
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
|
||||||
github.com/imdario/mergo v0.3.12 // indirect
|
github.com/imdario/mergo v0.3.12 // indirect
|
||||||
@@ -74,10 +70,12 @@ require (
|
|||||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
github.com/russross/blackfriday v1.6.0 // indirect
|
github.com/russross/blackfriday v1.6.0 // indirect
|
||||||
github.com/stretchr/testify v1.7.0 // indirect
|
github.com/stretchr/testify v1.7.0 // indirect
|
||||||
|
github.com/up9inc/mizu/tap/dbgctl v0.0.0 // indirect
|
||||||
github.com/xlab/treeprint v1.1.0 // indirect
|
github.com/xlab/treeprint v1.1.0 // indirect
|
||||||
go.starlark.net v0.0.0-20220203230714-bb14e151c28f // indirect
|
go.starlark.net v0.0.0-20220203230714-bb14e151c28f // indirect
|
||||||
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab // indirect
|
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab // indirect
|
||||||
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
|
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
|
||||||
|
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
|
||||||
golang.org/x/sys v0.0.0-20220207234003-57398862261d // indirect
|
golang.org/x/sys v0.0.0-20220207234003-57398862261d // indirect
|
||||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
|
||||||
golang.org/x/text v0.3.7 // indirect
|
golang.org/x/text v0.3.7 // indirect
|
||||||
@@ -104,3 +102,5 @@ replace github.com/up9inc/mizu/logger v0.0.0 => ../logger
|
|||||||
replace github.com/up9inc/mizu/shared v0.0.0 => ../shared
|
replace github.com/up9inc/mizu/shared v0.0.0 => ../shared
|
||||||
|
|
||||||
replace github.com/up9inc/mizu/tap/api v0.0.0 => ../tap/api
|
replace github.com/up9inc/mizu/tap/api v0.0.0 => ../tap/api
|
||||||
|
|
||||||
|
replace github.com/up9inc/mizu/tap/dbgctl v0.0.0 => ../tap/dbgctl
|
||||||
|
|||||||
@@ -190,9 +190,6 @@ github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui72
|
|||||||
github.com/fvbommel/sortorder v1.0.2 h1:mV4o8B2hKboCdkJm+a7uX/SIpZob4JzUpc5GGnM45eo=
|
github.com/fvbommel/sortorder v1.0.2 h1:mV4o8B2hKboCdkJm+a7uX/SIpZob4JzUpc5GGnM45eo=
|
||||||
github.com/fvbommel/sortorder v1.0.2/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
|
github.com/fvbommel/sortorder v1.0.2/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
|
||||||
github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
|
github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
|
||||||
github.com/getkin/kin-openapi v0.89.0 h1:p4nagHchUKGn85z/f+pse4aSh50nIBOYjOhMIku2hiA=
|
|
||||||
github.com/getkin/kin-openapi v0.89.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
|
|
||||||
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
|
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
|
||||||
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
|
||||||
@@ -294,7 +291,6 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
|
|||||||
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
|
||||||
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
|
|
||||||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
|
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=
|
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||||
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ var (
|
|||||||
BuildTimestamp = "" // this var is overridden using ldflags in makefile when building
|
BuildTimestamp = "" // this var is overridden using ldflags in makefile when building
|
||||||
RBACVersion = "v1"
|
RBACVersion = "v1"
|
||||||
Platform = ""
|
Platform = ""
|
||||||
InstallModePersistentVolumeSizeBufferBytes = int64(500 * 1000 * 1000) //500mb
|
|
||||||
)
|
)
|
||||||
|
|
||||||
const DEVENVVAR = "MIZU_DISABLE_TELEMTRY"
|
const DEVENVVAR = "MIZU_DISABLE_TELEMTRY"
|
||||||
|
|||||||
@@ -10,32 +10,13 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/up9inc/mizu/cli/apiserver"
|
|
||||||
"github.com/up9inc/mizu/cli/mizu"
|
"github.com/up9inc/mizu/cli/mizu"
|
||||||
"github.com/up9inc/mizu/cli/pkg/version"
|
"github.com/up9inc/mizu/cli/pkg/version"
|
||||||
"github.com/up9inc/mizu/logger"
|
"github.com/up9inc/mizu/logger"
|
||||||
|
|
||||||
"github.com/google/go-github/v37/github"
|
"github.com/google/go-github/v37/github"
|
||||||
"github.com/up9inc/mizu/cli/uiUtils"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func CheckVersionCompatibility(apiServerProvider *apiserver.Provider) (bool, error) {
|
|
||||||
apiVer, err := apiServerProvider.GetVersion()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if equals, err := version.AreEquals(apiVer, mizu.Ver); err != nil {
|
|
||||||
return false, fmt.Errorf("Failed to check version equality between mizuVer: %s and apiVer: %s, error: %w", mizu.Ver, apiVer, err)
|
|
||||||
} else if !equals {
|
|
||||||
logger.Log.Errorf(uiUtils.Red, fmt.Sprintf("cli version (%s) is not compatible with api version (%s)", mizu.Ver, apiVer))
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Log.Debug("cli version %s is compatible with api version %s", mizu.Ver, apiVer)
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func CheckNewerVersion(versionChan chan string) {
|
func CheckNewerVersion(versionChan chan string) {
|
||||||
if _, present := os.LookupEnv(mizu.DEVENVVAR); present {
|
if _, present := os.LookupEnv(mizu.DEVENVVAR); present {
|
||||||
versionChan <- ""
|
versionChan <- ""
|
||||||
|
|||||||
@@ -14,14 +14,14 @@ import (
|
|||||||
core "k8s.io/api/core/v1"
|
core "k8s.io/api/core/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CreateTapMizuResources(ctx context.Context, kubernetesProvider *kubernetes.Provider, serializedValidationRules string, serializedContract string, serializedMizuConfig string, isNsRestrictedMode bool, mizuResourcesNamespace string, agentImage string, syncEntriesConfig *shared.SyncEntriesConfig, maxEntriesDBSizeBytes int64, apiServerResources shared.Resources, imagePullPolicy core.PullPolicy, logLevel logging.Level) (bool, error) {
|
func CreateTapMizuResources(ctx context.Context, kubernetesProvider *kubernetes.Provider, serializedMizuConfig string, isNsRestrictedMode bool, mizuResourcesNamespace string, agentImage string, maxEntriesDBSizeBytes int64, apiServerResources shared.Resources, imagePullPolicy core.PullPolicy, logLevel logging.Level, profiler bool) (bool, error) {
|
||||||
if !isNsRestrictedMode {
|
if !isNsRestrictedMode {
|
||||||
if err := createMizuNamespace(ctx, kubernetesProvider, mizuResourcesNamespace); err != nil {
|
if err := createMizuNamespace(ctx, kubernetesProvider, mizuResourcesNamespace); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := createMizuConfigmap(ctx, kubernetesProvider, serializedValidationRules, serializedContract, serializedMizuConfig, mizuResourcesNamespace); err != nil {
|
if err := createMizuConfigmap(ctx, kubernetesProvider, serializedMizuConfig, mizuResourcesNamespace); err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,11 +45,11 @@ func CreateTapMizuResources(ctx context.Context, kubernetesProvider *kubernetes.
|
|||||||
KetoImage: "",
|
KetoImage: "",
|
||||||
ServiceAccountName: serviceAccountName,
|
ServiceAccountName: serviceAccountName,
|
||||||
IsNamespaceRestricted: isNsRestrictedMode,
|
IsNamespaceRestricted: isNsRestrictedMode,
|
||||||
SyncEntriesConfig: syncEntriesConfig,
|
|
||||||
MaxEntriesDBSizeBytes: maxEntriesDBSizeBytes,
|
MaxEntriesDBSizeBytes: maxEntriesDBSizeBytes,
|
||||||
Resources: apiServerResources,
|
Resources: apiServerResources,
|
||||||
ImagePullPolicy: imagePullPolicy,
|
ImagePullPolicy: imagePullPolicy,
|
||||||
LogLevel: logLevel,
|
LogLevel: logLevel,
|
||||||
|
Profiler: profiler,
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := createMizuApiServerPod(ctx, kubernetesProvider, opts); err != nil {
|
if err := createMizuApiServerPod(ctx, kubernetesProvider, opts); err != nil {
|
||||||
@@ -71,8 +71,8 @@ func createMizuNamespace(ctx context.Context, kubernetesProvider *kubernetes.Pro
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func createMizuConfigmap(ctx context.Context, kubernetesProvider *kubernetes.Provider, serializedValidationRules string, serializedContract string, serializedMizuConfig string, mizuResourcesNamespace string) error {
|
func createMizuConfigmap(ctx context.Context, kubernetesProvider *kubernetes.Provider, serializedMizuConfig string, mizuResourcesNamespace string) error {
|
||||||
err := kubernetesProvider.CreateConfigMap(ctx, mizuResourcesNamespace, kubernetes.ConfigMapName, serializedValidationRules, serializedContract, serializedMizuConfig)
|
err := kubernetesProvider.CreateConfigMap(ctx, mizuResourcesNamespace, kubernetes.ConfigMapName, serializedMizuConfig)
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -73,11 +73,7 @@ func shouldRunTelemetry() bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
if mizu.Branch != "main" && mizu.Branch != "develop" {
|
return mizu.Branch == "main" || mizu.Branch == "develop"
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendTelemetry(argsMap map[string]interface{}) error {
|
func sendTelemetry(argsMap map[string]interface{}) error {
|
||||||
|
|||||||
@@ -1,26 +0,0 @@
|
|||||||
package uiUtils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"bufio"
|
|
||||||
"fmt"
|
|
||||||
"os"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/up9inc/mizu/logger"
|
|
||||||
)
|
|
||||||
|
|
||||||
func AskForConfirmation(s string) bool {
|
|
||||||
reader := bufio.NewReader(os.Stdin)
|
|
||||||
|
|
||||||
fmt.Printf(Magenta, s)
|
|
||||||
|
|
||||||
response, err := reader.ReadString('\n')
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Fatalf("Error while reading confirmation string, err: %v", err)
|
|
||||||
}
|
|
||||||
response = strings.ToLower(strings.TrimSpace(response))
|
|
||||||
if response == "" || response == "y" || response == "yes" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
package up9
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"net/http"
|
|
||||||
"net/url"
|
|
||||||
)
|
|
||||||
|
|
||||||
func IsTokenValid(tokenString string, envName string) bool {
|
|
||||||
whoAmIUrl, _ := url.Parse(fmt.Sprintf("https://trcc.%s/admin/whoami", envName))
|
|
||||||
|
|
||||||
req := &http.Request{
|
|
||||||
Method: http.MethodGet,
|
|
||||||
URL: whoAmIUrl,
|
|
||||||
Header: map[string][]string{
|
|
||||||
"Authorization": {fmt.Sprintf("bearer %s", tokenString)},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
response, err := http.DefaultClient.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
defer response.Body.Close()
|
|
||||||
|
|
||||||
return response.StatusCode == http.StatusOK
|
|
||||||
}
|
|
||||||
12
devops/install-capstone.sh
Executable file
12
devops/install-capstone.sh
Executable file
@@ -0,0 +1,12 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
SUDO=''
|
||||||
|
if (( $EUID != 0 )); then
|
||||||
|
SUDO='sudo'
|
||||||
|
fi
|
||||||
|
|
||||||
|
curl https://github.com/capstone-engine/capstone/releases/download/5.0-rc2/capstone-5.0-rc2.tar.xz -Lo ./capstone.tar.xz \
|
||||||
|
&& tar -xf capstone.tar.xz && mv ./capstone-* ./capstone \
|
||||||
|
&& cd capstone \
|
||||||
|
&& CAPSTONE_ARCHS="aarch64 x86" ./make.sh \
|
||||||
|
&& $SUDO ./make.sh install
|
||||||
@@ -17,4 +17,14 @@ RUN curl https://www.tcpdump.org/release/libpcap-1.10.1.tar.gz -Lo ./libpcap.tar
|
|||||||
WORKDIR /work/libpcap
|
WORKDIR /work/libpcap
|
||||||
RUN ./configure --host=arm && make \
|
RUN ./configure --host=arm && make \
|
||||||
&& cp /work/libpcap/libpcap.a /usr/xcc/aarch64-linux-musl-cross/lib/gcc/aarch64-linux-musl/*/
|
&& cp /work/libpcap/libpcap.a /usr/xcc/aarch64-linux-musl-cross/lib/gcc/aarch64-linux-musl/*/
|
||||||
|
WORKDIR /work
|
||||||
|
|
||||||
|
# Build and install Capstone from source
|
||||||
|
RUN curl https://github.com/capstone-engine/capstone/releases/download/5.0-rc2/capstone-5.0-rc2.tar.xz -Lo ./capstone.tar.xz \
|
||||||
|
&& tar -xf capstone.tar.xz && mv ./capstone-* ./capstone
|
||||||
|
WORKDIR /work/capstone
|
||||||
|
RUN CAPSTONE_ARCHS="aarch64" CAPSTONE_STATIC=yes ./make.sh \
|
||||||
|
&& cp /work/capstone/libcapstone.a /usr/xcc/aarch64-linux-musl-cross/lib/gcc/aarch64-linux-musl/*/
|
||||||
|
|
||||||
|
# Install eBPF related dependencies
|
||||||
|
RUN apt-get -y install clang llvm libbpf-dev
|
||||||
5
devops/linux-arm64-musl-go-libpcap-capstone-bpf/build-push.sh
Executable file
5
devops/linux-arm64-musl-go-libpcap-capstone-bpf/build-push.sh
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Build it on x86_64
|
||||||
|
docker build . -t up9inc/linux-arm64-musl-go-libpcap-capstone-bpf:capstone-5.0-rc2 && docker push up9inc/linux-arm64-musl-go-libpcap-capstone-bpf:capstone-5.0-rc2
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -e
|
|
||||||
|
|
||||||
docker build . -t up9inc/linux-arm64-musl-go-libpcap && docker push up9inc/linux-arm64-musl-go-libpcap
|
|
||||||
@@ -1,5 +1,18 @@
|
|||||||
FROM messense/rust-musl-cross:x86_64-musl AS builder-from-arm64v8-to-amd64
|
FROM messense/rust-musl-cross:x86_64-musl AS builder-from-arm64v8-to-amd64
|
||||||
|
|
||||||
|
WORKDIR /
|
||||||
|
|
||||||
|
# Install eBPF related dependencies
|
||||||
|
RUN apt-get update
|
||||||
|
RUN apt-get -y install clang llvm libelf-dev pkg-config
|
||||||
|
|
||||||
|
# Build and install libbpf from source
|
||||||
|
RUN curl https://github.com/libbpf/libbpf/archive/refs/tags/v0.8.0.tar.gz -Lo ./libbpf.tar.gz \
|
||||||
|
&& tar -xzf libbpf.tar.gz && mv ./libbpf-* ./libbpf
|
||||||
|
WORKDIR /libbpf/src
|
||||||
|
RUN make && make install
|
||||||
|
WORKDIR /
|
||||||
|
|
||||||
ENV CROSS_TRIPLE x86_64-unknown-linux-musl
|
ENV CROSS_TRIPLE x86_64-unknown-linux-musl
|
||||||
ENV CROSS_ROOT /usr/local/musl
|
ENV CROSS_ROOT /usr/local/musl
|
||||||
|
|
||||||
@@ -12,7 +25,6 @@ ENV AS=${CROSS_ROOT}/bin/${CROSS_TRIPLE}-as \
|
|||||||
FC=${CROSS_ROOT}/bin/${CROSS_TRIPLE}-gfortran
|
FC=${CROSS_ROOT}/bin/${CROSS_TRIPLE}-gfortran
|
||||||
|
|
||||||
# Install Go
|
# Install Go
|
||||||
WORKDIR /
|
|
||||||
RUN curl https://go.dev/dl/go1.17.6.linux-arm64.tar.gz -Lo ./go.linux-arm64.tar.gz \
|
RUN curl https://go.dev/dl/go1.17.6.linux-arm64.tar.gz -Lo ./go.linux-arm64.tar.gz \
|
||||||
&& curl https://go.dev/dl/go1.17.6.linux-arm64.tar.gz.asc -Lo ./go.linux-arm64.tar.gz.asc \
|
&& curl https://go.dev/dl/go1.17.6.linux-arm64.tar.gz.asc -Lo ./go.linux-arm64.tar.gz.asc \
|
||||||
&& curl https://dl.google.com/dl/linux/linux_signing_key.pub -Lo linux_signing_key.pub \
|
&& curl https://dl.google.com/dl/linux/linux_signing_key.pub -Lo linux_signing_key.pub \
|
||||||
@@ -29,3 +41,11 @@ RUN curl https://www.tcpdump.org/release/libpcap-1.10.1.tar.gz -Lo ./libpcap.tar
|
|||||||
WORKDIR /libpcap
|
WORKDIR /libpcap
|
||||||
RUN ./configure --host=x86_64 && make \
|
RUN ./configure --host=x86_64 && make \
|
||||||
&& cp /libpcap/libpcap.a /usr/local/musl/lib/gcc/x86_64-unknown-linux-musl/*/
|
&& cp /libpcap/libpcap.a /usr/local/musl/lib/gcc/x86_64-unknown-linux-musl/*/
|
||||||
|
WORKDIR /
|
||||||
|
|
||||||
|
# Build and install Capstone from source
|
||||||
|
RUN curl https://github.com/capstone-engine/capstone/releases/download/5.0-rc2/capstone-5.0-rc2.tar.xz -Lo ./capstone.tar.xz \
|
||||||
|
&& tar -xf capstone.tar.xz && mv ./capstone-* ./capstone
|
||||||
|
WORKDIR /capstone
|
||||||
|
RUN CAPSTONE_ARCHS="x86" CAPSTONE_STATIC=yes ./make.sh \
|
||||||
|
&& cp /capstone/libcapstone.a /usr/local/musl/lib/gcc/x86_64-unknown-linux-musl/*/
|
||||||
5
devops/linux-x86_64-musl-go-libpcap-capstone-bpf/build-push.sh
Executable file
5
devops/linux-x86_64-musl-go-libpcap-capstone-bpf/build-push.sh
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Build it on arm64
|
||||||
|
docker build . -t up9inc/linux-x86_64-musl-go-libpcap-capstone-bpf:capstone-5.0-rc2 && docker push up9inc/linux-x86_64-musl-go-libpcap-capstone-bpf:capstone-5.0-rc2
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -e
|
|
||||||
|
|
||||||
docker build . -t up9inc/linux-x86_64-musl-go-libpcap && docker push up9inc/linux-x86_64-musl-go-libpcap
|
|
||||||
107
performance_analysis/README.md
Normal file
107
performance_analysis/README.md
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
|
||||||
|
# Performance analysis
|
||||||
|
|
||||||
|
This directory contains tools for analyzing tapper performance.
|
||||||
|
|
||||||
|
# Periodic tapper logs
|
||||||
|
|
||||||
|
In tapper logs there are some periodic lines that shows its internal state and consumed resources.
|
||||||
|
|
||||||
|
Internal state example (formatted and commented):
|
||||||
|
```
|
||||||
|
stats - {
|
||||||
|
"processedBytes":468940592, // how many bytes we read from pcap
|
||||||
|
"packetsCount":174883, // how many packets we read from pcap
|
||||||
|
"tcpPacketsCount":174883, // how many tcp packets we read from pcap
|
||||||
|
"reassembledTcpPayloadsCount":66893, // how many chunks sent to tcp stream
|
||||||
|
"matchedPairs":24821, // how many request response pairs found
|
||||||
|
"droppedTcpStreams":2 // how many tcp streams remained stale and dropped
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Consumed resources example (formatted and commented):
|
||||||
|
```
|
||||||
|
mem: 24441240, // golang heap size
|
||||||
|
goroutines: 29, // how many goroutines
|
||||||
|
cpu: 91.208791, // how much cpu the tapper process consume (in percentage per core)
|
||||||
|
cores: 16, // how many cores there are on the machine
|
||||||
|
rss: 87052288 // how many bytes held by the tapper process
|
||||||
|
```
|
||||||
|
|
||||||
|
# Plot tapper logs
|
||||||
|
|
||||||
|
In order to plot a tapper log or many logs into a graph, use the `plot_from_tapper_logs.py` util.
|
||||||
|
|
||||||
|
It gets a list of tapper logs as a parameter, and output an image with a nice graph.
|
||||||
|
|
||||||
|
The log file names should be named in this format `XX_DESCRIPTION.log` when XX is the number between determining the color of the output graph and description is the name of the series. It allows for easy comparison between various modes.
|
||||||
|
|
||||||
|
Example run:
|
||||||
|
```
|
||||||
|
cd $MIZU_HOME/performance_analysis
|
||||||
|
virtualenv venv
|
||||||
|
source venv/bin/activate
|
||||||
|
pip install -r requirements.txt
|
||||||
|
python plot_from_tapper_logs.py 00_tapper.log
|
||||||
|
```
|
||||||
|
|
||||||
|
# Tapper Modes
|
||||||
|
|
||||||
|
Every packet seen by the tapper is processed in a pipeline that contains various stages.
|
||||||
|
* Pcap - Read the packet from libpcap
|
||||||
|
* Assembler - Assemble the packet into a TcpStream
|
||||||
|
* TcpStream - Hold stream information and TcpReaders
|
||||||
|
* Dissectors - Read from TcpReader and recognize the packet content and protocol.
|
||||||
|
* Emit - Marshal the request response pair into a Json
|
||||||
|
* Send - Send the Json to Api Server
|
||||||
|
|
||||||
|
Tapper can be run with various debug modes:
|
||||||
|
* No Pcap - Start the tapper process, but don't read from any packets from pcap
|
||||||
|
* No Assembler - Read packets from pcap, but don't assemble them
|
||||||
|
* No TcpStream - Assemble the packets, but don't create TcpStream for them
|
||||||
|
* No Dissectors - Create a TcpStream for the packets, but don't dissect their content
|
||||||
|
* No Emit - Dissect the TcpStream, but don't emit the matched request response pair
|
||||||
|
* No Send - Emit the request response pair, but don't send them to the Api Server.
|
||||||
|
* Regular mode
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
# Run benchmark with various tapper modes
|
||||||
|
|
||||||
|
## Prerequisite
|
||||||
|
|
||||||
|
In order to run the benchmark you probably want:
|
||||||
|
1. An up and running Api Server
|
||||||
|
2. An up and running Basenine
|
||||||
|
3. An up and running UI (optional)
|
||||||
|
4. An up and running test server, like nginx, that can return a known payload at a known endpoint.
|
||||||
|
5. Set MIZU_HOME environment variable to points to mizu directory
|
||||||
|
6. Install the `hey` tool
|
||||||
|
|
||||||
|
## Running the benchmark
|
||||||
|
|
||||||
|
In order to run a benchmark use the `run_tapper_benchmark.sh` script.
|
||||||
|
|
||||||
|
Example run:
|
||||||
|
```
|
||||||
|
cd $MIZU_HOME/performance_analysis
|
||||||
|
source venv/bin/activate # Assuming you already run plot_from_tapper_logs.py
|
||||||
|
./run_tapper_benchmark.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Running it without params use the default values, use the following environment variables for customization:
|
||||||
|
```
|
||||||
|
export=MIZU_BENCHMARK_OUTPUT_DIR=/path/to/dir # Set the output directory for tapper logs and graph
|
||||||
|
export=MIZU_BENCHMARK_CLIENT_PERIOD=1m # How long each test run
|
||||||
|
export=MIZU_BENCHMARK_URL=http://server:port/path # The URL to use for the benchmarking process (the test server endpoint)
|
||||||
|
export=MIZU_BENCHMARK_RUN_COUNT=3 # How many times each tapper mode should run
|
||||||
|
export=MIZU_BENCHMARK_QPS=250 # How many queries per second the each client should send to the test server
|
||||||
|
export=MIZU_BENCHMARK_CLIENTS_COUNT=5 # How many clients should run in parallel during the benchmark
|
||||||
|
```
|
||||||
|
|
||||||
|
# Example output graph
|
||||||
|
|
||||||
|
An example output graph from a 15 min run with 15K payload and 1000 QPS looks like
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
BIN
performance_analysis/example-graph.png
Normal file
BIN
performance_analysis/example-graph.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 327 KiB |
182
performance_analysis/plot_from_tapper_logs.py
Normal file
182
performance_analysis/plot_from_tapper_logs.py
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
import matplotlib.pyplot as plt
|
||||||
|
import numpy as np
|
||||||
|
import pandas as pd
|
||||||
|
import pathlib
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
import typing
|
||||||
|
|
||||||
|
COLORMAP = plt.get_cmap('turbo')
|
||||||
|
|
||||||
|
# Extract cpu and rss samples from log files and plot them
|
||||||
|
# Input: List of log files
|
||||||
|
#
|
||||||
|
# example:
|
||||||
|
# python plot_from_tapper_logs.py 01_no_pcap_01.log 99_normal_00.log
|
||||||
|
#
|
||||||
|
# The script assumes that the log file names start with a number (pattern '\d+')
|
||||||
|
# and groups based on this number. Files that start will the same number will be plotted with the same color.
|
||||||
|
# Change group_pattern to an empty string to disable this, or change to a regex of your liking.
|
||||||
|
|
||||||
|
|
||||||
|
def get_sample(name: str, line: str, default_value: float):
|
||||||
|
pattern = name + r': ?(\d+(\.\d+)?)'
|
||||||
|
maybe_sample = re.findall(pattern, line)
|
||||||
|
if len(maybe_sample) == 0:
|
||||||
|
return default_value
|
||||||
|
|
||||||
|
sample = float(maybe_sample[0][0])
|
||||||
|
return sample
|
||||||
|
|
||||||
|
|
||||||
|
def append_sample(name: str, line: str, samples: typing.List[float]):
|
||||||
|
sample = get_sample(name, line, -1)
|
||||||
|
|
||||||
|
if sample == -1:
|
||||||
|
return
|
||||||
|
|
||||||
|
samples.append(sample)
|
||||||
|
|
||||||
|
|
||||||
|
def extract_samples(f: typing.IO) -> typing.Tuple[pd.Series, pd.Series, pd.Series, pd.Series, pd.Series, pd.Series, pd.Series, pd.Series]:
|
||||||
|
cpu_samples = []
|
||||||
|
rss_samples = []
|
||||||
|
count_samples = []
|
||||||
|
matched_samples = []
|
||||||
|
live_samples = []
|
||||||
|
processed_samples = []
|
||||||
|
heap_samples = []
|
||||||
|
goroutines_samples = []
|
||||||
|
for line in f:
|
||||||
|
append_sample('cpu', line, cpu_samples)
|
||||||
|
append_sample('rss', line, rss_samples)
|
||||||
|
ignored_packets_count = get_sample('"ignoredPacketsCount"', line, -1)
|
||||||
|
packets_count = get_sample('"packetsCount"', line, -1)
|
||||||
|
if ignored_packets_count != -1 and packets_count != -1:
|
||||||
|
count_samples.append(packets_count - ignored_packets_count)
|
||||||
|
append_sample('"matchedPairs"', line, matched_samples)
|
||||||
|
append_sample('"liveTcpStreams"', line, live_samples)
|
||||||
|
append_sample('"processedBytes"', line, processed_samples)
|
||||||
|
append_sample('heap-alloc', line, heap_samples)
|
||||||
|
append_sample('goroutines', line, goroutines_samples)
|
||||||
|
|
||||||
|
cpu_samples = pd.Series(cpu_samples)
|
||||||
|
rss_samples = pd.Series(rss_samples)
|
||||||
|
count_samples = pd.Series(count_samples)
|
||||||
|
matched_samples = pd.Series(matched_samples)
|
||||||
|
live_samples = pd.Series(live_samples)
|
||||||
|
processed_samples = pd.Series(processed_samples)
|
||||||
|
heap_samples = pd.Series(heap_samples)
|
||||||
|
goroutines_samples = pd.Series(goroutines_samples)
|
||||||
|
|
||||||
|
return cpu_samples, rss_samples, count_samples, matched_samples, live_samples, processed_samples, heap_samples, goroutines_samples
|
||||||
|
|
||||||
|
|
||||||
|
def plot(ax, df: pd.DataFrame, title: str, xlabel: str, ylabel: str, group_pattern: typing.Optional[str]):
|
||||||
|
if group_pattern:
|
||||||
|
color = get_group_color(df.columns, group_pattern)
|
||||||
|
df.plot(color=color, ax=ax)
|
||||||
|
else:
|
||||||
|
df.plot(cmap=COLORMAP, ax=ax)
|
||||||
|
|
||||||
|
ax.ticklabel_format(style='plain')
|
||||||
|
plt.title(title)
|
||||||
|
plt.legend()
|
||||||
|
plt.xlabel(xlabel)
|
||||||
|
plt.ylabel(ylabel)
|
||||||
|
|
||||||
|
|
||||||
|
def get_group_color(names, pattern):
|
||||||
|
props = [int(re.findall(pattern, pathlib.Path(name).name)[0]) for name in names]
|
||||||
|
key = dict(zip(sorted(list(set(props))), range(len(set(props)))))
|
||||||
|
n_colors = len(key)
|
||||||
|
color_options = plt.get_cmap('jet')(np.linspace(0, 1, n_colors))
|
||||||
|
groups = [key[prop] for prop in props]
|
||||||
|
color = color_options[groups] # type: ignore
|
||||||
|
return color
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
filenames = sys.argv[1:]
|
||||||
|
|
||||||
|
cpu_samples_all_files = []
|
||||||
|
rss_samples_all_files = []
|
||||||
|
count_samples_all_files = []
|
||||||
|
matched_samples_all_files = []
|
||||||
|
live_samples_all_files = []
|
||||||
|
processed_samples_all_files = []
|
||||||
|
heap_samples_all_files = []
|
||||||
|
goroutines_samples_all_files = []
|
||||||
|
|
||||||
|
for ii, filename in enumerate(filenames):
|
||||||
|
print("Analyzing {}".format(filename))
|
||||||
|
with open(filename, 'r') as f:
|
||||||
|
cpu_samples, rss_samples, count_samples, matched_samples, live_samples, processed_samples, heap_samples, goroutines_samples = extract_samples(f)
|
||||||
|
|
||||||
|
cpu_samples.name = pathlib.Path(filename).name
|
||||||
|
rss_samples.name = pathlib.Path(filename).name
|
||||||
|
count_samples.name = pathlib.Path(filename).name
|
||||||
|
matched_samples.name = pathlib.Path(filename).name
|
||||||
|
live_samples.name = pathlib.Path(filename).name
|
||||||
|
processed_samples.name = pathlib.Path(filename).name
|
||||||
|
heap_samples.name = pathlib.Path(filename).name
|
||||||
|
goroutines_samples.name = pathlib.Path(filename).name
|
||||||
|
|
||||||
|
cpu_samples_all_files.append(cpu_samples)
|
||||||
|
rss_samples_all_files.append(rss_samples)
|
||||||
|
count_samples_all_files.append(count_samples)
|
||||||
|
matched_samples_all_files.append(matched_samples)
|
||||||
|
live_samples_all_files.append(live_samples)
|
||||||
|
processed_samples_all_files.append(processed_samples)
|
||||||
|
heap_samples_all_files.append(heap_samples)
|
||||||
|
goroutines_samples_all_files.append(goroutines_samples)
|
||||||
|
|
||||||
|
cpu_samples_df = pd.concat(cpu_samples_all_files, axis=1)
|
||||||
|
rss_samples_df = pd.concat(rss_samples_all_files, axis=1)
|
||||||
|
count_samples_df = pd.concat(count_samples_all_files, axis=1)
|
||||||
|
matched_samples_df = pd.concat(matched_samples_all_files, axis=1)
|
||||||
|
live_samples_df = pd.concat(live_samples_all_files, axis=1)
|
||||||
|
processed_samples_df = pd.concat(processed_samples_all_files, axis=1)
|
||||||
|
heap_samples_df = pd.concat(heap_samples_all_files, axis=1)
|
||||||
|
goroutines_samples_df = pd.concat(goroutines_samples_all_files, axis=1)
|
||||||
|
|
||||||
|
group_pattern = r'^\d+'
|
||||||
|
|
||||||
|
cpu_plot = plt.subplot(8, 2, 1)
|
||||||
|
plot(cpu_plot, cpu_samples_df, 'cpu', '', 'cpu (%)', group_pattern)
|
||||||
|
cpu_plot.legend().remove()
|
||||||
|
|
||||||
|
mem_plot = plt.subplot(8, 2, 2)
|
||||||
|
plot(mem_plot, (rss_samples_df / 1024 / 1024), 'rss', '', 'mem (mega)', group_pattern)
|
||||||
|
mem_plot.legend(loc='center left', bbox_to_anchor=(1, 0.5))
|
||||||
|
|
||||||
|
packets_plot = plt.subplot(8, 2, 3)
|
||||||
|
plot(packets_plot, count_samples_df, 'packetsCount', '', 'packetsCount', group_pattern)
|
||||||
|
packets_plot.legend().remove()
|
||||||
|
|
||||||
|
matched_plot = plt.subplot(8, 2, 4)
|
||||||
|
plot(matched_plot, matched_samples_df, 'matchedCount', '', 'matchedCount', group_pattern)
|
||||||
|
matched_plot.legend().remove()
|
||||||
|
|
||||||
|
live_plot = plt.subplot(8, 2, 5)
|
||||||
|
plot(live_plot, live_samples_df, 'liveStreamsCount', '', 'liveStreamsCount', group_pattern)
|
||||||
|
live_plot.legend().remove()
|
||||||
|
|
||||||
|
processed_plot = plt.subplot(8, 2, 6)
|
||||||
|
plot(processed_plot, (processed_samples_df / 1024 / 1024), 'processedBytes', '', 'bytes (mega)', group_pattern)
|
||||||
|
processed_plot.legend().remove()
|
||||||
|
|
||||||
|
heap_plot = plt.subplot(8, 2, 7)
|
||||||
|
plot(heap_plot, (heap_samples_df / 1024 / 1024), 'heap', '', 'heap (mega)', group_pattern)
|
||||||
|
heap_plot.legend().remove()
|
||||||
|
|
||||||
|
goroutines_plot = plt.subplot(8, 2, 8)
|
||||||
|
plot(goroutines_plot, goroutines_samples_df, 'goroutines', '', 'goroutines', group_pattern)
|
||||||
|
goroutines_plot.legend().remove()
|
||||||
|
|
||||||
|
fig = plt.gcf()
|
||||||
|
fig.set_size_inches(20, 18)
|
||||||
|
|
||||||
|
print('Saving graph to graph.png')
|
||||||
|
plt.savefig('graph.png', bbox_inches='tight')
|
||||||
|
|
||||||
2
performance_analysis/requirements.txt
Normal file
2
performance_analysis/requirements.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
matplotlib
|
||||||
|
pandas
|
||||||
100
performance_analysis/run_tapper_benchmark.sh
Executable file
100
performance_analysis/run_tapper_benchmark.sh
Executable file
@@ -0,0 +1,100 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
[ -z "$MIZU_HOME" ] && { echo "MIZU_HOME is missing"; exit 1; }
|
||||||
|
[ -z "$MIZU_BENCHMARK_OUTPUT_DIR" ] && export MIZU_BENCHMARK_OUTPUT_DIR="/tmp/mizu-benchmark-results-$(date +%d-%m-%H-%M)"
|
||||||
|
[ -z "$MIZU_BENCHMARK_CLIENT_PERIOD" ] && export MIZU_BENCHMARK_CLIENT_PERIOD="1m"
|
||||||
|
[ -z "$MIZU_BENCHMARK_URL" ] && export MIZU_BENCHMARK_URL="http://localhost:8081/data/b.1000.json"
|
||||||
|
[ -z "$MIZU_BENCHMARK_RUN_COUNT" ] && export MIZU_BENCHMARK_RUN_COUNT="3"
|
||||||
|
[ -z "$MIZU_BENCHMARK_QPS" ] && export MIZU_BENCHMARK_QPS="500"
|
||||||
|
[ -z "$MIZU_BENCHMARK_CLIENTS_COUNT" ] && export MIZU_BENCHMARK_CLIENTS_COUNT="5"
|
||||||
|
|
||||||
|
function log() {
|
||||||
|
local message=$@
|
||||||
|
printf "[%s] %s\n" "$(date "+%d-%m %H:%M:%S")" "$message"
|
||||||
|
}
|
||||||
|
|
||||||
|
function run_single_bench() {
|
||||||
|
local mode_num=$1
|
||||||
|
local mode_str=$2
|
||||||
|
|
||||||
|
log "Starting ${mode_num}_${mode_str} (runs: $MIZU_BENCHMARK_RUN_COUNT) (period: $MIZU_BENCHMARK_CLIENT_PERIOD)"
|
||||||
|
|
||||||
|
for ((i=0;i<"$MIZU_BENCHMARK_RUN_COUNT";i++)); do
|
||||||
|
log " $i: Running tapper"
|
||||||
|
rm -f tapper.log
|
||||||
|
tapper_args=("--tap" "--api-server-address" "ws://localhost:8899/wsTapper" "-stats" "10" "-ignore-ports" "8899,9099")
|
||||||
|
if [[ $(uname) == "Darwin" ]]
|
||||||
|
then
|
||||||
|
tapper_args+=("-i" "lo0" "-"decoder "Loopback")
|
||||||
|
else
|
||||||
|
tapper_args+=("-i" "lo")
|
||||||
|
fi
|
||||||
|
nohup ./agent/build/mizuagent ${tapper_args[@]} > tapper.log 2>&1 &
|
||||||
|
|
||||||
|
log " $i: Running client (hey)"
|
||||||
|
hey -z $MIZU_BENCHMARK_CLIENT_PERIOD -c $MIZU_BENCHMARK_CLIENTS_COUNT -q $MIZU_BENCHMARK_QPS $MIZU_BENCHMARK_URL > /dev/null || return 1
|
||||||
|
|
||||||
|
log " $i: Killing tapper"
|
||||||
|
kill -9 $(ps -ef | grep agent/build/mizuagent | grep tap | grep -v grep | awk '{ print $2 }') > /dev/null 2>&1
|
||||||
|
|
||||||
|
local output_file=$MIZU_BENCHMARK_OUTPUT_DIR/${mode_num}_${mode_str}_${i}.log
|
||||||
|
log " $i: Moving output to $output_file"
|
||||||
|
mv tapper.log $output_file || return 1
|
||||||
|
done
|
||||||
|
}
|
||||||
|
|
||||||
|
function generate_bench_graph() {
|
||||||
|
cd performance_analysis/ || return 1
|
||||||
|
source venv/bin/activate
|
||||||
|
python plot_from_tapper_logs.py $MIZU_BENCHMARK_OUTPUT_DIR/*.log || return 1
|
||||||
|
mv graph.png $MIZU_BENCHMARK_OUTPUT_DIR || return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
mkdir -p $MIZU_BENCHMARK_OUTPUT_DIR
|
||||||
|
rm -f $MIZU_BENCHMARK_OUTPUT_DIR/*
|
||||||
|
log "Writing output to $MIZU_BENCHMARK_OUTPUT_DIR"
|
||||||
|
|
||||||
|
cd $MIZU_HOME || exit 1
|
||||||
|
|
||||||
|
export HOST_MODE=0
|
||||||
|
export SENSITIVE_DATA_FILTERING_OPTIONS='{"EnableRedaction": false}'
|
||||||
|
export MIZU_DEBUG_DISABLE_PCAP=false
|
||||||
|
export MIZU_DEBUG_DISABLE_TCP_REASSEMBLY=false
|
||||||
|
export MIZU_DEBUG_DISABLE_TCP_STREAM=false
|
||||||
|
export MIZU_DEBUG_DISABLE_NON_HTTP_EXTENSSION=false
|
||||||
|
export MIZU_DEBUG_DISABLE_DISSECTORS=false
|
||||||
|
export MIZU_DEBUG_DISABLE_EMITTING=false
|
||||||
|
export MIZU_DEBUG_DISABLE_SENDING=false
|
||||||
|
|
||||||
|
export MIZU_DEBUG_DISABLE_PCAP=true
|
||||||
|
run_single_bench "01" "no_pcap" || exit 1
|
||||||
|
export MIZU_DEBUG_DISABLE_PCAP=false
|
||||||
|
|
||||||
|
export MIZU_DEBUG_DISABLE_TCP_REASSEMBLY=true
|
||||||
|
run_single_bench "02" "no_assembler" || exit 1
|
||||||
|
export MIZU_DEBUG_DISABLE_TCP_REASSEMBLY=false
|
||||||
|
|
||||||
|
export MIZU_DEBUG_DISABLE_TCP_STREAM=true
|
||||||
|
run_single_bench "03" "no_tcp_stream" || exit 1
|
||||||
|
export MIZU_DEBUG_DISABLE_TCP_STREAM=false
|
||||||
|
|
||||||
|
export MIZU_DEBUG_DISABLE_NON_HTTP_EXTENSSION=true
|
||||||
|
run_single_bench "04" "only_http" || exit 1
|
||||||
|
export MIZU_DEBUG_DISABLE_NON_HTTP_EXTENSSION=false
|
||||||
|
|
||||||
|
export MIZU_DEBUG_DISABLE_DISSECTORS=true
|
||||||
|
run_single_bench "05" "no_dissectors" || exit 1
|
||||||
|
export MIZU_DEBUG_DISABLE_DISSECTORS=false
|
||||||
|
|
||||||
|
export MIZU_DEBUG_DISABLE_EMITTING=true
|
||||||
|
run_single_bench "06" "no_emit" || exit 1
|
||||||
|
export MIZU_DEBUG_DISABLE_EMITTING=false
|
||||||
|
|
||||||
|
export MIZU_DEBUG_DISABLE_SENDING=true
|
||||||
|
run_single_bench "07" "no_send" || exit 1
|
||||||
|
export MIZU_DEBUG_DISABLE_SENDING=false
|
||||||
|
|
||||||
|
run_single_bench "08" "normal" || exit 1
|
||||||
|
|
||||||
|
generate_bench_graph || exit 1
|
||||||
|
log "Output written to to $MIZU_BENCHMARK_OUTPUT_DIR"
|
||||||
BIN
performance_analysis/tapper-modes.png
Normal file
BIN
performance_analysis/tapper-modes.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 259 KiB |
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user