mirror of
https://github.com/kubeshark/kubeshark.git
synced 2026-03-03 02:00:32 +00:00
Compare commits
59 Commits
30.0-dev4
...
31.0-dev19
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d99c632102 | ||
|
|
76a6a77a14 | ||
|
|
2bfc523bbc | ||
|
|
66ba778384 | ||
|
|
7adbf7bf1b | ||
|
|
a97b5b3b38 | ||
|
|
aa8dcc5f5c | ||
|
|
9d08dbdd5d | ||
|
|
b47718e094 | ||
|
|
6a7fad430c | ||
|
|
59ad8d8fad | ||
|
|
a49443f101 | ||
|
|
2427955aa4 | ||
|
|
27a73e21fb | ||
|
|
8eeb0e54c9 | ||
|
|
97db24aeba | ||
|
|
63cf7ac34e | ||
|
|
e867b7d0f1 | ||
|
|
dcd8a64f43 | ||
|
|
bf8d5ed069 | ||
|
|
1f6e539590 | ||
|
|
590fa08c81 | ||
|
|
0a9be1884a | ||
|
|
40c745068e | ||
|
|
10dffd9331 | ||
|
|
0a800e8d8a | ||
|
|
068a4ff86e | ||
|
|
c45a869b75 | ||
|
|
0a793cd9e0 | ||
|
|
8d19080c11 | ||
|
|
319c3c7a8d | ||
|
|
0e7704eb15 | ||
|
|
dbcb776139 | ||
|
|
a3de34f544 | ||
|
|
99667984d6 | ||
|
|
763b0e7362 | ||
|
|
e07e04377f | ||
|
|
3c8f63ed92 | ||
|
|
11a2246cb9 | ||
|
|
a2595afd5e | ||
|
|
0f4710918f | ||
|
|
4bdda920d5 | ||
|
|
59e6268ddd | ||
|
|
2513e9099f | ||
|
|
a5c35d7d90 | ||
|
|
41a7587088 | ||
|
|
12f46da5c6 | ||
|
|
17f7879cff | ||
|
|
bc7776cbd3 | ||
|
|
2a31739100 | ||
|
|
308fa78955 | ||
|
|
cff5987ed4 | ||
|
|
7893b4596d | ||
|
|
774f07fccd | ||
|
|
482e5c8b69 | ||
|
|
21902b5f86 | ||
|
|
a4d0e250c9 | ||
|
|
5455220a3a | ||
|
|
237002ef29 |
2
.github/workflows/acceptance_tests.yml
vendored
2
.github/workflows/acceptance_tests.yml
vendored
@@ -43,7 +43,7 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
status: ${{ job.status }}
|
status: ${{ job.status }}
|
||||||
notification_title: 'Mizu {workflow} has {status_message}'
|
notification_title: 'Mizu {workflow} has {status_message}'
|
||||||
message_format: '{emoji} *{workflow}* {status_message} during <{run_url}|run>, after commit: <{commit_url}|{commit_sha}>'
|
message_format: '{emoji} *{workflow}* {status_message} during <{run_url}|run>, after commit <{commit_url}|{commit_sha}> by ${{ github.event.head_commit.committer.name }} <${{ github.event.head_commit.committer.email }}> ```${{ github.event.head_commit.message }}```'
|
||||||
footer: 'Linked Repo <{repo_url}|{repo}>'
|
footer: 'Linked Repo <{repo_url}|{repo}>'
|
||||||
notify_when: 'failure'
|
notify_when: 'failure'
|
||||||
env:
|
env:
|
||||||
|
|||||||
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -45,7 +45,7 @@ jobs:
|
|||||||
|
|
||||||
- name: Check modified files
|
- name: Check modified files
|
||||||
id: modified_files
|
id: modified_files
|
||||||
run: devops/check_modified_files.sh agent/ shared/ tap/ ui/ Dockerfile
|
run: devops/check_modified_files.sh agent/ shared/ tap/ ui/ ui-common/ Dockerfile
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
- name: Set up Docker Buildx
|
||||||
if: steps.modified_files.outputs.matched == 'true'
|
if: steps.modified_files.outputs.matched == 'true'
|
||||||
|
|||||||
53
.github/workflows/static_code_analysis.yml
vendored
53
.github/workflows/static_code_analysis.yml
vendored
@@ -15,6 +15,9 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
- uses: actions/setup-go@v2
|
- uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: '^1.17'
|
go-version: '^1.17'
|
||||||
@@ -24,67 +27,117 @@ jobs:
|
|||||||
sudo apt update
|
sudo apt update
|
||||||
sudo apt install -y libpcap-dev
|
sudo apt install -y libpcap-dev
|
||||||
|
|
||||||
|
- name: Check Agent modified files
|
||||||
|
id: agent_modified_files
|
||||||
|
run: devops/check_modified_files.sh agent/
|
||||||
|
|
||||||
- name: Go lint - agent
|
- name: Go lint - agent
|
||||||
uses: golangci/golangci-lint-action@v2
|
uses: golangci/golangci-lint-action@v2
|
||||||
|
if: steps.agent_modified_files.outputs.matched == 'true'
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
working-directory: agent
|
working-directory: agent
|
||||||
args: --timeout=3m
|
args: --timeout=3m
|
||||||
|
|
||||||
|
- name: Check shared modified files
|
||||||
|
id: shared_modified_files
|
||||||
|
run: devops/check_modified_files.sh shared/
|
||||||
|
|
||||||
- name: Go lint - shared
|
- name: Go lint - shared
|
||||||
uses: golangci/golangci-lint-action@v2
|
uses: golangci/golangci-lint-action@v2
|
||||||
|
if: steps.shared_modified_files.outputs.matched == 'true'
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
working-directory: shared
|
working-directory: shared
|
||||||
args: --timeout=3m
|
args: --timeout=3m
|
||||||
|
|
||||||
|
- name: Check tap modified files
|
||||||
|
id: tap_modified_files
|
||||||
|
run: devops/check_modified_files.sh tap/
|
||||||
|
|
||||||
- name: Go lint - tap
|
- name: Go lint - tap
|
||||||
uses: golangci/golangci-lint-action@v2
|
uses: golangci/golangci-lint-action@v2
|
||||||
|
if: steps.tap_modified_files.outputs.matched == 'true'
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
working-directory: tap
|
working-directory: tap
|
||||||
args: --timeout=3m
|
args: --timeout=3m
|
||||||
|
|
||||||
|
- name: Check cli modified files
|
||||||
|
id: cli_modified_files
|
||||||
|
run: devops/check_modified_files.sh cli/
|
||||||
|
|
||||||
- name: Go lint - CLI
|
- name: Go lint - CLI
|
||||||
uses: golangci/golangci-lint-action@v2
|
uses: golangci/golangci-lint-action@v2
|
||||||
|
if: steps.cli_modified_files.outputs.matched == 'true'
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
working-directory: cli
|
working-directory: cli
|
||||||
args: --timeout=3m
|
args: --timeout=3m
|
||||||
|
|
||||||
|
- name: Check acceptanceTests modified files
|
||||||
|
id: acceptanceTests_modified_files
|
||||||
|
run: devops/check_modified_files.sh acceptanceTests/
|
||||||
|
|
||||||
- name: Go lint - acceptanceTests
|
- name: Go lint - acceptanceTests
|
||||||
uses: golangci/golangci-lint-action@v2
|
uses: golangci/golangci-lint-action@v2
|
||||||
|
if: steps.acceptanceTests_modified_files.outputs.matched == 'true'
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
working-directory: acceptanceTests
|
working-directory: acceptanceTests
|
||||||
args: --timeout=3m
|
args: --timeout=3m
|
||||||
|
|
||||||
|
- name: Check tap/api modified files
|
||||||
|
id: tap_api_modified_files
|
||||||
|
run: devops/check_modified_files.sh tap/api/
|
||||||
|
|
||||||
- name: Go lint - tap/api
|
- name: Go lint - tap/api
|
||||||
uses: golangci/golangci-lint-action@v2
|
uses: golangci/golangci-lint-action@v2
|
||||||
|
if: steps.tap_api_modified_files.outputs.matched == 'true'
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
working-directory: tap/api
|
working-directory: tap/api
|
||||||
|
|
||||||
|
- name: Check tap/extensions/amqp modified files
|
||||||
|
id: tap_amqp_modified_files
|
||||||
|
run: devops/check_modified_files.sh tap/extensions/amqp/
|
||||||
|
|
||||||
- name: Go lint - tap/extensions/amqp
|
- name: Go lint - tap/extensions/amqp
|
||||||
uses: golangci/golangci-lint-action@v2
|
uses: golangci/golangci-lint-action@v2
|
||||||
|
if: steps.tap_amqp_modified_files.outputs.matched == 'true'
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
working-directory: tap/extensions/amqp
|
working-directory: tap/extensions/amqp
|
||||||
|
|
||||||
|
- name: Check tap/extensions/http modified files
|
||||||
|
id: tap_http_modified_files
|
||||||
|
run: devops/check_modified_files.sh tap/extensions/http/
|
||||||
|
|
||||||
- name: Go lint - tap/extensions/http
|
- name: Go lint - tap/extensions/http
|
||||||
uses: golangci/golangci-lint-action@v2
|
uses: golangci/golangci-lint-action@v2
|
||||||
|
if: steps.tap_http_modified_files.outputs.matched == 'true'
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
working-directory: tap/extensions/http
|
working-directory: tap/extensions/http
|
||||||
|
|
||||||
|
- name: Check tap/extensions/kafka modified files
|
||||||
|
id: tap_kafka_modified_files
|
||||||
|
run: devops/check_modified_files.sh tap/extensions/kafka/
|
||||||
|
|
||||||
- name: Go lint - tap/extensions/kafka
|
- name: Go lint - tap/extensions/kafka
|
||||||
uses: golangci/golangci-lint-action@v2
|
uses: golangci/golangci-lint-action@v2
|
||||||
|
if: steps.tap_kafka_modified_files.outputs.matched == 'true'
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
working-directory: tap/extensions/kafka
|
working-directory: tap/extensions/kafka
|
||||||
|
|
||||||
|
- name: Check tap/extensions/redis modified files
|
||||||
|
id: tap_redis_modified_files
|
||||||
|
run: devops/check_modified_files.sh tap/extensions/redis/
|
||||||
|
|
||||||
- name: Go lint - tap/extensions/redis
|
- name: Go lint - tap/extensions/redis
|
||||||
uses: golangci/golangci-lint-action@v2
|
uses: golangci/golangci-lint-action@v2
|
||||||
|
if: steps.tap_redis_modified_files.outputs.matched == 'true'
|
||||||
with:
|
with:
|
||||||
version: latest
|
version: latest
|
||||||
working-directory: tap/extensions/redis
|
working-directory: tap/extensions/redis
|
||||||
|
|||||||
9
.github/workflows/test.yml
vendored
9
.github/workflows/test.yml
vendored
@@ -18,6 +18,7 @@ jobs:
|
|||||||
run-unit-tests:
|
run-unit-tests:
|
||||||
name: Unit Tests
|
name: Unit Tests
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
timeout-minutes: 20
|
||||||
steps:
|
steps:
|
||||||
- name: Check out code into the Go module directory
|
- name: Check out code into the Go module directory
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
@@ -34,14 +35,6 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
sudo apt-get install libpcap-dev
|
sudo apt-get install libpcap-dev
|
||||||
|
|
||||||
- id: 'auth'
|
|
||||||
uses: 'google-github-actions/auth@v0'
|
|
||||||
with:
|
|
||||||
credentials_json: '${{ secrets.GCR_JSON_KEY }}'
|
|
||||||
|
|
||||||
- name: 'Set up Cloud SDK'
|
|
||||||
uses: 'google-github-actions/setup-gcloud@v0'
|
|
||||||
|
|
||||||
- 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/
|
||||||
|
|||||||
27
Dockerfile
27
Dockerfile
@@ -1,13 +1,23 @@
|
|||||||
ARG BUILDARCH=amd64
|
ARG BUILDARCH=amd64
|
||||||
ARG TARGETARCH=amd64
|
ARG TARGETARCH=amd64
|
||||||
|
|
||||||
|
### Front-end common
|
||||||
|
FROM node:16 AS front-end-common
|
||||||
|
|
||||||
|
WORKDIR /app/ui-build
|
||||||
|
COPY ui-common/package.json .
|
||||||
|
COPY ui-common/package-lock.json .
|
||||||
|
RUN npm i
|
||||||
|
COPY ui-common .
|
||||||
|
RUN npm pack
|
||||||
|
|
||||||
### Front-end
|
### Front-end
|
||||||
FROM node:16 AS front-end
|
FROM node:16 AS front-end
|
||||||
|
|
||||||
WORKDIR /app/ui-build
|
WORKDIR /app/ui-build
|
||||||
|
|
||||||
COPY ui/package.json .
|
COPY ui/package.json ui/package-lock.json ./
|
||||||
COPY ui/package-lock.json .
|
COPY --from=front-end-common ["/app/ui-build/up9-mizu-common-0.0.0.tgz", "."]
|
||||||
RUN npm i
|
RUN npm i
|
||||||
COPY ui .
|
COPY ui .
|
||||||
RUN npm run build
|
RUN npm run build
|
||||||
@@ -15,7 +25,7 @@ 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 libpcap-dev g++ perl-utils
|
RUN apk add --no-cache libpcap-dev g++ perl-utils
|
||||||
|
|
||||||
|
|
||||||
### Intermediate builder image for x86-64 to x86-64 native builds
|
### Intermediate builder image for x86-64 to x86-64 native builds
|
||||||
@@ -77,17 +87,16 @@ 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.6.3/basenine_linux_${GOARCH} ./basenine_linux_${GOARCH}
|
ADD https://github.com/up9inc/basenine/releases/download/v0.6.6/basenine_linux_${GOARCH} ./basenine_linux_${GOARCH}
|
||||||
ADD https://github.com/up9inc/basenine/releases/download/v0.6.3/basenine_linux_${GOARCH}.sha256 ./basenine_linux_${GOARCH}.sha256
|
ADD https://github.com/up9inc/basenine/releases/download/v0.6.6/basenine_linux_${GOARCH}.sha256 ./basenine_linux_${GOARCH}.sha256
|
||||||
RUN shasum -a 256 -c basenine_linux_${GOARCH}.sha256
|
|
||||||
RUN chmod +x ./basenine_linux_${GOARCH}
|
|
||||||
RUN mv ./basenine_linux_${GOARCH} ./basenine
|
|
||||||
|
|
||||||
|
RUN shasum -a 256 -c basenine_linux_"${GOARCH}".sha256 && \
|
||||||
|
chmod +x ./basenine_linux_"${GOARCH}" && \
|
||||||
|
mv ./basenine_linux_"${GOARCH}" ./basenine
|
||||||
|
|
||||||
### The shipped image
|
### The shipped image
|
||||||
ARG TARGETARCH=amd64
|
ARG TARGETARCH=amd64
|
||||||
FROM ${TARGETARCH}/busybox:latest
|
FROM ${TARGETARCH}/busybox:latest
|
||||||
|
|
||||||
# gin-gonic runs in debug mode without this
|
# gin-gonic runs in debug mode without this
|
||||||
ENV GIN_MODE=release
|
ENV GIN_MODE=release
|
||||||
|
|
||||||
|
|||||||
2
Makefile
2
Makefile
@@ -73,7 +73,7 @@ clean-agent: ## Clean agent.
|
|||||||
clean-cli: ## Clean CLI.
|
clean-cli: ## Clean CLI.
|
||||||
@(cd cli; make clean ; echo "CLI cleanup done" )
|
@(cd cli; make clean ; echo "CLI cleanup done" )
|
||||||
|
|
||||||
clean-docker: ## Run clen docker
|
clean-docker: ## Run clean docker
|
||||||
@(echo "DOCKER cleanup - NOT IMPLEMENTED YET " )
|
@(echo "DOCKER cleanup - NOT IMPLEMENTED YET " )
|
||||||
|
|
||||||
test-lint: ## Run lint on all modules
|
test-lint: ## Run lint on all modules
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
const columns = {podName : 1, namespace : 2, tapping : 3};
|
const columns = {podName : 1, namespace : 2, tapping : 3};
|
||||||
const greenStatusImageSrc = '/static/media/success.662997eb.svg';
|
|
||||||
|
|
||||||
function getDomPathInStatusBar(line, column) {
|
function getDomPathInStatusBar(line, column) {
|
||||||
return `.expandedStatusBar > :nth-child(2) > > :nth-child(2) > :nth-child(${line}) > :nth-child(${column})`;
|
return `[data-cy="expandedStatusBar"] > :nth-child(2) > > :nth-child(2) > :nth-child(${line}) > :nth-child(${column})`;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkLine(line, expectedValues) {
|
export function checkLine(line, expectedValues) {
|
||||||
@@ -12,14 +11,14 @@ export function checkLine(line, expectedValues) {
|
|||||||
|
|
||||||
cy.get(getDomPathInStatusBar(line, columns.namespace)).invoke('text').then(namespaceValue => {
|
cy.get(getDomPathInStatusBar(line, columns.namespace)).invoke('text').then(namespaceValue => {
|
||||||
expect(namespaceValue).to.equal(expectedValues.namespace);
|
expect(namespaceValue).to.equal(expectedValues.namespace);
|
||||||
cy.get(getDomPathInStatusBar(line, columns.tapping)).children().should('have.attr', 'src', greenStatusImageSrc);
|
cy.get(getDomPathInStatusBar(line, columns.tapping)).children().should('have.attr', 'src').and("match", /success.*\.svg/);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function findLineAndCheck(expectedValues) {
|
export function findLineAndCheck(expectedValues) {
|
||||||
cy.get('.expandedStatusBar > :nth-child(2) > > :nth-child(2) > > :nth-child(1)').then(pods => {
|
cy.get('[data-cy="expandedStatusBar"] > :nth-child(2) > > :nth-child(2) > > :nth-child(1)').then(pods => {
|
||||||
cy.get('.expandedStatusBar > :nth-child(2) > > :nth-child(2) > > :nth-child(2)').then(namespaces => {
|
cy.get('[data-cy="expandedStatusBar"] > :nth-child(2) > > :nth-child(2) > > :nth-child(2)').then(namespaces => {
|
||||||
// organizing namespaces array
|
// organizing namespaces array
|
||||||
const podObjectsArray = Object.values(pods ?? {});
|
const podObjectsArray = Object.values(pods ?? {});
|
||||||
const namespacesObjectsArray = Object.values(namespaces ?? {});
|
const namespacesObjectsArray = Object.values(namespaces ?? {});
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ export function leftTextCheck(entryNum, path, expectedText) {
|
|||||||
|
|
||||||
export function leftOnHoverCheck(entryNum, path, filterName) {
|
export function leftOnHoverCheck(entryNum, path, filterName) {
|
||||||
cy.get(`#list #entry-${entryNum} ${path}`).trigger('mouseover');
|
cy.get(`#list #entry-${entryNum} ${path}`).trigger('mouseover');
|
||||||
cy.get(`#list #entry-${entryNum} .Queryable-Tooltip`).invoke('text').should('match', new RegExp(filterName));
|
cy.get(`#list #entry-${entryNum} [data-cy='QueryableTooltip']`).invoke('text').should('match', new RegExp(filterName));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function rightTextCheck(path, expectedText) {
|
export function rightTextCheck(path, expectedText) {
|
||||||
@@ -54,7 +54,7 @@ export function rightTextCheck(path, expectedText) {
|
|||||||
|
|
||||||
export function rightOnHoverCheck(path, expectedText) {
|
export function rightOnHoverCheck(path, expectedText) {
|
||||||
cy.get(`#rightSideContainer ${path}`).trigger('mouseover');
|
cy.get(`#rightSideContainer ${path}`).trigger('mouseover');
|
||||||
cy.get(`#rightSideContainer .Queryable-Tooltip`).invoke('text').should('match', new RegExp(expectedText));
|
cy.get(`#rightSideContainer [data-cy='QueryableTooltip']`).invoke('text').should('match', new RegExp(expectedText));
|
||||||
}
|
}
|
||||||
|
|
||||||
export function checkThatAllEntriesShown() {
|
export function checkThatAllEntriesShown() {
|
||||||
@@ -142,7 +142,9 @@ function deepCheck(generalDict, protocolDict, methodDict, entry) {
|
|||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
if (value.tab === valueTabs.response)
|
if (value.tab === valueTabs.response)
|
||||||
cy.contains('Response').click();
|
// temporary fix, change to some "data-cy" attribute,
|
||||||
|
// this will fix the issue that happen because we have "response:" in the header of the right side
|
||||||
|
cy.get('#rightSideContainer > :nth-child(3)').contains('Response').click();
|
||||||
cy.get(Cypress.env('bodyJsonClass')).then(text => {
|
cy.get(Cypress.env('bodyJsonClass')).then(text => {
|
||||||
expect(text.text()).to.match(value.regex)
|
expect(text.text()).to.match(value.regex)
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,6 +8,6 @@ it('check', function () {
|
|||||||
cy.visit(`http://localhost:${port}`);
|
cy.visit(`http://localhost:${port}`);
|
||||||
cy.wait('@statusTap').its('response.statusCode').should('match', /^2\d{2}/);
|
cy.wait('@statusTap').its('response.statusCode').should('match', /^2\d{2}/);
|
||||||
|
|
||||||
cy.get('.podsCount').trigger('mouseover');
|
cy.get(`[data-cy="expandedStatusBar"]`).trigger('mouseover',{force: true});
|
||||||
findLineAndCheck(getExpectedDetailsDict(podName, namespace));
|
findLineAndCheck(getExpectedDetailsDict(podName, namespace));
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import {findLineAndCheck, getExpectedDetailsDict} from '../testHelpers/StatusBar
|
|||||||
|
|
||||||
it('opening', function () {
|
it('opening', function () {
|
||||||
cy.visit(Cypress.env('testUrl'));
|
cy.visit(Cypress.env('testUrl'));
|
||||||
cy.get('.podsCount').trigger('mouseover');
|
cy.get(`[data-cy="podsCountText"]`).trigger('mouseover');
|
||||||
});
|
});
|
||||||
|
|
||||||
[1, 2, 3].map(doItFunc);
|
[1, 2, 3].map(doItFunc);
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import {getExpectedDetailsDict, checkLine} from '../testHelpers/StatusBarHelper'
|
|||||||
|
|
||||||
it('opening', function () {
|
it('opening', function () {
|
||||||
cy.visit(Cypress.env('testUrl'));
|
cy.visit(Cypress.env('testUrl'));
|
||||||
cy.get('.podsCount').trigger('mouseover');
|
cy.get(`[data-cy="podsCountText"]`).trigger('mouseover');
|
||||||
|
|
||||||
cy.get('.expandedStatusBar > :nth-child(2) > > :nth-child(2) >').should('have.length', 1); // one line
|
cy.get('[data-cy="expandedStatusBar"] > :nth-child(2) > > :nth-child(2) >').should('have.length', 1); // one line
|
||||||
|
|
||||||
checkLine(1, getExpectedDetailsDict(Cypress.env('name'), Cypress.env('namespace')));
|
checkLine(1, getExpectedDetailsDict(Cypress.env('name'), Cypress.env('namespace')));
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ it('opening mizu', function () {
|
|||||||
verifyMinimumEntries();
|
verifyMinimumEntries();
|
||||||
|
|
||||||
it('top bar check', function () {
|
it('top bar check', function () {
|
||||||
cy.get('.podsCount').trigger('mouseover');
|
cy.get(`[data-cy="podsCountText"]`).trigger('mouseover');
|
||||||
podsArray.map(findLineAndCheck);
|
podsArray.map(findLineAndCheck);
|
||||||
cy.reload();
|
cy.reload();
|
||||||
});
|
});
|
||||||
@@ -40,32 +40,23 @@ it('filtering guide check', function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('right side sanity test', function () {
|
it('right side sanity test', function () {
|
||||||
cy.get('#entryDetailedTitleBodySize').then(sizeTopLine => {
|
cy.get('#entryDetailedTitleElapsedTime').then(timeInMs => {
|
||||||
const sizeOnTopLine = sizeTopLine.text().replace(' B', '');
|
const time = timeInMs.text();
|
||||||
cy.contains('Response').click();
|
if (time < '0ms') {
|
||||||
cy.contains('Body Size (bytes)').parent().next().then(size => {
|
throw new Error(`The time in the top line cannot be negative ${time}`);
|
||||||
const bodySizeByDetails = size.text();
|
}
|
||||||
expect(sizeOnTopLine).to.equal(bodySizeByDetails, 'The body size in the top line should match the details in the response');
|
});
|
||||||
|
|
||||||
if (parseInt(bodySizeByDetails) < 0) {
|
// temporary fix, change to some "data-cy" attribute,
|
||||||
throw new Error(`The body size cannot be negative. got the size: ${bodySizeByDetails}`)
|
// this will fix the issue that happen because we have "response:" in the header of the right side
|
||||||
}
|
cy.get('#rightSideContainer > :nth-child(3)').contains('Response').click();
|
||||||
|
|
||||||
cy.get('#entryDetailedTitleElapsedTime').then(timeInMs => {
|
cy.get('#rightSideContainer [title="Status Code"]').then(status => {
|
||||||
const time = timeInMs.text();
|
const statusCode = status.text();
|
||||||
if (time < '0ms') {
|
cy.contains('Status').parent().next().then(statusInDetails => {
|
||||||
throw new Error(`The time in the top line cannot be negative ${time}`);
|
const statusCodeInDetails = statusInDetails.text();
|
||||||
}
|
|
||||||
|
|
||||||
cy.get('#rightSideContainer [title="Status Code"]').then(status => {
|
expect(statusCode).to.equal(statusCodeInDetails, 'The status code in the top line should match the status code in details');
|
||||||
const statusCode = status.text();
|
|
||||||
cy.contains('Status').parent().next().then(statusInDetails => {
|
|
||||||
const statusCodeInDetails = statusInDetails.text();
|
|
||||||
|
|
||||||
expect(statusCode).to.equal(statusCodeInDetails, 'The status code in the top line should match the status code in details');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -205,6 +196,7 @@ function checkFilter(filterDetails){
|
|||||||
// checks the hover on the last entry (the only one in DOM at the beginning)
|
// checks the hover on the last entry (the only one in DOM at the beginning)
|
||||||
leftOnHoverCheck(totalEntries - 1, leftSidePath, name);
|
leftOnHoverCheck(totalEntries - 1, leftSidePath, name);
|
||||||
|
|
||||||
|
cy.get('.w-tc-editor-text').clear();
|
||||||
// applying the filter with alt+enter or with the button
|
// applying the filter with alt+enter or with the button
|
||||||
cy.get('.w-tc-editor-text').type(`${name}${applyByEnter ? '{alt+enter}' : ''}`);
|
cy.get('.w-tc-editor-text').type(`${name}${applyByEnter ? '{alt+enter}' : ''}`);
|
||||||
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'));
|
||||||
@@ -251,7 +243,9 @@ function deeperChcek(leftSidePath, rightSidePath, filterName, leftSideExpectedTe
|
|||||||
}
|
}
|
||||||
|
|
||||||
function checkRightSideResponseBody() {
|
function checkRightSideResponseBody() {
|
||||||
cy.contains('Response').click();
|
// temporary fix, change to some "data-cy" attribute,
|
||||||
|
// this will fix the issue that happen because we have "response:" in the header of the right side
|
||||||
|
cy.get('#rightSideContainer > :nth-child(3)').contains('Response').click();
|
||||||
clickCheckbox('Decode Base64');
|
clickCheckbox('Decode Base64');
|
||||||
|
|
||||||
cy.get(`${Cypress.env('bodyJsonClass')}`).then(value => {
|
cy.get(`${Cypress.env('bodyJsonClass')}`).then(value => {
|
||||||
|
|||||||
35
agent/go.mod
35
agent/go.mod
@@ -20,7 +20,7 @@ require (
|
|||||||
github.com/orcaman/concurrent-map v1.0.0
|
github.com/orcaman/concurrent-map v1.0.0
|
||||||
github.com/patrickmn/go-cache v2.1.0+incompatible
|
github.com/patrickmn/go-cache v2.1.0+incompatible
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.7.0
|
||||||
github.com/up9inc/basenine/client/go v0.0.0-20220315070758-3a76cfc4378e
|
github.com/up9inc/basenine/client/go v0.0.0-20220326121918-785f3061c8ce
|
||||||
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
|
||||||
@@ -37,53 +37,79 @@ require (
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
cloud.google.com/go/compute v1.2.0 // indirect
|
cloud.google.com/go/compute v1.2.0 // indirect
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect
|
||||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||||
github.com/Azure/go-autorest/autorest v0.11.24 // indirect
|
github.com/Azure/go-autorest/autorest v0.11.24 // indirect
|
||||||
github.com/Azure/go-autorest/autorest/adal v0.9.18 // indirect
|
github.com/Azure/go-autorest/autorest/adal v0.9.18 // indirect
|
||||||
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
|
github.com/Azure/go-autorest/autorest/date v0.3.0 // indirect
|
||||||
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/PuerkitoBio/purell v1.1.1 // 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/bradleyfalzon/tlsx v0.0.0-20170624122154-28fd0e59bac4 // indirect
|
github.com/bradleyfalzon/tlsx v0.0.0-20170624122154-28fd0e59bac4 // 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.8.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/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/fsnotify/fsnotify v1.5.1 // indirect
|
github.com/fvbommel/sortorder v1.0.2 // indirect
|
||||||
github.com/ghodss/yaml v1.0.0 // 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-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/swag v0.21.1 // indirect
|
github.com/go-openapi/swag v0.21.1 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/golang-jwt/jwt/v4 v4.2.0 // indirect
|
github.com/golang-jwt/jwt/v4 v4.2.0 // indirect
|
||||||
github.com/golang/protobuf v1.5.2 // indirect
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
github.com/golang/snappy v0.0.4 // indirect
|
github.com/golang/snappy v0.0.4 // indirect
|
||||||
|
github.com/google/btree v1.0.1 // indirect
|
||||||
github.com/google/go-cmp v0.5.7 // indirect
|
github.com/google/go-cmp v0.5.7 // indirect
|
||||||
github.com/google/gofuzz v1.2.0 // indirect
|
github.com/google/gofuzz v1.2.0 // indirect
|
||||||
github.com/google/gopacket v1.1.19 // indirect
|
github.com/google/gopacket v1.1.19 // indirect
|
||||||
github.com/google/martian v2.1.0+incompatible // indirect
|
github.com/google/martian v2.1.0+incompatible // 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/imdario/mergo v0.3.12 // 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/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/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/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||||
|
github.com/moby/spdystream v0.2.0 // 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
|
||||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||||
|
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
|
||||||
|
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
|
||||||
github.com/ohler55/ojg v1.12.12 // indirect
|
github.com/ohler55/ojg v1.12.12 // indirect
|
||||||
|
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
|
||||||
github.com/pierrec/lz4 v2.6.1+incompatible // indirect
|
github.com/pierrec/lz4 v2.6.1+incompatible // indirect
|
||||||
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
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/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/spf13/cobra v1.3.0 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.5 // 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/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
|
||||||
|
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/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
|
||||||
@@ -96,10 +122,15 @@ require (
|
|||||||
gopkg.in/inf.v0 v0.9.1 // indirect
|
gopkg.in/inf.v0 v0.9.1 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
|
||||||
|
k8s.io/cli-runtime v0.23.3 // indirect
|
||||||
|
k8s.io/component-base v0.23.3 // indirect
|
||||||
k8s.io/klog/v2 v2.40.1 // indirect
|
k8s.io/klog/v2 v2.40.1 // indirect
|
||||||
k8s.io/kube-openapi v0.0.0-20220124234850-424119656bbf // indirect
|
k8s.io/kube-openapi v0.0.0-20220124234850-424119656bbf // indirect
|
||||||
|
k8s.io/kubectl v0.23.3 // indirect
|
||||||
k8s.io/utils v0.0.0-20220127004650-9b3446523e65 // indirect
|
k8s.io/utils v0.0.0-20220127004650-9b3446523e65 // indirect
|
||||||
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect
|
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 // indirect
|
||||||
|
sigs.k8s.io/kustomize/api v0.11.1 // indirect
|
||||||
|
sigs.k8s.io/kustomize/kyaml v0.13.3 // indirect
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
|
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 // indirect
|
||||||
sigs.k8s.io/yaml v1.3.0 // indirect
|
sigs.k8s.io/yaml v1.3.0 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
38
agent/go.sum
38
agent/go.sum
@@ -53,6 +53,7 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX
|
|||||||
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
|
||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
github.com/Azure/go-ansiterm v0.0.0-20210608223527-2377c96fe795/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
|
||||||
|
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
|
||||||
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
|
||||||
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
|
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 v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||||
@@ -74,10 +75,13 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
|
|||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ=
|
||||||
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/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
|
github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE=
|
||||||
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/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
|
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/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
@@ -111,6 +115,7 @@ github.com/census-instrumentation/opencensus-proto v0.3.0/go.mod h1:f6KPmirojxKA
|
|||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 h1:7aWHqerlJ41y6FOsEUvknqgXnGmJyJSbjhAWq5pO4F8=
|
||||||
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw=
|
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5/go.mod h1:/iP1qXHoty45bqomnu2LM+VVyAEdWN+vtSHGlQgyxbw=
|
||||||
github.com/chanced/cmpjson v0.0.0-20210415035445-da9262c1f20a h1:zG6t+4krPXcCKtLbjFvAh+fKN1d0qfD+RaCj+680OU8=
|
github.com/chanced/cmpjson v0.0.0-20210415035445-da9262c1f20a h1:zG6t+4krPXcCKtLbjFvAh+fKN1d0qfD+RaCj+680OU8=
|
||||||
github.com/chanced/cmpjson v0.0.0-20210415035445-da9262c1f20a/go.mod h1:yhcmlFk1hxuZ+5XZbupzT/cEm/eE4ZvWbmsW1+Q/aZE=
|
github.com/chanced/cmpjson v0.0.0-20210415035445-da9262c1f20a/go.mod h1:yhcmlFk1hxuZ+5XZbupzT/cEm/eE4ZvWbmsW1+Q/aZE=
|
||||||
@@ -147,6 +152,7 @@ github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfc
|
|||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
|
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
|
||||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.11/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.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 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
@@ -163,6 +169,7 @@ github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21 h1:YEetp8
|
|||||||
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 h1:0fcSh4qeC/i1+7QU1KXpmq2iUAdMk4l0/vmbtW1+KJM=
|
||||||
github.com/elastic/go-elasticsearch/v7 v7.17.0/go.mod h1:OJ4wdbtDNk5g503kvlHLyErCgQwwzmDtaFC4XyOxXA4=
|
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/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=
|
||||||
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
|
||||||
@@ -184,6 +191,7 @@ github.com/evanphx/json-patch v5.6.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLi
|
|||||||
github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww=
|
github.com/evanphx/json-patch/v5 v5.6.0 h1:b91NhWfaz02IuVxO9faSllyAtNXHMPkC5J8sJCLunww=
|
||||||
github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4=
|
github.com/evanphx/json-patch/v5 v5.6.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4=
|
||||||
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4=
|
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4=
|
||||||
|
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f h1:Wl78ApPPB2Wvf/TIe2xdyJxTlb6obmF18d8QdkxNDu4=
|
||||||
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc=
|
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f/go.mod h1:OSYXu++VVOHnXeitef/D8n/6y4QV8uLHSFXX4NeXMGc=
|
||||||
github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8=
|
github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8=
|
||||||
github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
|
github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc=
|
||||||
@@ -201,6 +209,7 @@ github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4
|
|||||||
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
|
github.com/fsnotify/fsnotify v1.5.1 h1:mZcQUHVQUQWoPXXtuf9yuEXKudkV2sx1E06UadKWpgI=
|
||||||
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
github.com/fsnotify/fsnotify v1.5.1/go.mod h1:T3375wBYaZdLLcVNkcVbzGHY7f1l/uK5T5Ai1i3InKU=
|
||||||
github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
|
github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
|
||||||
|
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 h1:p4nagHchUKGn85z/f+pse4aSh50nIBOYjOhMIku2hiA=
|
||||||
@@ -237,6 +246,7 @@ github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUe
|
|||||||
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
|
||||||
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
|
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
|
||||||
github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
|
github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
|
||||||
|
github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs=
|
||||||
github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
|
github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
|
||||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||||
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||||
@@ -303,6 +313,7 @@ github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEW
|
|||||||
github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk=
|
github.com/golangplus/testing v0.0.0-20180327235837-af21d9c3145e/go.mod h1:0AA//k/eakGydO4jKRoRL2j92ZKSzTgj9tclaCrvXHk=
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
|
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
|
||||||
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
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.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
||||||
@@ -344,6 +355,7 @@ github.com/google/pprof v0.0.0-20210601050228-01bbb1931b22/go.mod h1:kpwsk12EmLe
|
|||||||
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
github.com/google/pprof v0.0.0-20210609004039-a478d1d731e9/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1/go.mod h1:kpwsk12EmLew5upagYY7GY0pfYCcupk39gWOCRROcvE=
|
||||||
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
|
||||||
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
@@ -363,6 +375,7 @@ github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoA
|
|||||||
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
|
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/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||||
|
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
|
||||||
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||||
@@ -410,7 +423,9 @@ github.com/iancoleman/strcase v0.2.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47
|
|||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||||
|
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
|
||||||
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||||
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
|
||||||
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
|
||||||
@@ -451,6 +466,7 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
|||||||
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
|
||||||
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
|
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
|
||||||
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
|
||||||
|
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
|
||||||
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
|
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
|
||||||
github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
|
github.com/lithammer/dedent v1.1.0/go.mod h1:jrXYCQtgg0nJiN+StA2KgR7w6CiQNv9Fd/Z9BP0jIOc=
|
||||||
github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w=
|
github.com/lyft/protoc-gen-star v0.5.3/go.mod h1:V0xaHgaf5oCCqmcxYcWiDfTiKsZsRc87/1qhoTACD8w=
|
||||||
@@ -486,6 +502,7 @@ github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk
|
|||||||
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
|
||||||
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
|
||||||
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
|
||||||
|
github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0=
|
||||||
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
|
github.com/mitchellh/go-wordwrap v1.0.1/go.mod h1:R62XHJLzvMFRBbcrT7m7WgmE1eOyTSsCt+hzestvNj0=
|
||||||
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
github.com/mitchellh/gox v0.4.0/go.mod h1:Sd9lOJ0+aimLBi73mGofS1ycjY8lL3uZM3JPS42BGNg=
|
||||||
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0QubkSMEySY=
|
||||||
@@ -493,8 +510,10 @@ 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/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=
|
||||||
|
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc=
|
||||||
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw=
|
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
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 h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
|
||||||
@@ -503,10 +522,12 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN
|
|||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
|
||||||
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
|
||||||
|
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
|
||||||
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
|
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
|
||||||
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
|
||||||
|
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/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
|
||||||
github.com/nav-inc/datetime v0.1.3 h1:PaybPUsScX+Cd3TEa1tYpfwU61deCEhMTlCO2hONm1c=
|
github.com/nav-inc/datetime v0.1.3 h1:PaybPUsScX+Cd3TEa1tYpfwU61deCEhMTlCO2hONm1c=
|
||||||
github.com/nav-inc/datetime v0.1.3/go.mod h1:gKGf5G+cW7qkTo5TC/sieNyz6lYdrA9cf1PNV+pXIOE=
|
github.com/nav-inc/datetime v0.1.3/go.mod h1:gKGf5G+cW7qkTo5TC/sieNyz6lYdrA9cf1PNV+pXIOE=
|
||||||
@@ -538,6 +559,7 @@ github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTK
|
|||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||||
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
github.com/pelletier/go-toml v1.9.4/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c=
|
||||||
|
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/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
|
||||||
github.com/pierrec/lz4 v2.6.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
github.com/pierrec/lz4 v2.6.0+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
|
||||||
github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM=
|
github.com/pierrec/lz4 v2.6.1+incompatible h1:9UY3+iC23yxF0UfGaYrGplQ+79Rg+h/q9FV9ix19jjM=
|
||||||
@@ -583,6 +605,7 @@ github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTE
|
|||||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
||||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||||
|
github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=
|
||||||
github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
|
github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
@@ -593,6 +616,7 @@ github.com/santhosh-tekuri/jsonschema/v5 v5.0.0/go.mod h1:FKdcjfQW6rpZSnxxUvEA5H
|
|||||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||||
github.com/segmentio/kafka-go v0.4.27 h1:sIhEozeL/TLN2mZ5dkG462vcGEWYKS+u31sXPjKhAM4=
|
github.com/segmentio/kafka-go v0.4.27 h1:sIhEozeL/TLN2mZ5dkG462vcGEWYKS+u31sXPjKhAM4=
|
||||||
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/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
|
||||||
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=
|
||||||
@@ -611,6 +635,7 @@ github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkU
|
|||||||
github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.4.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
github.com/spf13/cobra v1.0.0/go.mod h1:/6GTrnGXV9HjY+aR4k0oJ5tcvakLuG6EuKReYlHNrgE=
|
||||||
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
|
github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk=
|
||||||
|
github.com/spf13/cobra v1.3.0 h1:R7cSvGu+Vv+qX0gW5R/85dx2kmmJT5z5NM8ifdYjdn0=
|
||||||
github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4=
|
github.com/spf13/cobra v1.3.0/go.mod h1:BrRVncBjOJa/eUcVVm9CE+oC6as8k+VYr4NY7WCi9V4=
|
||||||
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo=
|
||||||
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo=
|
||||||
@@ -624,6 +649,7 @@ github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy
|
|||||||
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
|
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/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/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
|
||||||
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.1/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
@@ -655,8 +681,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-20220315070758-3a76cfc4378e h1:/9dFXqvRDHcwPQdIGHP6iz6M0iAWBPOxYf6C+Ntq5w0=
|
github.com/up9inc/basenine/client/go v0.0.0-20220326121918-785f3061c8ce h1:vMTCpKItc9OyTLJXocNaq2NcBU5EnurJgTVOYb8W8dw=
|
||||||
github.com/up9inc/basenine/client/go v0.0.0-20220315070758-3a76cfc4378e/go.mod h1:SvJGPoa/6erhUQV7kvHBwM/0x5LyO6XaG2lUaCaKiUI=
|
github.com/up9inc/basenine/client/go v0.0.0-20220326121918-785f3061c8ce/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=
|
||||||
@@ -665,6 +691,7 @@ github.com/xdg/scram v0.0.0-20180814205039-7eeb5667e42c/go.mod h1:lB8K/P019DLNhe
|
|||||||
github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
|
github.com/xdg/stringprep v1.0.0/go.mod h1:Jhud4/sHMO4oL310DaZAKk9ZaJ08SJfe+sJh0HrGL1Y=
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||||
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
|
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
|
||||||
|
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 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY=
|
||||||
@@ -701,6 +728,7 @@ go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4
|
|||||||
go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
|
go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
|
||||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||||
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o=
|
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5/go.mod h1:nmDLcffg48OtT/PSW0Hg7FvpRQsQh5OSqIylirxKC7o=
|
||||||
|
go.starlark.net v0.0.0-20220203230714-bb14e151c28f h1:aW4TkS39/naJa9wPSbIXtZUQOlvuUh8gxCsLRrJoByU=
|
||||||
go.starlark.net v0.0.0-20220203230714-bb14e151c28f/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0=
|
go.starlark.net v0.0.0-20220203230714-bb14e151c28f/go.mod h1:t3mmBBPzAVvK0L0n1drDmrQsJ8FoIx4INCqVMTr/Zo0=
|
||||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
@@ -1205,6 +1233,7 @@ 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=
|
||||||
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=
|
||||||
@@ -1217,10 +1246,12 @@ k8s.io/api v0.23.3 h1:KNrME8KHGr12Ozjf8ytOewKzZh6hl/hHUZeHddT3a38=
|
|||||||
k8s.io/api v0.23.3/go.mod h1:w258XdGyvCmnBj/vGzQMj6kzdufJZVUwEM1U2fRJwSQ=
|
k8s.io/api v0.23.3/go.mod h1:w258XdGyvCmnBj/vGzQMj6kzdufJZVUwEM1U2fRJwSQ=
|
||||||
k8s.io/apimachinery v0.23.3 h1:7IW6jxNzrXTsP0c8yXz2E5Yx/WTzVPTsHIx/2Vm0cIk=
|
k8s.io/apimachinery v0.23.3 h1:7IW6jxNzrXTsP0c8yXz2E5Yx/WTzVPTsHIx/2Vm0cIk=
|
||||||
k8s.io/apimachinery v0.23.3/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM=
|
k8s.io/apimachinery v0.23.3/go.mod h1:BEuFMMBaIbcOqVIJqNZJXGFTP4W6AycEpb5+m/97hrM=
|
||||||
|
k8s.io/cli-runtime v0.23.3 h1:aJiediw+uUbxkfO6BNulcAMTUoU9Om43g3R7rIkYqcw=
|
||||||
k8s.io/cli-runtime v0.23.3/go.mod h1:yA00O5pDqnjkBh8fkuugBbfIfjB1nOpz+aYLotbnOfc=
|
k8s.io/cli-runtime v0.23.3/go.mod h1:yA00O5pDqnjkBh8fkuugBbfIfjB1nOpz+aYLotbnOfc=
|
||||||
k8s.io/client-go v0.23.3 h1:23QYUmCQ/W6hW78xIwm3XqZrrKZM+LWDqW2zfo+szJs=
|
k8s.io/client-go v0.23.3 h1:23QYUmCQ/W6hW78xIwm3XqZrrKZM+LWDqW2zfo+szJs=
|
||||||
k8s.io/client-go v0.23.3/go.mod h1:47oMd+YvAOqZM7pcQ6neJtBiFH7alOyfunYN48VsmwE=
|
k8s.io/client-go v0.23.3/go.mod h1:47oMd+YvAOqZM7pcQ6neJtBiFH7alOyfunYN48VsmwE=
|
||||||
k8s.io/code-generator v0.23.3/go.mod h1:S0Q1JVA+kSzTI1oUvbKAxZY/DYbA/ZUb4Uknog12ETk=
|
k8s.io/code-generator v0.23.3/go.mod h1:S0Q1JVA+kSzTI1oUvbKAxZY/DYbA/ZUb4Uknog12ETk=
|
||||||
|
k8s.io/component-base v0.23.3 h1:q+epprVdylgecijVGVdf4MbizEL2feW4ssd7cdo6LVY=
|
||||||
k8s.io/component-base v0.23.3/go.mod h1:1Smc4C60rWG7d3HjSYpIwEbySQ3YWg0uzH5a2AtaTLg=
|
k8s.io/component-base v0.23.3/go.mod h1:1Smc4C60rWG7d3HjSYpIwEbySQ3YWg0uzH5a2AtaTLg=
|
||||||
k8s.io/component-helpers v0.23.3/go.mod h1:SH+W/WPTaTenbWyDEeY7iytAQiMh45aqKxkvlqQ57cg=
|
k8s.io/component-helpers v0.23.3/go.mod h1:SH+W/WPTaTenbWyDEeY7iytAQiMh45aqKxkvlqQ57cg=
|
||||||
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
|
||||||
@@ -1234,6 +1265,7 @@ k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e/go.mod h1:vHXdDvt9+2spS2R
|
|||||||
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk=
|
k8s.io/kube-openapi v0.0.0-20211115234752-e816edb12b65/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk=
|
||||||
k8s.io/kube-openapi v0.0.0-20220124234850-424119656bbf h1:M9XBsiMslw2lb2ZzglC0TOkBPK5NQi0/noUrdnoFwUg=
|
k8s.io/kube-openapi v0.0.0-20220124234850-424119656bbf h1:M9XBsiMslw2lb2ZzglC0TOkBPK5NQi0/noUrdnoFwUg=
|
||||||
k8s.io/kube-openapi v0.0.0-20220124234850-424119656bbf/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk=
|
k8s.io/kube-openapi v0.0.0-20220124234850-424119656bbf/go.mod h1:sX9MT8g7NVZM5lVL/j8QyCCJe8YSMW30QvGZWaCIDIk=
|
||||||
|
k8s.io/kubectl v0.23.3 h1:gJsF7cahkWDPYlNvYKK+OrBZLAJUBzCym+Zsi+dfi1E=
|
||||||
k8s.io/kubectl v0.23.3/go.mod h1:VBeeXNgLhSabu4/k0O7Q0YujgnA3+CLTUE0RcmF73yY=
|
k8s.io/kubectl v0.23.3/go.mod h1:VBeeXNgLhSabu4/k0O7Q0YujgnA3+CLTUE0RcmF73yY=
|
||||||
k8s.io/metrics v0.23.3/go.mod h1:Ut8TvkbsO4oMVeUzaTArvPrcw9QRFLs2XNzUlORjdYE=
|
k8s.io/metrics v0.23.3/go.mod h1:Ut8TvkbsO4oMVeUzaTArvPrcw9QRFLs2XNzUlORjdYE=
|
||||||
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
k8s.io/utils v0.0.0-20210802155522-efc7438f0176/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
|
||||||
@@ -1247,10 +1279,12 @@ sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6/go.mod h1:p4QtZmO4uMYipTQNza
|
|||||||
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 h1:kDi4JBNAsJWfz1aEXhO8Jg87JJaPNLh5tIzYHgStQ9Y=
|
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2 h1:kDi4JBNAsJWfz1aEXhO8Jg87JJaPNLh5tIzYHgStQ9Y=
|
||||||
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY=
|
sigs.k8s.io/json v0.0.0-20211208200746-9f7c6b3444d2/go.mod h1:B+TnT182UBxE84DiCz4CVE26eOSDAeYCpfDnC2kdKMY=
|
||||||
sigs.k8s.io/kustomize/api v0.10.1/go.mod h1:2FigT1QN6xKdcnGS2Ppp1uIWrtWN28Ms8A3OZUZhwr8=
|
sigs.k8s.io/kustomize/api v0.10.1/go.mod h1:2FigT1QN6xKdcnGS2Ppp1uIWrtWN28Ms8A3OZUZhwr8=
|
||||||
|
sigs.k8s.io/kustomize/api v0.11.1 h1:/Vutu+gAqVo8skw1xCZrsZD39SN4Adg+z7FrSTw9pds=
|
||||||
sigs.k8s.io/kustomize/api v0.11.1/go.mod h1:GZuhith5YcqxIDe0GnRJNx5xxPTjlwaLTt/e+ChUtJA=
|
sigs.k8s.io/kustomize/api v0.11.1/go.mod h1:GZuhith5YcqxIDe0GnRJNx5xxPTjlwaLTt/e+ChUtJA=
|
||||||
sigs.k8s.io/kustomize/cmd/config v0.10.2/go.mod h1:K2aW7nXJ0AaT+VA/eO0/dzFLxmpFcTzudmAgDwPY1HQ=
|
sigs.k8s.io/kustomize/cmd/config v0.10.2/go.mod h1:K2aW7nXJ0AaT+VA/eO0/dzFLxmpFcTzudmAgDwPY1HQ=
|
||||||
sigs.k8s.io/kustomize/kustomize/v4 v4.4.1/go.mod h1:qOKJMMz2mBP+vcS7vK+mNz4HBLjaQSWRY22EF6Tb7Io=
|
sigs.k8s.io/kustomize/kustomize/v4 v4.4.1/go.mod h1:qOKJMMz2mBP+vcS7vK+mNz4HBLjaQSWRY22EF6Tb7Io=
|
||||||
sigs.k8s.io/kustomize/kyaml v0.13.0/go.mod h1:FTJxEZ86ScK184NpGSAQcfEqee0nul8oLCK30D47m4E=
|
sigs.k8s.io/kustomize/kyaml v0.13.0/go.mod h1:FTJxEZ86ScK184NpGSAQcfEqee0nul8oLCK30D47m4E=
|
||||||
|
sigs.k8s.io/kustomize/kyaml v0.13.3 h1:tNNQIC+8cc+aXFTVg+RtQAOsjwUdYBZRAgYOVI3RBc4=
|
||||||
sigs.k8s.io/kustomize/kyaml v0.13.3/go.mod h1:/ya3Gk4diiQzlE4mBh7wykyLRFZNvqlbh+JnwQ9Vhrc=
|
sigs.k8s.io/kustomize/kyaml v0.13.3/go.mod h1:/ya3Gk4diiQzlE4mBh7wykyLRFZNvqlbh+JnwQ9Vhrc=
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
|
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
|
||||||
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y=
|
sigs.k8s.io/structured-merge-diff/v4 v4.2.1 h1:bKCqE9GvQ5tiVHn5rfn1r+yao3aLQEaLzkkmAkf+A6Y=
|
||||||
|
|||||||
@@ -16,7 +16,9 @@ import (
|
|||||||
|
|
||||||
"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/elastic"
|
"github.com/up9inc/mizu/agent/pkg/elastic"
|
||||||
|
"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"
|
||||||
@@ -29,8 +31,6 @@ import (
|
|||||||
"github.com/up9inc/mizu/agent/pkg/app"
|
"github.com/up9inc/mizu/agent/pkg/app"
|
||||||
"github.com/up9inc/mizu/agent/pkg/config"
|
"github.com/up9inc/mizu/agent/pkg/config"
|
||||||
|
|
||||||
v1 "k8s.io/api/core/v1"
|
|
||||||
|
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
"github.com/op/go-logging"
|
"github.com/op/go-logging"
|
||||||
"github.com/up9inc/mizu/shared"
|
"github.com/up9inc/mizu/shared"
|
||||||
@@ -46,7 +46,6 @@ 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 startTime int64
|
|
||||||
|
|
||||||
const (
|
const (
|
||||||
socketConnectionRetries = 30
|
socketConnectionRetries = 30
|
||||||
@@ -55,6 +54,7 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
initializeDependencies()
|
||||||
logLevel := determineLogLevel()
|
logLevel := determineLogLevel()
|
||||||
logger.InitLoggerStd(logLevel)
|
logger.InitLoggerStd(logLevel)
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
@@ -108,7 +108,7 @@ func hostApi(socketHarOutputChannel chan<- *tapApi.OutputChannelItem) *gin.Engin
|
|||||||
|
|
||||||
app.Use(middlewares.CORSMiddleware()) // This has to be called after the static middleware, does not work if its called before
|
app.Use(middlewares.CORSMiddleware()) // This has to be called after the static middleware, does not work if its called before
|
||||||
|
|
||||||
api.WebSocketRoutes(app, &eventHandlers, startTime)
|
api.WebSocketRoutes(app, &eventHandlers)
|
||||||
|
|
||||||
if config.Config.OAS {
|
if config.Config.OAS {
|
||||||
routes.OASRoutes(app)
|
routes.OASRoutes(app)
|
||||||
@@ -122,6 +122,7 @@ func hostApi(socketHarOutputChannel chan<- *tapApi.OutputChannelItem) *gin.Engin
|
|||||||
routes.EntriesRoutes(app)
|
routes.EntriesRoutes(app)
|
||||||
routes.MetadataRoutes(app)
|
routes.MetadataRoutes(app)
|
||||||
routes.StatusRoutes(app)
|
routes.StatusRoutes(app)
|
||||||
|
routes.DbRoutes(app)
|
||||||
|
|
||||||
return app
|
return app
|
||||||
}
|
}
|
||||||
@@ -131,7 +132,6 @@ func runInApiServerMode(namespace string) *gin.Engine {
|
|||||||
logger.Log.Fatalf("Error loading config file %v", err)
|
logger.Log.Fatalf("Error loading config file %v", err)
|
||||||
}
|
}
|
||||||
app.ConfigureBasenineServer(shared.BasenineHost, shared.BaseninePort, config.Config.MaxDBSizeBytes, config.Config.LogLevel, config.Config.InsertionFilter)
|
app.ConfigureBasenineServer(shared.BasenineHost, shared.BaseninePort, config.Config.MaxDBSizeBytes, config.Config.LogLevel, config.Config.InsertionFilter)
|
||||||
startTime = time.Now().UnixNano() / int64(time.Millisecond)
|
|
||||||
api.StartResolving(namespace)
|
api.StartResolving(namespace)
|
||||||
|
|
||||||
enableExpFeatureIfNeeded()
|
enableExpFeatureIfNeeded()
|
||||||
@@ -154,11 +154,6 @@ func runInTapperMode() {
|
|||||||
|
|
||||||
hostMode := os.Getenv(shared.HostModeEnvVar) == "1"
|
hostMode := os.Getenv(shared.HostModeEnvVar) == "1"
|
||||||
tapOpts := &tap.TapOpts{HostMode: hostMode}
|
tapOpts := &tap.TapOpts{HostMode: hostMode}
|
||||||
tapTargets := getTapTargets()
|
|
||||||
if tapTargets != nil {
|
|
||||||
tapOpts.FilterAuthorities = tapTargets
|
|
||||||
logger.Log.Infof("Filtering for the following authorities: %v", tapOpts.FilterAuthorities)
|
|
||||||
}
|
|
||||||
|
|
||||||
filteredOutputItemsChannel := make(chan *tapApi.OutputChannelItem)
|
filteredOutputItemsChannel := make(chan *tapApi.OutputChannelItem)
|
||||||
|
|
||||||
@@ -203,10 +198,12 @@ func runInHarReaderMode() {
|
|||||||
|
|
||||||
func enableExpFeatureIfNeeded() {
|
func enableExpFeatureIfNeeded() {
|
||||||
if config.Config.OAS {
|
if config.Config.OAS {
|
||||||
oas.GetOasGeneratorInstance().Start()
|
oasGenerator := dependency.GetInstance(dependency.OasGeneratorDependency).(oas.OasGenerator)
|
||||||
|
oasGenerator.Start()
|
||||||
}
|
}
|
||||||
if config.Config.ServiceMap {
|
if config.Config.ServiceMap {
|
||||||
servicemap.GetInstance().Enable()
|
serviceMapGenerator := dependency.GetInstance(dependency.ServiceMapGeneratorDependency).(servicemap.ServiceMap)
|
||||||
|
serviceMapGenerator.Enable()
|
||||||
}
|
}
|
||||||
elastic.GetInstance().Configure(config.Config.Elastic)
|
elastic.GetInstance().Configure(config.Config.Elastic)
|
||||||
}
|
}
|
||||||
@@ -254,28 +251,6 @@ func setUIFlags(uiIndexPath string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func parseEnvVar(env string) map[string][]v1.Pod {
|
|
||||||
var mapOfList map[string][]v1.Pod
|
|
||||||
|
|
||||||
val, present := os.LookupEnv(env)
|
|
||||||
|
|
||||||
if !present {
|
|
||||||
return mapOfList
|
|
||||||
}
|
|
||||||
|
|
||||||
err := json.Unmarshal([]byte(val), &mapOfList)
|
|
||||||
if err != nil {
|
|
||||||
panic(fmt.Sprintf("env var %s's value of %v is invalid! must be map[string][]v1.Pod %v", env, mapOfList, err))
|
|
||||||
}
|
|
||||||
return mapOfList
|
|
||||||
}
|
|
||||||
|
|
||||||
func getTapTargets() []v1.Pod {
|
|
||||||
nodeName := os.Getenv(shared.NodeNameEnvVar)
|
|
||||||
tappedAddressesPerNodeDict := parseEnvVar(shared.TappedAddressesPerNodeDictEnvVar)
|
|
||||||
return tappedAddressesPerNodeDict[nodeName]
|
|
||||||
}
|
|
||||||
|
|
||||||
func getTrafficFilteringOptions() *tapApi.TrafficFilteringOptions {
|
func getTrafficFilteringOptions() *tapApi.TrafficFilteringOptions {
|
||||||
filteringOptionsJson := os.Getenv(shared.MizuFilteringOptionsEnvVar)
|
filteringOptionsJson := os.Getenv(shared.MizuFilteringOptionsEnvVar)
|
||||||
if filteringOptionsJson == "" {
|
if filteringOptionsJson == "" {
|
||||||
@@ -378,6 +353,14 @@ func handleIncomingMessageAsTapper(socketConnection *websocket.Conn) {
|
|||||||
} else {
|
} else {
|
||||||
tap.UpdateTapTargets(tapConfigMessage.TapTargets)
|
tap.UpdateTapTargets(tapConfigMessage.TapTargets)
|
||||||
}
|
}
|
||||||
|
case shared.WebSocketMessageTypeUpdateTappedPods:
|
||||||
|
var tappedPodsMessage shared.WebSocketTappedPodsMessage
|
||||||
|
if err := json.Unmarshal(message, &tappedPodsMessage); err != nil {
|
||||||
|
logger.Log.Infof("Could not unmarshal message of message type %s %v", socketMessageBase.MessageType, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
nodeName := os.Getenv(shared.NodeNameEnvVar)
|
||||||
|
tap.UpdateTapTargets(tappedPodsMessage.NodeToTappedPodMap[nodeName])
|
||||||
default:
|
default:
|
||||||
logger.Log.Warningf("Received socket message of type %s for which no handlers are defined", socketMessageBase.MessageType)
|
logger.Log.Warningf("Received socket message of type %s for which no handlers are defined", socketMessageBase.MessageType)
|
||||||
}
|
}
|
||||||
@@ -385,3 +368,11 @@ func handleIncomingMessageAsTapper(socketConnection *websocket.Conn) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func initializeDependencies() {
|
||||||
|
dependency.RegisterGenerator(dependency.ServiceMapGeneratorDependency, func() interface{} { return servicemap.GetDefaultServiceMapInstance() })
|
||||||
|
dependency.RegisterGenerator(dependency.OasGeneratorDependency, func() interface{} { return oas.GetDefaultOasGeneratorInstance(nil) })
|
||||||
|
dependency.RegisterGenerator(dependency.EntriesProvider, func() interface{} { return &entries.BasenineEntriesProvider{} })
|
||||||
|
dependency.RegisterGenerator(dependency.EntriesSocketStreamer, func() interface{} { return &api.BasenineEntryStreamer{} })
|
||||||
|
dependency.RegisterGenerator(dependency.EntryStreamerSocketConnector, func() interface{} { return &api.DefaultEntryStreamerSocketConnector{} })
|
||||||
|
}
|
||||||
|
|||||||
57
agent/pkg/api/entry_streamer_socket_connector.go
Normal file
57
agent/pkg/api/entry_streamer_socket_connector.go
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
basenine "github.com/up9inc/basenine/client/go"
|
||||||
|
"github.com/up9inc/mizu/agent/pkg/models"
|
||||||
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
|
tapApi "github.com/up9inc/mizu/tap/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EntryStreamerSocketConnector interface {
|
||||||
|
SendEntry(socketId int, entry *tapApi.Entry, params *WebSocketParams)
|
||||||
|
SendMetadata(socketId int, metadata *basenine.Metadata)
|
||||||
|
SendToastError(socketId int, err error)
|
||||||
|
CleanupSocket(socketId int)
|
||||||
|
}
|
||||||
|
|
||||||
|
type DefaultEntryStreamerSocketConnector struct{}
|
||||||
|
|
||||||
|
func (e *DefaultEntryStreamerSocketConnector) SendEntry(socketId int, entry *tapApi.Entry, params *WebSocketParams) {
|
||||||
|
var message []byte
|
||||||
|
if params.EnableFullEntries {
|
||||||
|
message, _ = models.CreateFullEntryWebSocketMessage(entry)
|
||||||
|
} else {
|
||||||
|
extension := extensionsMap[entry.Protocol.Name]
|
||||||
|
base := extension.Dissector.Summarize(entry)
|
||||||
|
message, _ = models.CreateBaseEntryWebSocketMessage(base)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := SendToSocket(socketId, message); err != nil {
|
||||||
|
logger.Log.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *DefaultEntryStreamerSocketConnector) SendMetadata(socketId int, metadata *basenine.Metadata) {
|
||||||
|
metadataBytes, _ := models.CreateWebsocketQueryMetadataMessage(metadata)
|
||||||
|
if err := SendToSocket(socketId, metadataBytes); err != nil {
|
||||||
|
logger.Log.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *DefaultEntryStreamerSocketConnector) SendToastError(socketId int, err error) {
|
||||||
|
toastBytes, _ := models.CreateWebsocketToastMessage(&models.ToastMessage{
|
||||||
|
Type: "error",
|
||||||
|
AutoClose: 5000,
|
||||||
|
Text: fmt.Sprintf("Syntax error: %s", err.Error()),
|
||||||
|
})
|
||||||
|
if err := SendToSocket(socketId, toastBytes); err != nil {
|
||||||
|
logger.Log.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *DefaultEntryStreamerSocketConnector) CleanupSocket(socketId int) {
|
||||||
|
socketObj := connectedWebsockets[socketId]
|
||||||
|
socketCleanup(socketId, socketObj)
|
||||||
|
}
|
||||||
@@ -5,12 +5,14 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/up9inc/mizu/agent/pkg/models"
|
||||||
"os"
|
"os"
|
||||||
"path"
|
"path"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/up9inc/mizu/agent/pkg/dependency"
|
||||||
"github.com/up9inc/mizu/agent/pkg/elastic"
|
"github.com/up9inc/mizu/agent/pkg/elastic"
|
||||||
"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"
|
||||||
@@ -18,8 +20,6 @@ import (
|
|||||||
|
|
||||||
"github.com/up9inc/mizu/agent/pkg/servicemap"
|
"github.com/up9inc/mizu/agent/pkg/servicemap"
|
||||||
|
|
||||||
"github.com/up9inc/mizu/agent/pkg/models"
|
|
||||||
"github.com/up9inc/mizu/agent/pkg/oas"
|
|
||||||
"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"
|
||||||
|
|
||||||
@@ -139,19 +139,6 @@ func startReadingChannel(outputItems <-chan *tapApi.OutputChannelItem, extension
|
|||||||
rules, _, _ := models.RunValidationRulesState(*harEntry, mizuEntry.Destination.Name)
|
rules, _, _ := models.RunValidationRulesState(*harEntry, mizuEntry.Destination.Name)
|
||||||
mizuEntry.Rules = rules
|
mizuEntry.Rules = rules
|
||||||
}
|
}
|
||||||
|
|
||||||
entryWSource := oas.EntryWithSource{
|
|
||||||
Entry: *harEntry,
|
|
||||||
Source: mizuEntry.Source.Name,
|
|
||||||
Destination: mizuEntry.Destination.Name,
|
|
||||||
Id: mizuEntry.Id,
|
|
||||||
}
|
|
||||||
|
|
||||||
if entryWSource.Destination == "" {
|
|
||||||
entryWSource.Destination = mizuEntry.Destination.IP + ":" + mizuEntry.Destination.Port
|
|
||||||
}
|
|
||||||
|
|
||||||
oas.GetOasGeneratorInstance().PushEntry(&entryWSource)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
data, err := json.Marshal(mizuEntry)
|
data, err := json.Marshal(mizuEntry)
|
||||||
@@ -163,7 +150,9 @@ func startReadingChannel(outputItems <-chan *tapApi.OutputChannelItem, extension
|
|||||||
|
|
||||||
connection.SendText(string(data))
|
connection.SendText(string(data))
|
||||||
|
|
||||||
servicemap.GetInstance().NewTCPEntry(mizuEntry.Source, mizuEntry.Destination, &item.Protocol)
|
serviceMapGenerator := dependency.GetInstance(dependency.ServiceMapGeneratorDependency).(servicemap.ServiceMapSink)
|
||||||
|
serviceMapGenerator.NewTCPEntry(mizuEntry.Source, mizuEntry.Destination, &item.Protocol)
|
||||||
|
|
||||||
elastic.GetInstance().PushEntry(mizuEntry)
|
elastic.GetInstance().PushEntry(mizuEntry)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -179,6 +168,7 @@ func resolveIP(connectionInfo *tapApi.ConnectionInfo) (resolvedSource string, re
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
resolvedSource = resolvedSourceObject.FullAddress
|
resolvedSource = resolvedSourceObject.FullAddress
|
||||||
|
namespace = resolvedSourceObject.Namespace
|
||||||
}
|
}
|
||||||
|
|
||||||
unresolvedDestination := fmt.Sprintf("%s:%s", connectionInfo.ServerIP, connectionInfo.ServerPort)
|
unresolvedDestination := fmt.Sprintf("%s:%s", connectionInfo.ServerIP, connectionInfo.ServerPort)
|
||||||
@@ -190,7 +180,11 @@ func resolveIP(connectionInfo *tapApi.ConnectionInfo) (resolvedSource string, re
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
resolvedDestination = resolvedDestinationObject.FullAddress
|
resolvedDestination = resolvedDestinationObject.FullAddress
|
||||||
namespace = resolvedDestinationObject.Namespace
|
// Overwrite namespace (if it was set according to the source)
|
||||||
|
// Only overwrite if non-empty
|
||||||
|
if resolvedDestinationObject.Namespace != "" {
|
||||||
|
namespace = resolvedDestinationObject.Namespace
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return resolvedSource, resolvedDestination, namespace
|
return resolvedSource, resolvedDestination, namespace
|
||||||
|
|||||||
92
agent/pkg/api/socket_data_streamer.go
Normal file
92
agent/pkg/api/socket_data_streamer.go
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
|
||||||
|
basenine "github.com/up9inc/basenine/client/go"
|
||||||
|
"github.com/up9inc/mizu/agent/pkg/dependency"
|
||||||
|
"github.com/up9inc/mizu/shared"
|
||||||
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
|
tapApi "github.com/up9inc/mizu/tap/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EntryStreamer interface {
|
||||||
|
Get(ctx context.Context, socketId int, params *WebSocketParams) error
|
||||||
|
}
|
||||||
|
|
||||||
|
type BasenineEntryStreamer struct{}
|
||||||
|
|
||||||
|
func (e *BasenineEntryStreamer) Get(ctx context.Context, socketId int, params *WebSocketParams) error {
|
||||||
|
var connection *basenine.Connection
|
||||||
|
|
||||||
|
entryStreamerSocketConnector := dependency.GetInstance(dependency.EntryStreamerSocketConnector).(EntryStreamerSocketConnector)
|
||||||
|
|
||||||
|
connection, err := basenine.NewConnection(shared.BasenineHost, shared.BaseninePort)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log.Errorf("failed to establish a connection to Basenine: %v", err)
|
||||||
|
entryStreamerSocketConnector.CleanupSocket(socketId)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
data := make(chan []byte)
|
||||||
|
meta := make(chan []byte)
|
||||||
|
|
||||||
|
query := params.Query
|
||||||
|
err = basenine.Validate(shared.BasenineHost, shared.BaseninePort, query)
|
||||||
|
if err != nil {
|
||||||
|
entryStreamerSocketConnector.SendToastError(socketId, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
handleDataChannel := func(c *basenine.Connection, data chan []byte) {
|
||||||
|
for {
|
||||||
|
bytes := <-data
|
||||||
|
|
||||||
|
if string(bytes) == basenine.CloseChannel {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var entry *tapApi.Entry
|
||||||
|
err = json.Unmarshal(bytes, &entry)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log.Debugf("error unmarshalling entry: %v", err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
entryStreamerSocketConnector.SendEntry(socketId, entry, params)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleMetaChannel := func(c *basenine.Connection, meta chan []byte) {
|
||||||
|
for {
|
||||||
|
bytes := <-meta
|
||||||
|
|
||||||
|
if string(bytes) == basenine.CloseChannel {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var metadata *basenine.Metadata
|
||||||
|
err = json.Unmarshal(bytes, &metadata)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log.Debugf("Error unmarshalling metadata: %v", err.Error())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
entryStreamerSocketConnector.SendMetadata(socketId, metadata)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
go handleDataChannel(connection, data)
|
||||||
|
go handleMetaChannel(connection, meta)
|
||||||
|
|
||||||
|
connection.Query(query, data, meta)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
<-ctx.Done()
|
||||||
|
data <- []byte(basenine.CloseChannel)
|
||||||
|
meta <- []byte(basenine.CloseChannel)
|
||||||
|
connection.Close()
|
||||||
|
}()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -1,18 +1,15 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/up9inc/mizu/agent/pkg/models"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/gorilla/websocket"
|
"github.com/gorilla/websocket"
|
||||||
basenine "github.com/up9inc/basenine/client/go"
|
"github.com/up9inc/mizu/agent/pkg/models"
|
||||||
"github.com/up9inc/mizu/shared"
|
"github.com/up9inc/mizu/agent/pkg/utils"
|
||||||
"github.com/up9inc/mizu/shared/logger"
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
tapApi "github.com/up9inc/mizu/tap/api"
|
tapApi "github.com/up9inc/mizu/tap/api"
|
||||||
)
|
)
|
||||||
@@ -24,9 +21,9 @@ func InitExtensionsMap(ref map[string]*tapApi.Extension) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type EventHandlers interface {
|
type EventHandlers interface {
|
||||||
WebSocketConnect(socketId int, isTapper bool)
|
WebSocketConnect(c *gin.Context, socketId int, isTapper bool)
|
||||||
WebSocketDisconnect(socketId int, isTapper bool)
|
WebSocketDisconnect(socketId int, isTapper bool)
|
||||||
WebSocketMessage(socketId int, message []byte)
|
WebSocketMessage(socketId int, isTapper bool, message []byte)
|
||||||
}
|
}
|
||||||
|
|
||||||
type SocketConnection struct {
|
type SocketConnection struct {
|
||||||
@@ -59,13 +56,13 @@ func init() {
|
|||||||
connectedWebsockets = make(map[int]*SocketConnection)
|
connectedWebsockets = make(map[int]*SocketConnection)
|
||||||
}
|
}
|
||||||
|
|
||||||
func WebSocketRoutes(app *gin.Engine, eventHandlers EventHandlers, startTime int64) {
|
func WebSocketRoutes(app *gin.Engine, eventHandlers EventHandlers) {
|
||||||
SocketGetBrowserHandler = func(c *gin.Context) {
|
SocketGetBrowserHandler = func(c *gin.Context) {
|
||||||
websocketHandler(c.Writer, c.Request, eventHandlers, false, startTime)
|
websocketHandler(c, eventHandlers, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
SocketGetTapperHandler = func(c *gin.Context) {
|
SocketGetTapperHandler = func(c *gin.Context) {
|
||||||
websocketHandler(c.Writer, c.Request, eventHandlers, true, startTime)
|
websocketHandler(c, eventHandlers, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
app.GET("/ws", func(c *gin.Context) {
|
app.GET("/ws", func(c *gin.Context) {
|
||||||
@@ -77,10 +74,10 @@ func WebSocketRoutes(app *gin.Engine, eventHandlers EventHandlers, startTime int
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func websocketHandler(w http.ResponseWriter, r *http.Request, eventHandlers EventHandlers, isTapper bool, startTime int64) {
|
func websocketHandler(c *gin.Context, eventHandlers EventHandlers, isTapper bool) {
|
||||||
ws, err := websocketUpgrader.Upgrade(w, r, nil)
|
ws, err := websocketUpgrader.Upgrade(c.Writer, c.Request, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Log.Errorf("Failed to set websocket upgrade: %v", err)
|
logger.Log.Errorf("failed to set websocket upgrade: %v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,150 +89,44 @@ func websocketHandler(w http.ResponseWriter, r *http.Request, eventHandlers Even
|
|||||||
|
|
||||||
websocketIdsLock.Unlock()
|
websocketIdsLock.Unlock()
|
||||||
|
|
||||||
var connection *basenine.Connection
|
|
||||||
var isQuerySet bool
|
|
||||||
|
|
||||||
// `!isTapper` means it's a connection from the web UI
|
|
||||||
if !isTapper {
|
|
||||||
connection, err = basenine.NewConnection(shared.BasenineHost, shared.BaseninePort)
|
|
||||||
if err != nil {
|
|
||||||
panic(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data := make(chan []byte)
|
|
||||||
meta := make(chan []byte)
|
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
socketCleanup(socketId, connectedWebsockets[socketId])
|
socketCleanup(socketId, connectedWebsockets[socketId])
|
||||||
data <- []byte(basenine.CloseChannel)
|
|
||||||
meta <- []byte(basenine.CloseChannel)
|
|
||||||
connection.Close()
|
|
||||||
}()
|
}()
|
||||||
|
|
||||||
eventHandlers.WebSocketConnect(socketId, isTapper)
|
eventHandlers.WebSocketConnect(c, socketId, isTapper)
|
||||||
|
|
||||||
startTimeBytes, _ := models.CreateWebsocketStartTimeMessage(startTime)
|
startTimeBytes, _ := models.CreateWebsocketStartTimeMessage(utils.StartTime)
|
||||||
|
|
||||||
if err = SendToSocket(socketId, startTimeBytes); err != nil {
|
if err = SendToSocket(socketId, startTimeBytes); err != nil {
|
||||||
logger.Log.Error(err)
|
logger.Log.Error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
var params WebSocketParams
|
|
||||||
|
|
||||||
for {
|
for {
|
||||||
_, msg, err := ws.ReadMessage()
|
_, msg, err := ws.ReadMessage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if _, ok := err.(*websocket.CloseError); ok {
|
if _, ok := err.(*websocket.CloseError); ok {
|
||||||
logger.Log.Debugf("Received websocket close message, socket id: %d", socketId)
|
logger.Log.Debugf("received websocket close message, socket id: %d", socketId)
|
||||||
} else {
|
} else {
|
||||||
logger.Log.Errorf("Error reading message, socket id: %d, error: %v", socketId, err)
|
logger.Log.Errorf("error reading message, socket id: %d, error: %v", socketId, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if !isTapper && !isQuerySet {
|
eventHandlers.WebSocketMessage(socketId, isTapper, msg)
|
||||||
if err := json.Unmarshal(msg, ¶ms); err != nil {
|
|
||||||
logger.Log.Errorf("Error: %v", socketId, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
query := params.Query
|
|
||||||
err = basenine.Validate(shared.BasenineHost, shared.BaseninePort, query)
|
|
||||||
if err != nil {
|
|
||||||
toastBytes, _ := models.CreateWebsocketToastMessage(&models.ToastMessage{
|
|
||||||
Type: "error",
|
|
||||||
AutoClose: 5000,
|
|
||||||
Text: fmt.Sprintf("Syntax error: %s", err.Error()),
|
|
||||||
})
|
|
||||||
if err := SendToSocket(socketId, toastBytes); err != nil {
|
|
||||||
logger.Log.Error(err)
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
isQuerySet = true
|
|
||||||
|
|
||||||
handleDataChannel := func(c *basenine.Connection, data chan []byte) {
|
|
||||||
for {
|
|
||||||
bytes := <-data
|
|
||||||
|
|
||||||
if string(bytes) == basenine.CloseChannel {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var entry *tapApi.Entry
|
|
||||||
err = json.Unmarshal(bytes, &entry)
|
|
||||||
|
|
||||||
var message []byte
|
|
||||||
if params.EnableFullEntries {
|
|
||||||
message, _ = models.CreateFullEntryWebSocketMessage(entry)
|
|
||||||
} else {
|
|
||||||
extension := extensionsMap[entry.Protocol.Name]
|
|
||||||
base := extension.Dissector.Summarize(entry)
|
|
||||||
message, _ = models.CreateBaseEntryWebSocketMessage(base)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := SendToSocket(socketId, message); err != nil {
|
|
||||||
logger.Log.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
handleMetaChannel := func(c *basenine.Connection, meta chan []byte) {
|
|
||||||
for {
|
|
||||||
bytes := <-meta
|
|
||||||
|
|
||||||
if string(bytes) == basenine.CloseChannel {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var metadata *basenine.Metadata
|
|
||||||
err = json.Unmarshal(bytes, &metadata)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Debugf("Error recieving metadata: %v", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
metadataBytes, _ := models.CreateWebsocketQueryMetadataMessage(metadata)
|
|
||||||
if err := SendToSocket(socketId, metadataBytes); err != nil {
|
|
||||||
logger.Log.Error(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
go handleDataChannel(connection, data)
|
|
||||||
go handleMetaChannel(connection, meta)
|
|
||||||
|
|
||||||
connection.Query(query, data, meta)
|
|
||||||
} else {
|
|
||||||
eventHandlers.WebSocketMessage(socketId, msg)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func socketCleanup(socketId int, socketConnection *SocketConnection) {
|
|
||||||
err := socketConnection.connection.Close()
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Errorf("Error closing socket connection for socket id %d: %v", socketId, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
websocketIdsLock.Lock()
|
|
||||||
connectedWebsockets[socketId] = nil
|
|
||||||
websocketIdsLock.Unlock()
|
|
||||||
|
|
||||||
socketConnection.eventHandlers.WebSocketDisconnect(socketId, socketConnection.isTapper)
|
|
||||||
}
|
|
||||||
|
|
||||||
func SendToSocket(socketId int, message []byte) error {
|
func SendToSocket(socketId int, message []byte) error {
|
||||||
socketObj := connectedWebsockets[socketId]
|
socketObj := connectedWebsockets[socketId]
|
||||||
if socketObj == nil {
|
if socketObj == nil {
|
||||||
return fmt.Errorf("Socket %v is disconnected", socketId)
|
return fmt.Errorf("socket %v is disconnected", socketId)
|
||||||
}
|
}
|
||||||
|
|
||||||
var sent = false
|
var sent = false
|
||||||
time.AfterFunc(time.Second*5, func() {
|
time.AfterFunc(time.Second*5, func() {
|
||||||
if !sent {
|
if !sent {
|
||||||
logger.Log.Error("Socket timed out")
|
logger.Log.Error("socket timed out")
|
||||||
socketCleanup(socketId, socketObj)
|
socketCleanup(socketId, socketObj)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -246,7 +137,20 @@ func SendToSocket(socketId int, message []byte) error {
|
|||||||
sent = true
|
sent = true
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Failed to write message to socket %v, err: %w", socketId, err)
|
return fmt.Errorf("failed to write message to socket %v, err: %w", socketId, err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func socketCleanup(socketId int, socketConnection *SocketConnection) {
|
||||||
|
err := socketConnection.connection.Close()
|
||||||
|
if err != nil {
|
||||||
|
logger.Log.Errorf("error closing socket connection for socket id %d: %v", socketId, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
websocketIdsLock.Lock()
|
||||||
|
connectedWebsockets[socketId] = nil
|
||||||
|
websocketIdsLock.Unlock()
|
||||||
|
|
||||||
|
socketConnection.eventHandlers.WebSocketDisconnect(socketId, socketConnection.isTapper)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
package api
|
package api
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/up9inc/mizu/agent/pkg/dependency"
|
||||||
"github.com/up9inc/mizu/agent/pkg/models"
|
"github.com/up9inc/mizu/agent/pkg/models"
|
||||||
"github.com/up9inc/mizu/agent/pkg/providers"
|
"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/up9"
|
||||||
|
|
||||||
@@ -16,7 +18,12 @@ import (
|
|||||||
"github.com/up9inc/mizu/shared/logger"
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
var browserClientSocketUUIDs = make([]int, 0)
|
type BrowserClient struct {
|
||||||
|
dataStreamCancelFunc context.CancelFunc
|
||||||
|
}
|
||||||
|
|
||||||
|
var browserClients = make(map[int]*BrowserClient, 0)
|
||||||
|
var tapperClientSocketUUIDs = make([]int, 0)
|
||||||
var socketListLock = sync.Mutex{}
|
var socketListLock = sync.Mutex{}
|
||||||
|
|
||||||
type RoutesEventHandlers struct {
|
type RoutesEventHandlers struct {
|
||||||
@@ -28,15 +35,22 @@ func init() {
|
|||||||
go up9.UpdateAnalyzeStatus(BroadcastToBrowserClients)
|
go up9.UpdateAnalyzeStatus(BroadcastToBrowserClients)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *RoutesEventHandlers) WebSocketConnect(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)
|
||||||
tappers.Connected()
|
tappers.Connected()
|
||||||
|
|
||||||
|
socketListLock.Lock()
|
||||||
|
tapperClientSocketUUIDs = append(tapperClientSocketUUIDs, socketId)
|
||||||
|
socketListLock.Unlock()
|
||||||
|
|
||||||
|
nodeToTappedPodMap := tappedPods.GetNodeToTappedPodMap()
|
||||||
|
SendTappedPods(socketId, nodeToTappedPodMap)
|
||||||
} else {
|
} else {
|
||||||
logger.Log.Infof("Websocket event - Browser socket connected, socket ID: %d", socketId)
|
logger.Log.Infof("Websocket event - Browser socket connected, socket ID: %d", socketId)
|
||||||
|
|
||||||
socketListLock.Lock()
|
socketListLock.Lock()
|
||||||
browserClientSocketUUIDs = append(browserClientSocketUUIDs, socketId)
|
browserClients[socketId] = &BrowserClient{}
|
||||||
socketListLock.Unlock()
|
socketListLock.Unlock()
|
||||||
|
|
||||||
BroadcastTappedPodsStatus()
|
BroadcastTappedPodsStatus()
|
||||||
@@ -47,16 +61,23 @@ func (h *RoutesEventHandlers) WebSocketDisconnect(socketId int, isTapper bool) {
|
|||||||
if isTapper {
|
if isTapper {
|
||||||
logger.Log.Infof("Websocket event - Tapper disconnected, socket ID: %d", socketId)
|
logger.Log.Infof("Websocket event - Tapper disconnected, socket ID: %d", socketId)
|
||||||
tappers.Disconnected()
|
tappers.Disconnected()
|
||||||
|
|
||||||
|
socketListLock.Lock()
|
||||||
|
removeSocketUUIDFromTapperSlice(socketId)
|
||||||
|
socketListLock.Unlock()
|
||||||
} else {
|
} else {
|
||||||
logger.Log.Infof("Websocket event - Browser socket disconnected, socket ID: %d", socketId)
|
logger.Log.Infof("Websocket event - Browser socket disconnected, socket ID: %d", socketId)
|
||||||
socketListLock.Lock()
|
socketListLock.Lock()
|
||||||
removeSocketUUIDFromBrowserSlice(socketId)
|
if browserClients[socketId] != nil && browserClients[socketId].dataStreamCancelFunc != nil {
|
||||||
|
browserClients[socketId].dataStreamCancelFunc()
|
||||||
|
}
|
||||||
|
delete(browserClients, socketId)
|
||||||
socketListLock.Unlock()
|
socketListLock.Unlock()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func BroadcastToBrowserClients(message []byte) {
|
func BroadcastToBrowserClients(message []byte) {
|
||||||
for _, socketId := range browserClientSocketUUIDs {
|
for socketId := range browserClients {
|
||||||
go func(socketId int) {
|
go func(socketId int) {
|
||||||
if err := SendToSocket(socketId, message); err != nil {
|
if err := SendToSocket(socketId, message); err != nil {
|
||||||
logger.Log.Error(err)
|
logger.Log.Error(err)
|
||||||
@@ -65,7 +86,43 @@ func BroadcastToBrowserClients(message []byte) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *RoutesEventHandlers) WebSocketMessage(_ int, message []byte) {
|
func BroadcastToTapperClients(message []byte) {
|
||||||
|
for _, socketId := range tapperClientSocketUUIDs {
|
||||||
|
go func(socketId int) {
|
||||||
|
if err := SendToSocket(socketId, message); err != nil {
|
||||||
|
logger.Log.Error(err)
|
||||||
|
}
|
||||||
|
}(socketId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *RoutesEventHandlers) WebSocketMessage(socketId int, isTapper bool, message []byte) {
|
||||||
|
if isTapper {
|
||||||
|
HandleTapperIncomingMessage(message, h.SocketOutChannel, BroadcastToBrowserClients)
|
||||||
|
} else {
|
||||||
|
// we initiate the basenine stream after the first websocket message we receive (it contains the entry query), we then store a cancelfunc to later cancel this stream
|
||||||
|
if browserClients[socketId] != nil && browserClients[socketId].dataStreamCancelFunc == nil {
|
||||||
|
var params WebSocketParams
|
||||||
|
if err := json.Unmarshal(message, ¶ms); err != nil {
|
||||||
|
logger.Log.Errorf("Error: %v", socketId, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
entriesStreamer := dependency.GetInstance(dependency.EntriesSocketStreamer).(EntryStreamer)
|
||||||
|
ctx, cancelFunc := context.WithCancel(context.Background())
|
||||||
|
err := entriesStreamer.Get(ctx, socketId, ¶ms)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Log.Errorf("error initializing basenine stream for browser socket %d %+v", socketId, err)
|
||||||
|
cancelFunc()
|
||||||
|
} else {
|
||||||
|
browserClients[socketId].dataStreamCancelFunc = cancelFunc
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func HandleTapperIncomingMessage(message []byte, socketOutChannel chan<- *tapApi.OutputChannelItem, broadcastMessageFunc func([]byte)) {
|
||||||
var socketMessageBase shared.WebSocketMessageMetadata
|
var socketMessageBase shared.WebSocketMessageMetadata
|
||||||
err := json.Unmarshal(message, &socketMessageBase)
|
err := json.Unmarshal(message, &socketMessageBase)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -79,7 +136,7 @@ func (h *RoutesEventHandlers) WebSocketMessage(_ int, message []byte) {
|
|||||||
logger.Log.Infof("Could not unmarshal message of message type %s %v", socketMessageBase.MessageType, err)
|
logger.Log.Infof("Could not unmarshal message of message type %s %v", socketMessageBase.MessageType, err)
|
||||||
} else {
|
} else {
|
||||||
// NOTE: This is where the message comes back from the intermediate WebSocket to code.
|
// NOTE: This is where the message comes back from the intermediate WebSocket to code.
|
||||||
h.SocketOutChannel <- tappedEntryMessage.Data
|
socketOutChannel <- tappedEntryMessage.Data
|
||||||
}
|
}
|
||||||
case shared.WebSocketMessageTypeUpdateStatus:
|
case shared.WebSocketMessageTypeUpdateStatus:
|
||||||
var statusMessage shared.WebSocketStatusMessage
|
var statusMessage shared.WebSocketStatusMessage
|
||||||
@@ -87,15 +144,7 @@ func (h *RoutesEventHandlers) WebSocketMessage(_ int, message []byte) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Log.Infof("Could not unmarshal message of message type %s %v", socketMessageBase.MessageType, err)
|
logger.Log.Infof("Could not unmarshal message of message type %s %v", socketMessageBase.MessageType, err)
|
||||||
} else {
|
} else {
|
||||||
BroadcastToBrowserClients(message)
|
broadcastMessageFunc(message)
|
||||||
}
|
|
||||||
case shared.WebsocketMessageTypeOutboundLink:
|
|
||||||
var outboundLinkMessage models.WebsocketOutboundLinkMessage
|
|
||||||
err := json.Unmarshal(message, &outboundLinkMessage)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Infof("Could not unmarshal message of message type %s %v", socketMessageBase.MessageType, err)
|
|
||||||
} else {
|
|
||||||
handleTLSLink(outboundLinkMessage)
|
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
logger.Log.Infof("Received socket message of type %s for which no handlers are defined", socketMessageBase.MessageType)
|
logger.Log.Infof("Received socket message of type %s for which no handlers are defined", socketMessageBase.MessageType)
|
||||||
@@ -103,35 +152,12 @@ func (h *RoutesEventHandlers) WebSocketMessage(_ int, message []byte) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleTLSLink(outboundLinkMessage models.WebsocketOutboundLinkMessage) {
|
func removeSocketUUIDFromTapperSlice(uuidToRemove int) {
|
||||||
resolvedNameObject := k8sResolver.Resolve(outboundLinkMessage.Data.DstIP)
|
newUUIDSlice := make([]int, 0, len(tapperClientSocketUUIDs))
|
||||||
if resolvedNameObject != nil {
|
for _, uuid := range tapperClientSocketUUIDs {
|
||||||
outboundLinkMessage.Data.DstIP = resolvedNameObject.FullAddress
|
|
||||||
} else if outboundLinkMessage.Data.SuggestedResolvedName != "" {
|
|
||||||
outboundLinkMessage.Data.DstIP = outboundLinkMessage.Data.SuggestedResolvedName
|
|
||||||
}
|
|
||||||
cacheKey := fmt.Sprintf("%s -> %s:%d", outboundLinkMessage.Data.Src, outboundLinkMessage.Data.DstIP, outboundLinkMessage.Data.DstPort)
|
|
||||||
_, isInCache := providers.RecentTLSLinks.Get(cacheKey)
|
|
||||||
if isInCache {
|
|
||||||
return
|
|
||||||
} else {
|
|
||||||
providers.RecentTLSLinks.SetDefault(cacheKey, outboundLinkMessage.Data)
|
|
||||||
}
|
|
||||||
marshaledMessage, err := json.Marshal(outboundLinkMessage)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Errorf("Error marshaling outbound link message for broadcasting: %v", err)
|
|
||||||
} else {
|
|
||||||
logger.Log.Errorf("Broadcasting outboundlink message %s", string(marshaledMessage))
|
|
||||||
BroadcastToBrowserClients(marshaledMessage)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func removeSocketUUIDFromBrowserSlice(uuidToRemove int) {
|
|
||||||
newUUIDSlice := make([]int, 0, len(browserClientSocketUUIDs))
|
|
||||||
for _, uuid := range browserClientSocketUUIDs {
|
|
||||||
if uuid != uuidToRemove {
|
if uuid != uuidToRemove {
|
||||||
newUUIDSlice = append(newUUIDSlice, uuid)
|
newUUIDSlice = append(newUUIDSlice, uuid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
browserClientSocketUUIDs = newUUIDSlice
|
tapperClientSocketUUIDs = newUUIDSlice
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,3 +18,23 @@ func BroadcastTappedPodsStatus() {
|
|||||||
BroadcastToBrowserClients(jsonBytes)
|
BroadcastToBrowserClients(jsonBytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SendTappedPods(socketId int, nodeToTappedPodMap shared.NodeToPodsMap) {
|
||||||
|
message := shared.CreateWebSocketTappedPodsMessage(nodeToTappedPodMap)
|
||||||
|
if jsonBytes, err := json.Marshal(message); err != nil {
|
||||||
|
logger.Log.Errorf("Could not Marshal message %v", err)
|
||||||
|
} else {
|
||||||
|
if err := SendToSocket(socketId, jsonBytes); err != nil {
|
||||||
|
logger.Log.Error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BroadcastTappedPodsToTappers(nodeToTappedPodMap shared.NodeToPodsMap) {
|
||||||
|
message := shared.CreateWebSocketTappedPodsMessage(nodeToTappedPodMap)
|
||||||
|
if jsonBytes, err := json.Marshal(message); err != nil {
|
||||||
|
logger.Log.Errorf("Could not Marshal message %v", err)
|
||||||
|
} else {
|
||||||
|
BroadcastToTapperClients(jsonBytes)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ 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/controllers"
|
"github.com/up9inc/mizu/agent/pkg/utils"
|
||||||
"github.com/up9inc/mizu/shared/logger"
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
tapApi "github.com/up9inc/mizu/tap/api"
|
tapApi "github.com/up9inc/mizu/tap/api"
|
||||||
amqpExt "github.com/up9inc/mizu/tap/extensions/amqp"
|
amqpExt "github.com/up9inc/mizu/tap/extensions/amqp"
|
||||||
@@ -59,7 +59,6 @@ func LoadExtensions() {
|
|||||||
return Extensions[i].Protocol.Priority < Extensions[j].Protocol.Priority
|
return Extensions[i].Protocol.Priority < Extensions[j].Protocol.Priority
|
||||||
})
|
})
|
||||||
|
|
||||||
controllers.InitExtensionsMap(ExtensionsMap)
|
|
||||||
api.InitExtensionsMap(ExtensionsMap)
|
api.InitExtensionsMap(ExtensionsMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,6 +91,8 @@ func ConfigureBasenineServer(host string, port string, dbSize int64, logLevel lo
|
|||||||
if err := basenine.InsertionFilter(host, port, insertionFilter); err != nil {
|
if err := basenine.InsertionFilter(host, port, insertionFilter); err != nil {
|
||||||
logger.Log.Errorf("Error while setting the insertion filter: %v", err)
|
logger.Log.Errorf("Error while setting the insertion filter: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
utils.StartTime = time.Now().UnixNano() / int64(time.Millisecond)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetEntryInputChannel() chan *tapApi.OutputChannelItem {
|
func GetEntryInputChannel() chan *tapApi.OutputChannelItem {
|
||||||
|
|||||||
28
agent/pkg/controllers/db_controller.go
Normal file
28
agent/pkg/controllers/db_controller.go
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
package controllers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
basenine "github.com/up9inc/basenine/client/go"
|
||||||
|
"github.com/up9inc/mizu/agent/pkg/app"
|
||||||
|
"github.com/up9inc/mizu/agent/pkg/config"
|
||||||
|
"github.com/up9inc/mizu/shared"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Flush(c *gin.Context) {
|
||||||
|
if err := basenine.Flush(shared.BasenineHost, shared.BaseninePort); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, err)
|
||||||
|
} else {
|
||||||
|
c.JSON(http.StatusOK, "Flushed.")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Reset(c *gin.Context) {
|
||||||
|
if err := basenine.Reset(shared.BasenineHost, shared.BaseninePort); err != nil {
|
||||||
|
c.JSON(http.StatusBadRequest, err)
|
||||||
|
} else {
|
||||||
|
app.ConfigureBasenineServer(shared.BasenineHost, shared.BaseninePort, config.Config.MaxDBSizeBytes, config.Config.LogLevel, config.Config.InsertionFilter)
|
||||||
|
c.JSON(http.StatusOK, "Resetted.")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,30 +1,20 @@
|
|||||||
package controllers
|
package controllers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strconv"
|
"strconv"
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/up9inc/mizu/agent/pkg/har"
|
"github.com/up9inc/mizu/agent/pkg/dependency"
|
||||||
|
"github.com/up9inc/mizu/agent/pkg/entries"
|
||||||
"github.com/up9inc/mizu/agent/pkg/models"
|
"github.com/up9inc/mizu/agent/pkg/models"
|
||||||
"github.com/up9inc/mizu/agent/pkg/validation"
|
"github.com/up9inc/mizu/agent/pkg/validation"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
|
||||||
basenine "github.com/up9inc/basenine/client/go"
|
|
||||||
"github.com/up9inc/mizu/shared"
|
|
||||||
"github.com/up9inc/mizu/shared/logger"
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
tapApi "github.com/up9inc/mizu/tap/api"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var extensionsMap map[string]*tapApi.Extension // global
|
func HandleEntriesError(c *gin.Context, err error) bool {
|
||||||
|
|
||||||
func InitExtensionsMap(ref map[string]*tapApi.Extension) {
|
|
||||||
extensionsMap = ref
|
|
||||||
}
|
|
||||||
|
|
||||||
func Error(c *gin.Context, err error) bool {
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Log.Errorf("Error getting entry: %v", err)
|
logger.Log.Errorf("Error getting entry: %v", err)
|
||||||
_ = c.Error(err)
|
_ = c.Error(err)
|
||||||
@@ -54,45 +44,18 @@ func GetEntries(c *gin.Context) {
|
|||||||
entriesRequest.TimeoutMs = 3000
|
entriesRequest.TimeoutMs = 3000
|
||||||
}
|
}
|
||||||
|
|
||||||
data, meta, err := basenine.Fetch(shared.BasenineHost, shared.BaseninePort,
|
entriesProvider := dependency.GetInstance(dependency.EntriesProvider).(entries.EntriesProvider)
|
||||||
entriesRequest.LeftOff, entriesRequest.Direction, entriesRequest.Query,
|
entries, metadata, err := entriesProvider.GetEntries(entriesRequest)
|
||||||
entriesRequest.Limit, time.Duration(entriesRequest.TimeoutMs)*time.Millisecond)
|
if !HandleEntriesError(c, err) {
|
||||||
if err != nil {
|
baseEntries := make([]interface{}, 0)
|
||||||
c.JSON(http.StatusInternalServerError, validationError)
|
for _, entry := range entries {
|
||||||
}
|
baseEntries = append(baseEntries, entry.Base)
|
||||||
|
|
||||||
response := &models.EntriesResponse{}
|
|
||||||
var dataSlice []interface{}
|
|
||||||
|
|
||||||
for _, row := range data {
|
|
||||||
var entry *tapApi.Entry
|
|
||||||
err = json.Unmarshal(row, &entry)
|
|
||||||
if err != nil {
|
|
||||||
c.JSON(http.StatusBadRequest, gin.H{
|
|
||||||
"error": true,
|
|
||||||
"type": "error",
|
|
||||||
"autoClose": "5000",
|
|
||||||
"msg": string(row),
|
|
||||||
})
|
|
||||||
return // exit
|
|
||||||
}
|
}
|
||||||
|
c.JSON(http.StatusOK, models.EntriesResponse{
|
||||||
extension := extensionsMap[entry.Protocol.Name]
|
Data: baseEntries,
|
||||||
base := extension.Dissector.Summarize(entry)
|
Meta: metadata,
|
||||||
|
})
|
||||||
dataSlice = append(dataSlice, base)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var metadata *basenine.Metadata
|
|
||||||
err = json.Unmarshal(meta, &metadata)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Debugf("Error recieving metadata: %v", err.Error())
|
|
||||||
}
|
|
||||||
|
|
||||||
response.Data = dataSlice
|
|
||||||
response.Meta = metadata
|
|
||||||
|
|
||||||
c.JSON(http.StatusOK, response)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetEntry(c *gin.Context) {
|
func GetEntry(c *gin.Context) {
|
||||||
@@ -107,45 +70,11 @@ func GetEntry(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
id, _ := strconv.Atoi(c.Param("id"))
|
id, _ := strconv.Atoi(c.Param("id"))
|
||||||
var entry *tapApi.Entry
|
|
||||||
bytes, err := basenine.Single(shared.BasenineHost, shared.BaseninePort, id, singleEntryRequest.Query)
|
|
||||||
if Error(c, err) {
|
|
||||||
return // exit
|
|
||||||
}
|
|
||||||
err = json.Unmarshal(bytes, &entry)
|
|
||||||
if err != nil {
|
|
||||||
c.JSON(http.StatusNotFound, gin.H{
|
|
||||||
"error": true,
|
|
||||||
"type": "error",
|
|
||||||
"autoClose": "5000",
|
|
||||||
"msg": string(bytes),
|
|
||||||
})
|
|
||||||
return // exit
|
|
||||||
}
|
|
||||||
|
|
||||||
extension := extensionsMap[entry.Protocol.Name]
|
entriesProvider := dependency.GetInstance(dependency.EntriesProvider).(entries.EntriesProvider)
|
||||||
base := extension.Dissector.Summarize(entry)
|
entry, err := entriesProvider.GetEntry(singleEntryRequest, id)
|
||||||
representation, bodySize, _ := extension.Dissector.Represent(entry.Request, entry.Response)
|
|
||||||
|
|
||||||
var rules []map[string]interface{}
|
if !HandleEntriesError(c, err) {
|
||||||
var isRulesEnabled bool
|
c.JSON(http.StatusOK, entry)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
c.JSON(http.StatusOK, tapApi.EntryWrapper{
|
|
||||||
Protocol: entry.Protocol,
|
|
||||||
Representation: string(representation),
|
|
||||||
BodySize: bodySize,
|
|
||||||
Data: entry,
|
|
||||||
Base: base,
|
|
||||||
Rules: rules,
|
|
||||||
IsRulesEnabled: isRulesEnabled,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,13 +5,15 @@ import (
|
|||||||
|
|
||||||
"github.com/chanced/openapi"
|
"github.com/chanced/openapi"
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/up9inc/mizu/agent/pkg/dependency"
|
||||||
"github.com/up9inc/mizu/agent/pkg/oas"
|
"github.com/up9inc/mizu/agent/pkg/oas"
|
||||||
"github.com/up9inc/mizu/shared/logger"
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetOASServers(c *gin.Context) {
|
func GetOASServers(c *gin.Context) {
|
||||||
m := make([]string, 0)
|
m := make([]string, 0)
|
||||||
oas.GetOasGeneratorInstance().ServiceSpecs.Range(func(key, value interface{}) bool {
|
oasGenerator := dependency.GetInstance(dependency.OasGeneratorDependency).(oas.OasGenerator)
|
||||||
|
oasGenerator.GetServiceSpecs().Range(func(key, value interface{}) bool {
|
||||||
m = append(m, key.(string))
|
m = append(m, key.(string))
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
@@ -20,7 +22,8 @@ func GetOASServers(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func GetOASSpec(c *gin.Context) {
|
func GetOASSpec(c *gin.Context) {
|
||||||
res, ok := oas.GetOasGeneratorInstance().ServiceSpecs.Load(c.Param("id"))
|
oasGenerator := dependency.GetInstance(dependency.OasGeneratorDependency).(oas.OasGenerator)
|
||||||
|
res, ok := oasGenerator.GetServiceSpecs().Load(c.Param("id"))
|
||||||
if !ok {
|
if !ok {
|
||||||
c.JSON(http.StatusNotFound, gin.H{
|
c.JSON(http.StatusNotFound, gin.H{
|
||||||
"error": true,
|
"error": true,
|
||||||
@@ -48,7 +51,9 @@ func GetOASSpec(c *gin.Context) {
|
|||||||
|
|
||||||
func GetOASAllSpecs(c *gin.Context) {
|
func GetOASAllSpecs(c *gin.Context) {
|
||||||
res := map[string]*openapi.OpenAPI{}
|
res := map[string]*openapi.OpenAPI{}
|
||||||
oas.GetOasGeneratorInstance().ServiceSpecs.Range(func(key, value interface{}) bool {
|
|
||||||
|
oasGenerator := dependency.GetInstance(dependency.OasGeneratorDependency).(oas.OasGenerator)
|
||||||
|
oasGenerator.GetServiceSpecs().Range(func(key, value interface{}) bool {
|
||||||
svc := key.(string)
|
svc := key.(string)
|
||||||
gen := value.(*oas.SpecGen)
|
gen := value.(*oas.SpecGen)
|
||||||
spec, err := gen.GetSpec()
|
spec, err := gen.GetSpec()
|
||||||
|
|||||||
@@ -1,42 +1,69 @@
|
|||||||
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/up9inc/mizu/agent/pkg/oas"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestGetOASServers(t *testing.T) {
|
func TestGetOASServers(t *testing.T) {
|
||||||
recorder := httptest.NewRecorder()
|
recorder, c := getRecorderAndContext()
|
||||||
c, _ := gin.CreateTestContext(recorder)
|
|
||||||
oas.GetOasGeneratorInstance().Start()
|
|
||||||
oas.GetOasGeneratorInstance().ServiceSpecs.Store("some", oas.NewGen("some"))
|
|
||||||
|
|
||||||
GetOASServers(c)
|
GetOASServers(c)
|
||||||
t.Logf("Written body: %s", recorder.Body.String())
|
t.Logf("Written body: %s", recorder.Body.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetOASAllSpecs(t *testing.T) {
|
func TestGetOASAllSpecs(t *testing.T) {
|
||||||
recorder := httptest.NewRecorder()
|
recorder, c := getRecorderAndContext()
|
||||||
c, _ := gin.CreateTestContext(recorder)
|
|
||||||
oas.GetOasGeneratorInstance().Start()
|
|
||||||
oas.GetOasGeneratorInstance().ServiceSpecs.Store("some", oas.NewGen("some"))
|
|
||||||
|
|
||||||
GetOASAllSpecs(c)
|
GetOASAllSpecs(c)
|
||||||
t.Logf("Written body: %s", recorder.Body.String())
|
t.Logf("Written body: %s", recorder.Body.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetOASSpec(t *testing.T) {
|
func TestGetOASSpec(t *testing.T) {
|
||||||
recorder := httptest.NewRecorder()
|
recorder, c := getRecorderAndContext()
|
||||||
c, _ := gin.CreateTestContext(recorder)
|
|
||||||
oas.GetOasGeneratorInstance().Start()
|
|
||||||
oas.GetOasGeneratorInstance().ServiceSpecs.Store("some", oas.NewGen("some"))
|
|
||||||
|
|
||||||
c.Params = []gin.Param{{Key: "id", Value: "some"}}
|
c.Params = []gin.Param{{Key: "id", Value: "some"}}
|
||||||
|
|
||||||
GetOASSpec(c)
|
GetOASSpec(c)
|
||||||
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) {
|
||||||
|
dummyConn := new(basenine.Connection)
|
||||||
|
dummyConn.Conn = fakeConn{
|
||||||
|
sendBuffer: bytes.NewBufferString("\n"),
|
||||||
|
receiveBuffer: bytes.NewBufferString("\n"),
|
||||||
|
}
|
||||||
|
dependency.RegisterGenerator(dependency.OasGeneratorDependency, func() interface{} {
|
||||||
|
return oas.GetDefaultOasGeneratorInstance(dummyConn)
|
||||||
|
})
|
||||||
|
|
||||||
|
recorder := httptest.NewRecorder()
|
||||||
|
c, _ := gin.CreateTestContext(recorder)
|
||||||
|
oas.GetDefaultOasGeneratorInstance(dummyConn).Start()
|
||||||
|
oas.GetDefaultOasGeneratorInstance(dummyConn).GetServiceSpecs().Store("some", oas.NewGen("some"))
|
||||||
|
return recorder, c
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package controllers
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/up9inc/mizu/agent/pkg/dependency"
|
||||||
"github.com/up9inc/mizu/agent/pkg/servicemap"
|
"github.com/up9inc/mizu/agent/pkg/servicemap"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@@ -13,8 +14,9 @@ type ServiceMapController struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func NewServiceMapController() *ServiceMapController {
|
func NewServiceMapController() *ServiceMapController {
|
||||||
|
serviceMapGenerator := dependency.GetInstance(dependency.ServiceMapGeneratorDependency).(servicemap.ServiceMap)
|
||||||
return &ServiceMapController{
|
return &ServiceMapController{
|
||||||
service: servicemap.GetInstance(),
|
service: serviceMapGenerator,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import (
|
|||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/up9inc/mizu/agent/pkg/dependency"
|
||||||
"github.com/up9inc/mizu/agent/pkg/servicemap"
|
"github.com/up9inc/mizu/agent/pkg/servicemap"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
@@ -57,9 +58,11 @@ type ServiceMapControllerSuite struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (s *ServiceMapControllerSuite) SetupTest() {
|
func (s *ServiceMapControllerSuite) SetupTest() {
|
||||||
|
dependency.RegisterGenerator(dependency.ServiceMapGeneratorDependency, func() interface{} { return servicemap.GetDefaultServiceMapInstance() })
|
||||||
|
|
||||||
s.c = NewServiceMapController()
|
s.c = NewServiceMapController()
|
||||||
s.c.service.Enable()
|
s.c.service.Enable()
|
||||||
s.c.service.NewTCPEntry(TCPEntryA, TCPEntryB, ProtocolHttp)
|
s.c.service.(servicemap.ServiceMapSink).NewTCPEntry(TCPEntryA, TCPEntryB, ProtocolHttp)
|
||||||
|
|
||||||
s.w = httptest.NewRecorder()
|
s.w = httptest.NewRecorder()
|
||||||
s.g, _ = gin.CreateTestContext(s.w)
|
s.g, _ = gin.CreateTestContext(s.w)
|
||||||
@@ -98,16 +101,18 @@ func (s *ServiceMapControllerSuite) TestGet() {
|
|||||||
|
|
||||||
// response nodes
|
// response nodes
|
||||||
aNode := servicemap.ServiceMapNode{
|
aNode := servicemap.ServiceMapNode{
|
||||||
Id: 1,
|
Id: 1,
|
||||||
Name: TCPEntryA.Name,
|
Name: TCPEntryA.Name,
|
||||||
Entry: TCPEntryA,
|
Entry: TCPEntryA,
|
||||||
Count: 1,
|
Resolved: true,
|
||||||
|
Count: 1,
|
||||||
}
|
}
|
||||||
bNode := servicemap.ServiceMapNode{
|
bNode := servicemap.ServiceMapNode{
|
||||||
Id: 2,
|
Id: 2,
|
||||||
Name: TCPEntryB.Name,
|
Name: TCPEntryB.Name,
|
||||||
Entry: TCPEntryB,
|
Entry: TCPEntryB,
|
||||||
Count: 1,
|
Resolved: true,
|
||||||
|
Count: 1,
|
||||||
}
|
}
|
||||||
assert.Contains(response.Nodes, aNode)
|
assert.Contains(response.Nodes, aNode)
|
||||||
assert.Contains(response.Nodes, bNode)
|
assert.Contains(response.Nodes, bNode)
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package controllers
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
core "k8s.io/api/core/v1"
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/up9inc/mizu/agent/pkg/api"
|
"github.com/up9inc/mizu/agent/pkg/api"
|
||||||
@@ -12,6 +13,7 @@ import (
|
|||||||
"github.com/up9inc/mizu/agent/pkg/up9"
|
"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/shared"
|
"github.com/up9inc/mizu/shared"
|
||||||
|
"github.com/up9inc/mizu/shared/kubernetes"
|
||||||
"github.com/up9inc/mizu/shared/logger"
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -30,15 +32,21 @@ func HealthCheck(c *gin.Context) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func PostTappedPods(c *gin.Context) {
|
func PostTappedPods(c *gin.Context) {
|
||||||
var requestTappedPods []*shared.PodInfo
|
var requestTappedPods []core.Pod
|
||||||
if err := c.Bind(&requestTappedPods); err != nil {
|
if err := c.Bind(&requestTappedPods); err != nil {
|
||||||
c.JSON(http.StatusBadRequest, err)
|
c.JSON(http.StatusBadRequest, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
podInfos := kubernetes.GetPodInfosForPods(requestTappedPods)
|
||||||
|
|
||||||
logger.Log.Infof("[Status] POST request: %d tapped pods", len(requestTappedPods))
|
logger.Log.Infof("[Status] POST request: %d tapped pods", len(requestTappedPods))
|
||||||
tappedPods.Set(requestTappedPods)
|
tappedPods.Set(podInfos)
|
||||||
api.BroadcastTappedPodsStatus()
|
api.BroadcastTappedPodsStatus()
|
||||||
|
|
||||||
|
nodeToTappedPodMap := kubernetes.GetNodeHostToTappedPodsMap(requestTappedPods)
|
||||||
|
tappedPods.SetNodeToTappedPodMap(nodeToTappedPodMap)
|
||||||
|
api.BroadcastTappedPodsToTappers(nodeToTappedPodMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
func PostTapperStatus(c *gin.Context) {
|
func PostTapperStatus(c *gin.Context) {
|
||||||
|
|||||||
11
agent/pkg/dependency/container.go
Normal file
11
agent/pkg/dependency/container.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package dependency
|
||||||
|
|
||||||
|
var typeIntializerMap = make(map[DependencyContainerType]func() interface{}, 0)
|
||||||
|
|
||||||
|
func RegisterGenerator(name DependencyContainerType, fn func() interface{}) {
|
||||||
|
typeIntializerMap[name] = fn
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetInstance(name DependencyContainerType) interface{} {
|
||||||
|
return typeIntializerMap[name]()
|
||||||
|
}
|
||||||
11
agent/pkg/dependency/type_names.go
Normal file
11
agent/pkg/dependency/type_names.go
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
package dependency
|
||||||
|
|
||||||
|
type DependencyContainerType string
|
||||||
|
|
||||||
|
const (
|
||||||
|
ServiceMapGeneratorDependency = "ServiceMapGeneratorDependency"
|
||||||
|
OasGeneratorDependency = "OasGeneratorDependency"
|
||||||
|
EntriesProvider = "EntriesProvider"
|
||||||
|
EntriesSocketStreamer = "EntriesSocketStreamer"
|
||||||
|
EntryStreamerSocketConnector = "EntryStreamerSocketConnector"
|
||||||
|
)
|
||||||
98
agent/pkg/entries/entries_provider.go
Normal file
98
agent/pkg/entries/entries_provider.go
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
package entries
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
basenine "github.com/up9inc/basenine/client/go"
|
||||||
|
"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/shared"
|
||||||
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
|
tapApi "github.com/up9inc/mizu/tap/api"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EntriesProvider interface {
|
||||||
|
GetEntries(entriesRequest *models.EntriesRequest) ([]*tapApi.EntryWrapper, *basenine.Metadata, error)
|
||||||
|
GetEntry(singleEntryRequest *models.SingleEntryRequest, entryId int) (*tapApi.EntryWrapper, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type BasenineEntriesProvider struct{}
|
||||||
|
|
||||||
|
func (e *BasenineEntriesProvider) GetEntries(entriesRequest *models.EntriesRequest) ([]*tapApi.EntryWrapper, *basenine.Metadata, error) {
|
||||||
|
data, meta, err := basenine.Fetch(shared.BasenineHost, shared.BaseninePort,
|
||||||
|
entriesRequest.LeftOff, entriesRequest.Direction, entriesRequest.Query,
|
||||||
|
entriesRequest.Limit, time.Duration(entriesRequest.TimeoutMs)*time.Millisecond)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var dataSlice []*tapApi.EntryWrapper
|
||||||
|
|
||||||
|
for _, row := range data {
|
||||||
|
var entry *tapApi.Entry
|
||||||
|
err = json.Unmarshal(row, &entry)
|
||||||
|
if err != nil {
|
||||||
|
return nil, nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
extension := app.ExtensionsMap[entry.Protocol.Name]
|
||||||
|
base := extension.Dissector.Summarize(entry)
|
||||||
|
|
||||||
|
dataSlice = append(dataSlice, &tapApi.EntryWrapper{
|
||||||
|
Protocol: entry.Protocol,
|
||||||
|
Data: entry,
|
||||||
|
Base: base,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
var metadata *basenine.Metadata
|
||||||
|
err = json.Unmarshal(meta, &metadata)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log.Debugf("Error recieving metadata: %v", err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
return dataSlice, metadata, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *BasenineEntriesProvider) GetEntry(singleEntryRequest *models.SingleEntryRequest, entryId int) (*tapApi.EntryWrapper, error) {
|
||||||
|
var entry *tapApi.Entry
|
||||||
|
bytes, err := basenine.Single(shared.BasenineHost, shared.BaseninePort, entryId, singleEntryRequest.Query)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
err = json.Unmarshal(bytes, &entry)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
extension := app.ExtensionsMap[entry.Protocol.Name]
|
||||||
|
base := extension.Dissector.Summarize(entry)
|
||||||
|
var representation []byte
|
||||||
|
representation, err = extension.Dissector.Represent(entry.Request, entry.Response)
|
||||||
|
if err != nil {
|
||||||
|
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{
|
||||||
|
Protocol: entry.Protocol,
|
||||||
|
Representation: string(representation),
|
||||||
|
Data: entry,
|
||||||
|
Base: base,
|
||||||
|
Rules: rules,
|
||||||
|
IsRulesEnabled: isRulesEnabled,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
@@ -67,23 +67,23 @@ func fileSize(fname string) int64 {
|
|||||||
return fi.Size()
|
return fi.Size()
|
||||||
}
|
}
|
||||||
|
|
||||||
func feedEntries(fromFiles []string, isSync bool) (count int, err error) {
|
func feedEntries(fromFiles []string, isSync bool, gen *defaultOasGenerator) (count uint, err error) {
|
||||||
badFiles := make([]string, 0)
|
badFiles := make([]string, 0)
|
||||||
cnt := 0
|
cnt := uint(0)
|
||||||
for _, file := range fromFiles {
|
for _, file := range fromFiles {
|
||||||
logger.Log.Info("Processing file: " + file)
|
logger.Log.Info("Processing file: " + file)
|
||||||
ext := strings.ToLower(filepath.Ext(file))
|
ext := strings.ToLower(filepath.Ext(file))
|
||||||
eCnt := 0
|
eCnt := uint(0)
|
||||||
switch ext {
|
switch ext {
|
||||||
case ".har":
|
case ".har":
|
||||||
eCnt, err = feedFromHAR(file, isSync)
|
eCnt, err = feedFromHAR(file, isSync, gen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Log.Warning("Failed processing file: " + err.Error())
|
logger.Log.Warning("Failed processing file: " + err.Error())
|
||||||
badFiles = append(badFiles, file)
|
badFiles = append(badFiles, file)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
case ".ldjson":
|
case ".ldjson":
|
||||||
eCnt, err = feedFromLDJSON(file, isSync)
|
eCnt, err = feedFromLDJSON(file, isSync, gen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Log.Warning("Failed processing file: " + err.Error())
|
logger.Log.Warning("Failed processing file: " + err.Error())
|
||||||
badFiles = append(badFiles, file)
|
badFiles = append(badFiles, file)
|
||||||
@@ -102,7 +102,7 @@ func feedEntries(fromFiles []string, isSync bool) (count int, err error) {
|
|||||||
return cnt, nil
|
return cnt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func feedFromHAR(file string, isSync bool) (int, error) {
|
func feedFromHAR(file string, isSync bool, gen *defaultOasGenerator) (uint, error) {
|
||||||
fd, err := os.Open(file)
|
fd, err := os.Open(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -121,16 +121,16 @@ func feedFromHAR(file string, isSync bool) (int, error) {
|
|||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
cnt := 0
|
cnt := uint(0)
|
||||||
for _, entry := range harDoc.Log.Entries {
|
for _, entry := range harDoc.Log.Entries {
|
||||||
cnt += 1
|
cnt += 1
|
||||||
feedEntry(&entry, "", isSync, file)
|
feedEntry(&entry, "", file, gen, cnt)
|
||||||
}
|
}
|
||||||
|
|
||||||
return cnt, nil
|
return cnt, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func feedEntry(entry *har.Entry, source string, isSync bool, file string) {
|
func feedEntry(entry *har.Entry, source string, file string, gen *defaultOasGenerator, cnt uint) {
|
||||||
entry.Comment = file
|
entry.Comment = file
|
||||||
if entry.Response.Status == 302 {
|
if entry.Response.Status == 302 {
|
||||||
logger.Log.Debugf("Dropped traffic entry due to permanent redirect status: %s", entry.StartedDateTime)
|
logger.Log.Debugf("Dropped traffic entry due to permanent redirect status: %s", entry.StartedDateTime)
|
||||||
@@ -145,15 +145,11 @@ func feedEntry(entry *har.Entry, source string, isSync bool, file string) {
|
|||||||
logger.Log.Errorf("Failed to parse entry URL: %v, err: %v", entry.Request.URL, err)
|
logger.Log.Errorf("Failed to parse entry URL: %v, err: %v", entry.Request.URL, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
ews := EntryWithSource{Entry: *entry, Source: source, Destination: u.Host, Id: uint(0)}
|
ews := EntryWithSource{Entry: *entry, Source: source, Destination: u.Host, Id: cnt}
|
||||||
if isSync {
|
gen.handleHARWithSource(&ews)
|
||||||
GetOasGeneratorInstance().entriesChan <- ews // blocking variant, right?
|
|
||||||
} else {
|
|
||||||
GetOasGeneratorInstance().PushEntry(&ews)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func feedFromLDJSON(file string, isSync bool) (int, error) {
|
func feedFromLDJSON(file string, isSync bool, gen *defaultOasGenerator) (uint, error) {
|
||||||
fd, err := os.Open(file)
|
fd, err := os.Open(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -165,7 +161,7 @@ func feedFromLDJSON(file string, isSync bool) (int, error) {
|
|||||||
|
|
||||||
var meta map[string]interface{}
|
var meta map[string]interface{}
|
||||||
buf := strings.Builder{}
|
buf := strings.Builder{}
|
||||||
cnt := 0
|
cnt := uint(0)
|
||||||
source := ""
|
source := ""
|
||||||
for {
|
for {
|
||||||
substr, isPrefix, err := reader.ReadLine()
|
substr, isPrefix, err := reader.ReadLine()
|
||||||
@@ -196,7 +192,7 @@ func feedFromLDJSON(file string, isSync bool) (int, error) {
|
|||||||
logger.Log.Warningf("Failed decoding entry: %s", line)
|
logger.Log.Warningf("Failed decoding entry: %s", line)
|
||||||
} else {
|
} else {
|
||||||
cnt += 1
|
cnt += 1
|
||||||
feedEntry(&entry, source, isSync, file)
|
feedEntry(&entry, source, file, gen, cnt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,40 +3,66 @@ package oas
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
basenine "github.com/up9inc/basenine/client/go"
|
||||||
|
"github.com/up9inc/mizu/agent/pkg/har"
|
||||||
|
"github.com/up9inc/mizu/shared"
|
||||||
|
"github.com/up9inc/mizu/tap/api"
|
||||||
"net/url"
|
"net/url"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"github.com/up9inc/mizu/agent/pkg/har"
|
|
||||||
"github.com/up9inc/mizu/shared/logger"
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
syncOnce sync.Once
|
syncOnce sync.Once
|
||||||
instance *oasGenerator
|
instance *defaultOasGenerator
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetOasGeneratorInstance() *oasGenerator {
|
type OasGenerator interface {
|
||||||
|
Start()
|
||||||
|
Stop()
|
||||||
|
IsStarted() bool
|
||||||
|
Reset()
|
||||||
|
GetServiceSpecs() *sync.Map
|
||||||
|
}
|
||||||
|
|
||||||
|
type defaultOasGenerator struct {
|
||||||
|
started bool
|
||||||
|
ctx context.Context
|
||||||
|
cancel context.CancelFunc
|
||||||
|
serviceSpecs *sync.Map
|
||||||
|
dbConn *basenine.Connection
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDefaultOasGeneratorInstance(conn *basenine.Connection) *defaultOasGenerator {
|
||||||
syncOnce.Do(func() {
|
syncOnce.Do(func() {
|
||||||
instance = newOasGenerator()
|
if conn == nil {
|
||||||
|
c, err := basenine.NewConnection(shared.BasenineHost, shared.BaseninePort)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
conn = c
|
||||||
|
}
|
||||||
|
|
||||||
|
instance = NewDefaultOasGenerator(conn)
|
||||||
logger.Log.Debug("OAS Generator Initialized")
|
logger.Log.Debug("OAS Generator Initialized")
|
||||||
})
|
})
|
||||||
return instance
|
return instance
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *oasGenerator) Start() {
|
func (g *defaultOasGenerator) Start() {
|
||||||
if g.started {
|
if g.started {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
g.cancel = cancel
|
g.cancel = cancel
|
||||||
g.ctx = ctx
|
g.ctx = ctx
|
||||||
g.entriesChan = make(chan EntryWithSource, 100) // buffer up to 100 entries for OAS processing
|
g.serviceSpecs = &sync.Map{}
|
||||||
g.ServiceSpecs = &sync.Map{}
|
|
||||||
g.started = true
|
g.started = true
|
||||||
go instance.runGenerator()
|
go g.runGenerator()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *oasGenerator) Stop() {
|
func (g *defaultOasGenerator) Stop() {
|
||||||
if !g.started {
|
if !g.started {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -45,89 +71,122 @@ func (g *oasGenerator) Stop() {
|
|||||||
g.started = false
|
g.started = false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *oasGenerator) IsStarted() bool {
|
func (g *defaultOasGenerator) IsStarted() bool {
|
||||||
return g.started
|
return g.started
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *oasGenerator) runGenerator() {
|
func (g *defaultOasGenerator) runGenerator() {
|
||||||
|
// Make []byte channels to recieve the data and the meta
|
||||||
|
dataChan := make(chan []byte)
|
||||||
|
metaChan := make(chan []byte)
|
||||||
|
|
||||||
|
g.dbConn.Query("", dataChan, metaChan)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-g.ctx.Done():
|
case <-g.ctx.Done():
|
||||||
logger.Log.Infof("OAS Generator was canceled")
|
logger.Log.Infof("OAS Generator was canceled")
|
||||||
return
|
return
|
||||||
|
|
||||||
case entryWithSource, ok := <-g.entriesChan:
|
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 {
|
if !ok {
|
||||||
logger.Log.Infof("OAS Generator - entries channel closed")
|
logger.Log.Infof("OAS Generator - entries channel closed")
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
entry := entryWithSource.Entry
|
|
||||||
u, err := url.Parse(entry.Request.URL)
|
logger.Log.Debugf("Data: %s", dataBytes)
|
||||||
|
e := new(api.Entry)
|
||||||
|
err := json.Unmarshal(dataBytes, e)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Log.Errorf("Failed to parse entry URL: %v, err: %v", entry.Request.URL, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
val, found := g.ServiceSpecs.Load(entryWithSource.Destination)
|
|
||||||
var gen *SpecGen
|
|
||||||
if !found {
|
|
||||||
gen = NewGen(u.Scheme + "://" + entryWithSource.Destination)
|
|
||||||
g.ServiceSpecs.Store(entryWithSource.Destination, gen)
|
|
||||||
} else {
|
|
||||||
gen = val.(*SpecGen)
|
|
||||||
}
|
|
||||||
|
|
||||||
opId, err := gen.feedEntry(entryWithSource)
|
|
||||||
if err != nil {
|
|
||||||
txt, suberr := json.Marshal(entry)
|
|
||||||
if suberr == nil {
|
|
||||||
logger.Log.Debugf("Problematic entry: %s", txt)
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Log.Warningf("Failed processing entry: %s", err)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
g.handleEntry(e)
|
||||||
logger.Log.Debugf("Handled entry %s as opId: %s", entry.Request.URL, opId) // TODO: set opId back to entry?
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *oasGenerator) Reset() {
|
func (g *defaultOasGenerator) handleEntry(mizuEntry *api.Entry) {
|
||||||
g.ServiceSpecs = &sync.Map{}
|
if mizuEntry.Protocol.Name == "http" {
|
||||||
|
entry, err := har.NewEntry(mizuEntry.Request, mizuEntry.Response, mizuEntry.StartTime, mizuEntry.ElapsedTime)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log.Warningf("Failed to turn MizuEntry %d into HAR Entry: %s", mizuEntry.Id, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dest := mizuEntry.Destination.Name
|
||||||
|
if dest == "" {
|
||||||
|
dest = mizuEntry.Destination.IP + ":" + mizuEntry.Destination.Port
|
||||||
|
}
|
||||||
|
|
||||||
|
entryWSource := &EntryWithSource{
|
||||||
|
Entry: *entry,
|
||||||
|
Source: mizuEntry.Source.Name,
|
||||||
|
Destination: dest,
|
||||||
|
Id: mizuEntry.Id,
|
||||||
|
}
|
||||||
|
|
||||||
|
g.handleHARWithSource(entryWSource)
|
||||||
|
} else {
|
||||||
|
logger.Log.Debugf("OAS: Unsupported protocol in entry %d: %s", mizuEntry.Id, mizuEntry.Protocol.Name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *oasGenerator) PushEntry(entryWithSource *EntryWithSource) {
|
func (g *defaultOasGenerator) handleHARWithSource(entryWSource *EntryWithSource) {
|
||||||
if !g.started {
|
entry := entryWSource.Entry
|
||||||
|
gen := g.getGen(entryWSource.Destination, entry.Request.URL)
|
||||||
|
|
||||||
|
opId, err := gen.feedEntry(entryWSource)
|
||||||
|
if err != nil {
|
||||||
|
txt, suberr := json.Marshal(entry)
|
||||||
|
if suberr == nil {
|
||||||
|
logger.Log.Debugf("Problematic entry: %s", txt)
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Log.Warningf("Failed processing entry %d: %s", entryWSource.Id, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
select {
|
|
||||||
case g.entriesChan <- *entryWithSource:
|
logger.Log.Debugf("Handled entry %d as opId: %s", entryWSource.Id, opId) // TODO: set opId back to entry?
|
||||||
default:
|
|
||||||
logger.Log.Warningf("OAS Generator - entry wasn't sent to channel because the channel has no buffer or there is no receiver")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func newOasGenerator() *oasGenerator {
|
func (g *defaultOasGenerator) getGen(dest string, urlStr string) *SpecGen {
|
||||||
return &oasGenerator{
|
u, err := url.Parse(urlStr)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log.Errorf("Failed to parse entry URL: %v, err: %v", urlStr, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
val, found := g.serviceSpecs.Load(dest)
|
||||||
|
var gen *SpecGen
|
||||||
|
if !found {
|
||||||
|
gen = NewGen(u.Scheme + "://" + dest)
|
||||||
|
g.serviceSpecs.Store(dest, gen)
|
||||||
|
} else {
|
||||||
|
gen = val.(*SpecGen)
|
||||||
|
}
|
||||||
|
return gen
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *defaultOasGenerator) Reset() {
|
||||||
|
g.serviceSpecs = &sync.Map{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (g *defaultOasGenerator) GetServiceSpecs() *sync.Map {
|
||||||
|
return g.serviceSpecs
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewDefaultOasGenerator(c *basenine.Connection) *defaultOasGenerator {
|
||||||
|
return &defaultOasGenerator{
|
||||||
started: false,
|
started: false,
|
||||||
ctx: nil,
|
ctx: nil,
|
||||||
cancel: nil,
|
cancel: nil,
|
||||||
ServiceSpecs: nil,
|
serviceSpecs: nil,
|
||||||
entriesChan: nil,
|
dbConn: c,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type EntryWithSource struct {
|
|
||||||
Source string
|
|
||||||
Destination string
|
|
||||||
Entry har.Entry
|
|
||||||
Id uint
|
|
||||||
}
|
|
||||||
|
|
||||||
type oasGenerator struct {
|
|
||||||
started bool
|
|
||||||
ctx context.Context
|
|
||||||
cancel context.CancelFunc
|
|
||||||
ServiceSpecs *sync.Map
|
|
||||||
entriesChan chan EntryWithSource
|
|
||||||
}
|
|
||||||
|
|||||||
36
agent/pkg/oas/oas_generator_test.go
Normal file
36
agent/pkg/oas/oas_generator_test.go
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package oas
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"github.com/up9inc/mizu/agent/pkg/har"
|
||||||
|
"sync"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestOASGen(t *testing.T) {
|
||||||
|
gen := new(defaultOasGenerator)
|
||||||
|
gen.serviceSpecs = &sync.Map{}
|
||||||
|
|
||||||
|
e := new(har.Entry)
|
||||||
|
err := json.Unmarshal([]byte(`{"startedDateTime": "20000101","request": {"url": "https://host/path", "method": "GET"}, "response": {"status": 200}}`), e)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ews := &EntryWithSource{
|
||||||
|
Destination: "some",
|
||||||
|
Entry: *e,
|
||||||
|
}
|
||||||
|
gen.handleHARWithSource(ews)
|
||||||
|
g, ok := gen.serviceSpecs.Load("some")
|
||||||
|
if !ok {
|
||||||
|
panic("Failed")
|
||||||
|
}
|
||||||
|
sg := g.(*SpecGen)
|
||||||
|
spec, err := sg.GetSpec()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
specText, _ := json.Marshal(spec)
|
||||||
|
t.Log(string(specText))
|
||||||
|
}
|
||||||
@@ -28,6 +28,13 @@ const CountersTotal = "x-counters-total"
|
|||||||
const CountersPerSource = "x-counters-per-source"
|
const CountersPerSource = "x-counters-per-source"
|
||||||
const SampleId = "x-sample-entry"
|
const SampleId = "x-sample-entry"
|
||||||
|
|
||||||
|
type EntryWithSource struct {
|
||||||
|
Source string
|
||||||
|
Destination string
|
||||||
|
Entry har.Entry
|
||||||
|
Id uint
|
||||||
|
}
|
||||||
|
|
||||||
type reqResp struct { // hello, generics in Go
|
type reqResp struct { // hello, generics in Go
|
||||||
Req *har.Request
|
Req *har.Request
|
||||||
Resp *har.Response
|
Resp *har.Response
|
||||||
@@ -60,7 +67,7 @@ func (g *SpecGen) StartFromSpec(oas *openapi.OpenAPI) {
|
|||||||
g.tree = new(Node)
|
g.tree = new(Node)
|
||||||
for pathStr, pathObj := range oas.Paths.Items {
|
for pathStr, pathObj := range oas.Paths.Items {
|
||||||
pathSplit := strings.Split(string(pathStr), "/")
|
pathSplit := strings.Split(string(pathStr), "/")
|
||||||
g.tree.getOrSet(pathSplit, pathObj)
|
g.tree.getOrSet(pathSplit, pathObj, 0)
|
||||||
|
|
||||||
// clean "last entry timestamp" markers from the past
|
// clean "last entry timestamp" markers from the past
|
||||||
for _, pathAndOp := range g.tree.listOps() {
|
for _, pathAndOp := range g.tree.listOps() {
|
||||||
@@ -69,11 +76,11 @@ func (g *SpecGen) StartFromSpec(oas *openapi.OpenAPI) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *SpecGen) feedEntry(entryWithSource EntryWithSource) (string, error) {
|
func (g *SpecGen) feedEntry(entryWithSource *EntryWithSource) (string, error) {
|
||||||
g.lock.Lock()
|
g.lock.Lock()
|
||||||
defer g.lock.Unlock()
|
defer g.lock.Unlock()
|
||||||
|
|
||||||
opId, err := g.handlePathObj(&entryWithSource)
|
opId, err := g.handlePathObj(entryWithSource)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
@@ -219,7 +226,7 @@ func (g *SpecGen) handlePathObj(entryWithSource *EntryWithSource) (string, error
|
|||||||
} else {
|
} else {
|
||||||
split = strings.Split(urlParsed.Path, "/")
|
split = strings.Split(urlParsed.Path, "/")
|
||||||
}
|
}
|
||||||
node := g.tree.getOrSet(split, new(openapi.PathObj))
|
node := g.tree.getOrSet(split, new(openapi.PathObj), entryWithSource.Id)
|
||||||
opObj, err := handleOpObj(entryWithSource, node.pathObj)
|
opObj, err := handleOpObj(entryWithSource, node.pathObj)
|
||||||
|
|
||||||
if opObj != nil {
|
if opObj != nil {
|
||||||
@@ -242,12 +249,12 @@ func handleOpObj(entryWithSource *EntryWithSource, pathObj *openapi.PathObj) (*o
|
|||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
err = handleRequest(&entry.Request, opObj, isSuccess)
|
err = handleRequest(&entry.Request, opObj, isSuccess, entryWithSource.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = handleResponse(&entry.Response, opObj, isSuccess)
|
err = handleResponse(&entry.Response, opObj, isSuccess, entryWithSource.Id)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -257,6 +264,8 @@ func handleOpObj(entryWithSource *EntryWithSource, pathObj *openapi.PathObj) (*o
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setSampleID(&opObj.Extensions, entryWithSource.Id)
|
||||||
|
|
||||||
return opObj, nil
|
return opObj, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,15 +338,10 @@ func handleCounters(opObj *openapi.Operation, success bool, entryWithSource *Ent
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = opObj.Extensions.SetExtension(SampleId, entryWithSource.Id)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleRequest(req *har.Request, opObj *openapi.Operation, isSuccess bool) error {
|
func handleRequest(req *har.Request, opObj *openapi.Operation, isSuccess bool, sampleId uint) 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 {
|
||||||
@@ -361,7 +365,7 @@ func handleRequest(req *har.Request, opObj *openapi.Operation, isSuccess bool) e
|
|||||||
IsIgnored: func(name string) bool { return false },
|
IsIgnored: func(name string) bool { return false },
|
||||||
GeneralizeName: func(name string) string { return name },
|
GeneralizeName: func(name string) string { return name },
|
||||||
}
|
}
|
||||||
handleNameVals(qstrGW, &opObj.Parameters, false)
|
handleNameVals(qstrGW, &opObj.Parameters, false, sampleId)
|
||||||
|
|
||||||
hdrGW := nvParams{
|
hdrGW := nvParams{
|
||||||
In: openapi.InHeader,
|
In: openapi.InHeader,
|
||||||
@@ -369,7 +373,7 @@ func handleRequest(req *har.Request, opObj *openapi.Operation, isSuccess bool) e
|
|||||||
IsIgnored: isHeaderIgnored,
|
IsIgnored: isHeaderIgnored,
|
||||||
GeneralizeName: strings.ToLower,
|
GeneralizeName: strings.ToLower,
|
||||||
}
|
}
|
||||||
handleNameVals(hdrGW, &opObj.Parameters, true)
|
handleNameVals(hdrGW, &opObj.Parameters, true, sampleId)
|
||||||
|
|
||||||
if isSuccess {
|
if isSuccess {
|
||||||
reqBody, err := getRequestBody(req, opObj)
|
reqBody, err := getRequestBody(req, opObj)
|
||||||
@@ -378,12 +382,14 @@ func handleRequest(req *har.Request, opObj *openapi.Operation, isSuccess bool) e
|
|||||||
}
|
}
|
||||||
|
|
||||||
if reqBody != nil {
|
if reqBody != nil {
|
||||||
|
setSampleID(&reqBody.Extensions, sampleId)
|
||||||
|
|
||||||
if req.PostData.Text == "" {
|
if req.PostData.Text == "" {
|
||||||
reqBody.Required = false
|
reqBody.Required = false
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
reqCtype, _ := getReqCtype(req)
|
reqCtype, _ := getReqCtype(req)
|
||||||
reqMedia, err := fillContent(reqResp{Req: req}, reqBody.Content, reqCtype)
|
reqMedia, err := fillContent(reqResp{Req: req}, reqBody.Content, reqCtype, sampleId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -395,18 +401,20 @@ func handleRequest(req *har.Request, opObj *openapi.Operation, isSuccess bool) e
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleResponse(resp *har.Response, opObj *openapi.Operation, isSuccess bool) error {
|
func handleResponse(resp *har.Response, opObj *openapi.Operation, isSuccess bool, sampleId uint) 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 {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
handleRespHeaders(resp.Headers, respObj)
|
setSampleID(&respObj.Extensions, sampleId)
|
||||||
|
|
||||||
|
handleRespHeaders(resp.Headers, respObj, sampleId)
|
||||||
|
|
||||||
respCtype := getRespCtype(resp)
|
respCtype := getRespCtype(resp)
|
||||||
respContent := respObj.Content
|
respContent := respObj.Content
|
||||||
respMedia, err := fillContent(reqResp{Resp: resp}, respContent, respCtype)
|
respMedia, err := fillContent(reqResp{Resp: resp}, respContent, respCtype, sampleId)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -414,7 +422,7 @@ func handleResponse(resp *har.Response, opObj *openapi.Operation, isSuccess bool
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleRespHeaders(reqHeaders []har.Header, respObj *openapi.ResponseObj) {
|
func handleRespHeaders(reqHeaders []har.Header, respObj *openapi.ResponseObj, sampleId uint) {
|
||||||
visited := map[string]*openapi.HeaderObj{}
|
visited := map[string]*openapi.HeaderObj{}
|
||||||
for _, pair := range reqHeaders {
|
for _, pair := range reqHeaders {
|
||||||
if isHeaderIgnored(pair.Name) {
|
if isHeaderIgnored(pair.Name) {
|
||||||
@@ -436,6 +444,8 @@ func handleRespHeaders(reqHeaders []har.Header, respObj *openapi.ResponseObj) {
|
|||||||
logger.Log.Warningf("Failed to add example to a parameter: %s", err)
|
logger.Log.Warningf("Failed to add example to a parameter: %s", err)
|
||||||
}
|
}
|
||||||
visited[nameGeneral] = param
|
visited[nameGeneral] = param
|
||||||
|
|
||||||
|
setSampleID(¶m.Extensions, sampleId)
|
||||||
}
|
}
|
||||||
|
|
||||||
// maintain "required" flag
|
// maintain "required" flag
|
||||||
@@ -456,13 +466,15 @@ func handleRespHeaders(reqHeaders []har.Header, respObj *openapi.ResponseObj) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fillContent(reqResp reqResp, respContent openapi.Content, ctype string) (*openapi.MediaType, error) {
|
func fillContent(reqResp reqResp, respContent openapi.Content, ctype string, sampleId uint) (*openapi.MediaType, error) {
|
||||||
content, found := respContent[ctype]
|
content, found := respContent[ctype]
|
||||||
if !found {
|
if !found {
|
||||||
respContent[ctype] = &openapi.MediaType{}
|
respContent[ctype] = &openapi.MediaType{}
|
||||||
content = respContent[ctype]
|
content = respContent[ctype]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setSampleID(&content.Extensions, sampleId)
|
||||||
|
|
||||||
var text string
|
var text string
|
||||||
var isBinary bool
|
var isBinary bool
|
||||||
if reqResp.Req != nil {
|
if reqResp.Req != nil {
|
||||||
@@ -474,10 +486,10 @@ func fillContent(reqResp reqResp, respContent openapi.Content, ctype string) (*o
|
|||||||
if !isBinary && text != "" {
|
if !isBinary && text != "" {
|
||||||
var exampleMsg []byte
|
var exampleMsg []byte
|
||||||
// try treating it as json
|
// try treating it as json
|
||||||
any, isJSON := anyJSON(text)
|
anyVal, isJSON := anyJSON(text)
|
||||||
if isJSON {
|
if isJSON {
|
||||||
// re-marshal with forced indent
|
// re-marshal with forced indent
|
||||||
if msg, err := json.MarshalIndent(any, "", "\t"); err != nil {
|
if msg, err := json.MarshalIndent(anyVal, "", "\t"); err != nil {
|
||||||
panic("Failed to re-marshal value, super-strange")
|
panic("Failed to re-marshal value, super-strange")
|
||||||
} else {
|
} else {
|
||||||
exampleMsg = msg
|
exampleMsg = msg
|
||||||
|
|||||||
@@ -2,23 +2,25 @@ package oas
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"github.com/chanced/openapi"
|
|
||||||
"github.com/op/go-logging"
|
|
||||||
"github.com/up9inc/mizu/shared/logger"
|
|
||||||
"github.com/wI2L/jsondiff"
|
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"os"
|
"os"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/chanced/openapi"
|
||||||
|
"github.com/op/go-logging"
|
||||||
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
|
"github.com/wI2L/jsondiff"
|
||||||
|
|
||||||
"github.com/up9inc/mizu/agent/pkg/har"
|
"github.com/up9inc/mizu/agent/pkg/har"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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, "", "\t")
|
content, err := json.MarshalIndent(spec, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -47,14 +49,16 @@ func TestEntries(t *testing.T) {
|
|||||||
t.Log(err)
|
t.Log(err)
|
||||||
t.FailNow()
|
t.FailNow()
|
||||||
}
|
}
|
||||||
GetOasGeneratorInstance().Start()
|
|
||||||
loadStartingOAS("test_artifacts/catalogue.json", "catalogue")
|
gen := NewDefaultOasGenerator(nil)
|
||||||
loadStartingOAS("test_artifacts/trcc.json", "trcc-api-service")
|
gen.serviceSpecs = new(sync.Map)
|
||||||
|
loadStartingOAS("test_artifacts/catalogue.json", "catalogue", gen.serviceSpecs)
|
||||||
|
loadStartingOAS("test_artifacts/trcc.json", "trcc-api-service", gen.serviceSpecs)
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
for {
|
for {
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
GetOasGeneratorInstance().ServiceSpecs.Range(func(key, val interface{}) bool {
|
gen.serviceSpecs.Range(func(key, val interface{}) bool {
|
||||||
svc := key.(string)
|
svc := key.(string)
|
||||||
t.Logf("Getting spec for %s", svc)
|
t.Logf("Getting spec for %s", svc)
|
||||||
gen := val.(*SpecGen)
|
gen := val.(*SpecGen)
|
||||||
@@ -67,16 +71,14 @@ func TestEntries(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
cnt, err := feedEntries(files, true)
|
cnt, err := feedEntries(files, true, gen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Log(err)
|
t.Log(err)
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
|
|
||||||
waitQueueProcessed()
|
|
||||||
|
|
||||||
svcs := strings.Builder{}
|
svcs := strings.Builder{}
|
||||||
GetOasGeneratorInstance().ServiceSpecs.Range(func(key, val interface{}) bool {
|
gen.serviceSpecs.Range(func(key, val interface{}) bool {
|
||||||
gen := val.(*SpecGen)
|
gen := val.(*SpecGen)
|
||||||
svc := key.(string)
|
svc := key.(string)
|
||||||
svcs.WriteString(svc + ",")
|
svcs.WriteString(svc + ",")
|
||||||
@@ -98,7 +100,7 @@ func TestEntries(t *testing.T) {
|
|||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
|
||||||
GetOasGeneratorInstance().ServiceSpecs.Range(func(key, val interface{}) bool {
|
gen.serviceSpecs.Range(func(key, val interface{}) bool {
|
||||||
svc := key.(string)
|
svc := key.(string)
|
||||||
gen := val.(*SpecGen)
|
gen := val.(*SpecGen)
|
||||||
spec, err := gen.GetSpec()
|
spec, err := gen.GetSpec()
|
||||||
@@ -122,20 +124,18 @@ func TestEntries(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestFileSingle(t *testing.T) {
|
func TestFileSingle(t *testing.T) {
|
||||||
GetOasGeneratorInstance().Start()
|
gen := NewDefaultOasGenerator(nil)
|
||||||
GetOasGeneratorInstance().Reset()
|
gen.serviceSpecs = new(sync.Map)
|
||||||
// loadStartingOAS()
|
// loadStartingOAS()
|
||||||
file := "test_artifacts/params.har"
|
file := "test_artifacts/params.har"
|
||||||
files := []string{file}
|
files := []string{file}
|
||||||
cnt, err := feedEntries(files, true)
|
cnt, err := feedEntries(files, true, gen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
logger.Log.Warning("Failed processing file: " + err.Error())
|
logger.Log.Warning("Failed processing file: " + err.Error())
|
||||||
t.Fail()
|
t.Fail()
|
||||||
}
|
}
|
||||||
|
|
||||||
waitQueueProcessed()
|
gen.serviceSpecs.Range(func(key, val interface{}) bool {
|
||||||
|
|
||||||
GetOasGeneratorInstance().ServiceSpecs.Range(func(key, val interface{}) bool {
|
|
||||||
svc := key.(string)
|
svc := key.(string)
|
||||||
gen := val.(*SpecGen)
|
gen := val.(*SpecGen)
|
||||||
spec, err := gen.GetSpec()
|
spec, err := gen.GetSpec()
|
||||||
@@ -188,18 +188,7 @@ func TestFileSingle(t *testing.T) {
|
|||||||
logger.Log.Infof("Processed entries: %d", cnt)
|
logger.Log.Infof("Processed entries: %d", cnt)
|
||||||
}
|
}
|
||||||
|
|
||||||
func waitQueueProcessed() {
|
func loadStartingOAS(file string, label string, specs *sync.Map) {
|
||||||
for {
|
|
||||||
time.Sleep(100 * time.Millisecond)
|
|
||||||
queue := len(GetOasGeneratorInstance().entriesChan)
|
|
||||||
logger.Log.Infof("Queue: %d", queue)
|
|
||||||
if queue < 1 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func loadStartingOAS(file string, label string) {
|
|
||||||
fd, err := os.Open(file)
|
fd, err := os.Open(file)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
@@ -221,12 +210,14 @@ func loadStartingOAS(file string, label string) {
|
|||||||
gen := NewGen(label)
|
gen := NewGen(label)
|
||||||
gen.StartFromSpec(doc)
|
gen.StartFromSpec(doc)
|
||||||
|
|
||||||
GetOasGeneratorInstance().ServiceSpecs.Store(label, gen)
|
specs.Store(label, gen)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestEntriesNegative(t *testing.T) {
|
func TestEntriesNegative(t *testing.T) {
|
||||||
|
gen := NewDefaultOasGenerator(nil)
|
||||||
|
gen.serviceSpecs = new(sync.Map)
|
||||||
files := []string{"invalid"}
|
files := []string{"invalid"}
|
||||||
_, err := feedEntries(files, false)
|
_, err := feedEntries(files, false, gen)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
t.Logf("Should have failed")
|
t.Logf("Should have failed")
|
||||||
t.Fail()
|
t.Fail()
|
||||||
@@ -234,8 +225,10 @@ func TestEntriesNegative(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestEntriesPositive(t *testing.T) {
|
func TestEntriesPositive(t *testing.T) {
|
||||||
|
gen := NewDefaultOasGenerator(nil)
|
||||||
|
gen.serviceSpecs = new(sync.Map)
|
||||||
files := []string{"test_artifacts/params.har"}
|
files := []string{"test_artifacts/params.har"}
|
||||||
_, err := feedEntries(files, false)
|
_, err := feedEntries(files, false, gen)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Logf("Failed")
|
t.Logf("Failed")
|
||||||
t.Fail()
|
t.Fail()
|
||||||
|
|||||||
@@ -21,9 +21,11 @@
|
|||||||
"description": "Successful call with status 200",
|
"description": "Successful call with status 200",
|
||||||
"content": {
|
"content": {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
"example": null
|
"example": null,
|
||||||
|
"x-sample-entry": 4
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"x-sample-entry": 4
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"x-counters-per-source": {
|
"x-counters-per-source": {
|
||||||
@@ -45,7 +47,7 @@
|
|||||||
"sumDuration": 0
|
"sumDuration": 0
|
||||||
},
|
},
|
||||||
"x-last-seen-ts": 1567750580.04,
|
"x-last-seen-ts": 1567750580.04,
|
||||||
"x-sample-entry": 0
|
"x-sample-entry": 4
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/appears-twice": {
|
"/appears-twice": {
|
||||||
@@ -58,9 +60,11 @@
|
|||||||
"description": "Successful call with status 200",
|
"description": "Successful call with status 200",
|
||||||
"content": {
|
"content": {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
"example": null
|
"example": null,
|
||||||
|
"x-sample-entry": 6
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"x-sample-entry": 6
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"x-counters-per-source": {
|
"x-counters-per-source": {
|
||||||
@@ -82,7 +86,7 @@
|
|||||||
"sumDuration": 1
|
"sumDuration": 1
|
||||||
},
|
},
|
||||||
"x-last-seen-ts": 1567750581.74,
|
"x-last-seen-ts": 1567750581.74,
|
||||||
"x-sample-entry": 0
|
"x-sample-entry": 6
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"/body-optional": {
|
"/body-optional": {
|
||||||
@@ -94,8 +98,11 @@
|
|||||||
"200": {
|
"200": {
|
||||||
"description": "Successful call with status 200",
|
"description": "Successful call with status 200",
|
||||||
"content": {
|
"content": {
|
||||||
"": {}
|
"": {
|
||||||
}
|
"x-sample-entry": 12
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-sample-entry": 12
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"x-counters-per-source": {
|
"x-counters-per-source": {
|
||||||
@@ -117,14 +124,16 @@
|
|||||||
"sumDuration": 0.01
|
"sumDuration": 0.01
|
||||||
},
|
},
|
||||||
"x-last-seen-ts": 1567750581.75,
|
"x-last-seen-ts": 1567750581.75,
|
||||||
"x-sample-entry": 0,
|
"x-sample-entry": 12,
|
||||||
"requestBody": {
|
"requestBody": {
|
||||||
"description": "Generic request body",
|
"description": "Generic request body",
|
||||||
"content": {
|
"content": {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
"example": "{\"key\", \"val\"}"
|
"example": "{\"key\", \"val\"}",
|
||||||
|
"x-sample-entry": 11
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"x-sample-entry": 12
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -137,8 +146,11 @@
|
|||||||
"200": {
|
"200": {
|
||||||
"description": "Successful call with status 200",
|
"description": "Successful call with status 200",
|
||||||
"content": {
|
"content": {
|
||||||
"": {}
|
"": {
|
||||||
}
|
"x-sample-entry": 13
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-sample-entry": 13
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"x-counters-per-source": {
|
"x-counters-per-source": {
|
||||||
@@ -160,15 +172,17 @@
|
|||||||
"sumDuration": 0
|
"sumDuration": 0
|
||||||
},
|
},
|
||||||
"x-last-seen-ts": 1567750581.75,
|
"x-last-seen-ts": 1567750581.75,
|
||||||
"x-sample-entry": 0,
|
"x-sample-entry": 13,
|
||||||
"requestBody": {
|
"requestBody": {
|
||||||
"description": "Generic request body",
|
"description": "Generic request body",
|
||||||
"content": {
|
"content": {
|
||||||
"": {
|
"": {
|
||||||
"example": "body exists"
|
"example": "body exists",
|
||||||
|
"x-sample-entry": 13
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": true
|
"required": true,
|
||||||
|
"x-sample-entry": 13
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -182,9 +196,11 @@
|
|||||||
"description": "Successful call with status 200",
|
"description": "Successful call with status 200",
|
||||||
"content": {
|
"content": {
|
||||||
"": {
|
"": {
|
||||||
"example": {}
|
"example": {},
|
||||||
|
"x-sample-entry": 9
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"x-sample-entry": 9
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"x-counters-per-source": {
|
"x-counters-per-source": {
|
||||||
@@ -206,7 +222,7 @@
|
|||||||
"sumDuration": 0
|
"sumDuration": 0
|
||||||
},
|
},
|
||||||
"x-last-seen-ts": 1567750582.74,
|
"x-last-seen-ts": 1567750582.74,
|
||||||
"x-sample-entry": 0,
|
"x-sample-entry": 9,
|
||||||
"requestBody": {
|
"requestBody": {
|
||||||
"description": "Generic request body",
|
"description": "Generic request body",
|
||||||
"content": {
|
"content": {
|
||||||
@@ -233,10 +249,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"example": "--BOUNDARY\r\nContent-Disposition: form-data; name=\"file\"; filename=\"metadata.json\"\r\nContent-Type: application/json\r\n\r\n{\"functions\": 123}\r\n--BOUNDARY\r\nContent-Disposition: form-data; name=\"path\"\r\n\r\n/content/components\r\n--BOUNDARY--\r\n"
|
"example": "--BOUNDARY\r\nContent-Disposition: form-data; name=\"file\"; filename=\"metadata.json\"\r\nContent-Type: application/json\r\n\r\n{\"functions\": 123}\r\n--BOUNDARY\r\nContent-Disposition: form-data; name=\"path\"\r\n\r\n/content/components\r\n--BOUNDARY--\r\n",
|
||||||
|
"x-sample-entry": 9
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": true
|
"required": true,
|
||||||
|
"x-sample-entry": 9
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -249,8 +267,11 @@
|
|||||||
"200": {
|
"200": {
|
||||||
"description": "Successful call with status 200",
|
"description": "Successful call with status 200",
|
||||||
"content": {
|
"content": {
|
||||||
"": {}
|
"": {
|
||||||
}
|
"x-sample-entry": 8
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-sample-entry": 8
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"x-counters-per-source": {
|
"x-counters-per-source": {
|
||||||
@@ -272,7 +293,7 @@
|
|||||||
"sumDuration": 1
|
"sumDuration": 1
|
||||||
},
|
},
|
||||||
"x-last-seen-ts": 1567750581.74,
|
"x-last-seen-ts": 1567750581.74,
|
||||||
"x-sample-entry": 0,
|
"x-sample-entry": 8,
|
||||||
"requestBody": {
|
"requestBody": {
|
||||||
"description": "Generic request body",
|
"description": "Generic request body",
|
||||||
"content": {
|
"content": {
|
||||||
@@ -312,10 +333,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"example": "agent-id=ade\u0026callback-url=\u0026token=sometoken"
|
"example": "agent-id=ade\u0026callback-url=\u0026token=sometoken",
|
||||||
|
"x-sample-entry": 8
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": true
|
"required": true,
|
||||||
|
"x-sample-entry": 8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -331,8 +354,11 @@
|
|||||||
"200": {
|
"200": {
|
||||||
"description": "Successful call with status 200",
|
"description": "Successful call with status 200",
|
||||||
"content": {
|
"content": {
|
||||||
"": {}
|
"": {
|
||||||
}
|
"x-sample-entry": 14
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-sample-entry": 14
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"x-counters-per-source": {
|
"x-counters-per-source": {
|
||||||
@@ -354,7 +380,7 @@
|
|||||||
"sumDuration": 0
|
"sumDuration": 0
|
||||||
},
|
},
|
||||||
"x-last-seen-ts": 1567750582,
|
"x-last-seen-ts": 1567750582,
|
||||||
"x-sample-entry": 0
|
"x-sample-entry": 14
|
||||||
},
|
},
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
@@ -369,7 +395,8 @@
|
|||||||
"example #0": {
|
"example #0": {
|
||||||
"value": "234324"
|
"value": "234324"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"x-sample-entry": 14
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -385,8 +412,11 @@
|
|||||||
"200": {
|
"200": {
|
||||||
"description": "Successful call with status 200",
|
"description": "Successful call with status 200",
|
||||||
"content": {
|
"content": {
|
||||||
"": {}
|
"": {
|
||||||
}
|
"x-sample-entry": 18
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-sample-entry": 18
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"x-counters-per-source": {
|
"x-counters-per-source": {
|
||||||
@@ -408,7 +438,7 @@
|
|||||||
"sumDuration": 9.53e-7
|
"sumDuration": 9.53e-7
|
||||||
},
|
},
|
||||||
"x-last-seen-ts": 1567750582.00,
|
"x-last-seen-ts": 1567750582.00,
|
||||||
"x-sample-entry": 0
|
"x-sample-entry": 18
|
||||||
},
|
},
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
@@ -436,7 +466,8 @@
|
|||||||
"example #4": {
|
"example #4": {
|
||||||
"value": "prefix-gibberish-afterwards"
|
"value": "prefix-gibberish-afterwards"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"x-sample-entry": 19
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -452,8 +483,11 @@
|
|||||||
"200": {
|
"200": {
|
||||||
"description": "Successful call with status 200",
|
"description": "Successful call with status 200",
|
||||||
"content": {
|
"content": {
|
||||||
"": {}
|
"": {
|
||||||
}
|
"x-sample-entry": 15
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-sample-entry": 15
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"x-counters-per-source": {
|
"x-counters-per-source": {
|
||||||
@@ -475,7 +509,7 @@
|
|||||||
"sumDuration": 0
|
"sumDuration": 0
|
||||||
},
|
},
|
||||||
"x-last-seen-ts": 1567750582.00,
|
"x-last-seen-ts": 1567750582.00,
|
||||||
"x-sample-entry": 0
|
"x-sample-entry": 15
|
||||||
},
|
},
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
@@ -503,7 +537,8 @@
|
|||||||
"example #4": {
|
"example #4": {
|
||||||
"value": "prefix-gibberish-afterwards"
|
"value": "prefix-gibberish-afterwards"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"x-sample-entry": 19
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -519,8 +554,11 @@
|
|||||||
"200": {
|
"200": {
|
||||||
"description": "Successful call with status 200",
|
"description": "Successful call with status 200",
|
||||||
"content": {
|
"content": {
|
||||||
"": {}
|
"": {
|
||||||
}
|
"x-sample-entry": 16
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-sample-entry": 16
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"x-counters-per-source": {
|
"x-counters-per-source": {
|
||||||
@@ -542,7 +580,7 @@
|
|||||||
"sumDuration": 0
|
"sumDuration": 0
|
||||||
},
|
},
|
||||||
"x-last-seen-ts": 1567750582.00,
|
"x-last-seen-ts": 1567750582.00,
|
||||||
"x-sample-entry": 0
|
"x-sample-entry": 16
|
||||||
},
|
},
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
@@ -570,7 +608,8 @@
|
|||||||
"example #4": {
|
"example #4": {
|
||||||
"value": "prefix-gibberish-afterwards"
|
"value": "prefix-gibberish-afterwards"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"x-sample-entry": 19
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -586,8 +625,11 @@
|
|||||||
"200": {
|
"200": {
|
||||||
"description": "Successful call with status 200",
|
"description": "Successful call with status 200",
|
||||||
"content": {
|
"content": {
|
||||||
"": {}
|
"": {
|
||||||
}
|
"x-sample-entry": 19
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-sample-entry": 19
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"x-counters-per-source": {
|
"x-counters-per-source": {
|
||||||
@@ -609,7 +651,7 @@
|
|||||||
"sumDuration": 0
|
"sumDuration": 0
|
||||||
},
|
},
|
||||||
"x-last-seen-ts": 1567750582.00,
|
"x-last-seen-ts": 1567750582.00,
|
||||||
"x-sample-entry": 0
|
"x-sample-entry": 19
|
||||||
},
|
},
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
@@ -624,7 +666,8 @@
|
|||||||
"example #0": {
|
"example #0": {
|
||||||
"value": "23421"
|
"value": "23421"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"x-sample-entry": 19
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "parampatternId",
|
"name": "parampatternId",
|
||||||
@@ -651,7 +694,8 @@
|
|||||||
"example #4": {
|
"example #4": {
|
||||||
"value": "prefix-gibberish-afterwards"
|
"value": "prefix-gibberish-afterwards"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"x-sample-entry": 19
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -665,9 +709,11 @@
|
|||||||
"description": "Successful call with status 200",
|
"description": "Successful call with status 200",
|
||||||
"content": {
|
"content": {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
"example": null
|
"example": null,
|
||||||
|
"x-sample-entry": 3
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"x-sample-entry": 3
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"x-counters-per-source": {
|
"x-counters-per-source": {
|
||||||
@@ -689,7 +735,7 @@
|
|||||||
"sumDuration": 0
|
"sumDuration": 0
|
||||||
},
|
},
|
||||||
"x-last-seen-ts": 1567750579.74,
|
"x-last-seen-ts": 1567750579.74,
|
||||||
"x-sample-entry": 0
|
"x-sample-entry": 3
|
||||||
},
|
},
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
@@ -707,7 +753,8 @@
|
|||||||
"example #1": {
|
"example #1": {
|
||||||
"value": "<UUID4>"
|
"value": "<UUID4>"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"x-sample-entry": 3
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -720,8 +767,11 @@
|
|||||||
"200": {
|
"200": {
|
||||||
"description": "Successful call with status 200",
|
"description": "Successful call with status 200",
|
||||||
"content": {
|
"content": {
|
||||||
"text/html": {}
|
"text/html": {
|
||||||
}
|
"x-sample-entry": 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"x-sample-entry": 1
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"x-counters-per-source": {
|
"x-counters-per-source": {
|
||||||
@@ -743,7 +793,7 @@
|
|||||||
"sumDuration": 0
|
"sumDuration": 0
|
||||||
},
|
},
|
||||||
"x-last-seen-ts": 1567750483.86,
|
"x-last-seen-ts": 1567750483.86,
|
||||||
"x-sample-entry": 0
|
"x-sample-entry": 1
|
||||||
},
|
},
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
@@ -761,7 +811,8 @@
|
|||||||
"example #1": {
|
"example #1": {
|
||||||
"value": "<UUID4>"
|
"value": "<UUID4>"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"x-sample-entry": 3
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -775,9 +826,11 @@
|
|||||||
"description": "Successful call with status 200",
|
"description": "Successful call with status 200",
|
||||||
"content": {
|
"content": {
|
||||||
"application/json": {
|
"application/json": {
|
||||||
"example": null
|
"example": null,
|
||||||
|
"x-sample-entry": 2
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"x-sample-entry": 2
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"x-counters-per-source": {
|
"x-counters-per-source": {
|
||||||
@@ -799,7 +852,7 @@
|
|||||||
"sumDuration": 0
|
"sumDuration": 0
|
||||||
},
|
},
|
||||||
"x-last-seen-ts": 1567750578.74,
|
"x-last-seen-ts": 1567750578.74,
|
||||||
"x-sample-entry": 0
|
"x-sample-entry": 2
|
||||||
},
|
},
|
||||||
"parameters": [
|
"parameters": [
|
||||||
{
|
{
|
||||||
@@ -817,7 +870,8 @@
|
|||||||
"example #1": {
|
"example #1": {
|
||||||
"value": "<UUID4>"
|
"value": "<UUID4>"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"x-sample-entry": 3
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ type Node struct {
|
|||||||
children []*Node
|
children []*Node
|
||||||
}
|
}
|
||||||
|
|
||||||
func (n *Node) getOrSet(path NodePath, existingPathObj *openapi.PathObj) (node *Node) {
|
func (n *Node) getOrSet(path NodePath, existingPathObj *openapi.PathObj, sampleId uint) (node *Node) {
|
||||||
if existingPathObj == nil {
|
if existingPathObj == nil {
|
||||||
panic("Invalid function call")
|
panic("Invalid function call")
|
||||||
}
|
}
|
||||||
@@ -70,6 +70,10 @@ func (n *Node) getOrSet(path NodePath, existingPathObj *openapi.PathObj) (node *
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if node.pathParam != nil {
|
||||||
|
setSampleID(&node.pathParam.Extensions, sampleId)
|
||||||
|
}
|
||||||
|
|
||||||
// add example if it's a gibberish chunk
|
// add example if it's a gibberish chunk
|
||||||
if node.pathParam != nil && !chunkIsParam {
|
if node.pathParam != nil && !chunkIsParam {
|
||||||
exmp := &node.pathParam.Examples
|
exmp := &node.pathParam.Examples
|
||||||
@@ -85,7 +89,7 @@ func (n *Node) getOrSet(path NodePath, existingPathObj *openapi.PathObj) (node *
|
|||||||
|
|
||||||
// TODO: eat up trailing slash, in a smart way: node.pathObj!=nil && path[1]==""
|
// TODO: eat up trailing slash, in a smart way: node.pathObj!=nil && path[1]==""
|
||||||
if len(path) > 1 {
|
if len(path) > 1 {
|
||||||
return node.getOrSet(path[1:], existingPathObj)
|
return node.getOrSet(path[1:], existingPathObj, sampleId)
|
||||||
} else if node.pathObj == nil {
|
} else if node.pathObj == nil {
|
||||||
node.pathObj = existingPathObj
|
node.pathObj = existingPathObj
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
package oas
|
package oas
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/chanced/openapi"
|
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"github.com/chanced/openapi"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTree(t *testing.T) {
|
func TestTree(t *testing.T) {
|
||||||
@@ -19,10 +20,10 @@ func TestTree(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tree := new(Node)
|
tree := new(Node)
|
||||||
for _, tc := range testCases {
|
for i, tc := range testCases {
|
||||||
split := strings.Split(tc.inp, "/")
|
split := strings.Split(tc.inp, "/")
|
||||||
pathObj := new(openapi.PathObj)
|
pathObj := new(openapi.PathObj)
|
||||||
node := tree.getOrSet(split, pathObj)
|
node := tree.getOrSet(split, pathObj, uint(i))
|
||||||
|
|
||||||
fillPathParams(node, pathObj)
|
fillPathParams(node, pathObj)
|
||||||
|
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ type nvParams struct {
|
|||||||
GeneralizeName func(name string) string
|
GeneralizeName func(name string) string
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleNameVals(gw nvParams, params **openapi.ParameterList, checkIgnore bool) {
|
func handleNameVals(gw nvParams, params **openapi.ParameterList, checkIgnore bool, sampleId uint) {
|
||||||
visited := map[string]*openapi.ParameterObj{}
|
visited := map[string]*openapi.ParameterObj{}
|
||||||
for _, pair := range gw.Pairs {
|
for _, pair := range gw.Pairs {
|
||||||
if (checkIgnore && gw.IsIgnored(pair.Name)) || pair.Name == "" {
|
if (checkIgnore && gw.IsIgnored(pair.Name)) || pair.Name == "" {
|
||||||
@@ -137,6 +137,8 @@ func handleNameVals(gw nvParams, params **openapi.ParameterList, checkIgnore boo
|
|||||||
logger.Log.Warningf("Failed to add example to a parameter: %s", err)
|
logger.Log.Warningf("Failed to add example to a parameter: %s", err)
|
||||||
}
|
}
|
||||||
visited[nameGeneral] = param
|
visited[nameGeneral] = param
|
||||||
|
|
||||||
|
setSampleID(¶m.Extensions, sampleId)
|
||||||
}
|
}
|
||||||
|
|
||||||
// maintain "required" flag
|
// maintain "required" flag
|
||||||
@@ -474,3 +476,15 @@ func intersectSliceWithMap(required []string, names map[string]struct{}) []strin
|
|||||||
}
|
}
|
||||||
return required
|
return required
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setSampleID(extensions *openapi.Extensions, id uint) {
|
||||||
|
if id > 0 {
|
||||||
|
if *extensions == nil {
|
||||||
|
*extensions = openapi.Extensions{}
|
||||||
|
}
|
||||||
|
err := (extensions).SetExtension(SampleId, id)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log.Warningf("Failed to set sample ID: %s", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -14,9 +14,10 @@ import (
|
|||||||
const FilePath = shared.DataDirPath + "tapped-pods.json"
|
const FilePath = shared.DataDirPath + "tapped-pods.json"
|
||||||
|
|
||||||
var (
|
var (
|
||||||
lock = &sync.Mutex{}
|
lock = &sync.Mutex{}
|
||||||
syncOnce sync.Once
|
syncOnce sync.Once
|
||||||
tappedPods []*shared.PodInfo
|
tappedPods []*shared.PodInfo
|
||||||
|
nodeHostToTappedPodsMap shared.NodeToPodsMap
|
||||||
)
|
)
|
||||||
|
|
||||||
func Get() []*shared.PodInfo {
|
func Get() []*shared.PodInfo {
|
||||||
@@ -55,3 +56,14 @@ func GetTappedPodsStatus() []shared.TappedPodStatus {
|
|||||||
|
|
||||||
return tappedPodsStatus
|
return tappedPodsStatus
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func SetNodeToTappedPodMap(nodeToTappedPodsMap shared.NodeToPodsMap) {
|
||||||
|
summary := nodeToTappedPodsMap.Summary()
|
||||||
|
logger.Log.Infof("Setting node to tapped pods map to %v", summary)
|
||||||
|
|
||||||
|
nodeHostToTappedPodsMap = nodeToTappedPodsMap
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetNodeToTappedPodMap() shared.NodeToPodsMap {
|
||||||
|
return nodeHostToTappedPodsMap
|
||||||
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
restclient "k8s.io/client-go/rest"
|
restclient "k8s.io/client-go/rest"
|
||||||
)
|
)
|
||||||
|
|
||||||
func NewFromInCluster(errOut chan error, namesapce string) (*Resolver, error) {
|
func NewFromInCluster(errOut chan error, namespace string) (*Resolver, error) {
|
||||||
config, err := restclient.InClusterConfig()
|
config, err := restclient.InClusterConfig()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -19,5 +19,5 @@ func NewFromInCluster(errOut chan error, namesapce string) (*Resolver, error) {
|
|||||||
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: namesapce}, nil
|
return &Resolver{clientConfig: config, clientSet: clientset, nameMap: cmap.New(), serviceMap: cmap.New(), errOut: errOut, namespace: namespace}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -168,11 +168,13 @@ func (resolver *Resolver) watchServices(ctx context.Context) error {
|
|||||||
|
|
||||||
func (resolver *Resolver) saveResolvedName(key string, resolved string, namespace string, eventType watch.EventType) {
|
func (resolver *Resolver) saveResolvedName(key string, resolved string, namespace string, eventType watch.EventType) {
|
||||||
if eventType == watch.Deleted {
|
if eventType == watch.Deleted {
|
||||||
|
resolver.nameMap.Remove(resolved)
|
||||||
resolver.nameMap.Remove(key)
|
resolver.nameMap.Remove(key)
|
||||||
logger.Log.Infof("setting %s=nil", key)
|
logger.Log.Infof("setting %s=nil", key)
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
resolver.nameMap.Set(key, &ResolvedObjectInfo{FullAddress: resolved, Namespace: namespace})
|
resolver.nameMap.Set(key, &ResolvedObjectInfo{FullAddress: resolved, Namespace: namespace})
|
||||||
|
resolver.nameMap.Set(resolved, &ResolvedObjectInfo{FullAddress: resolved, Namespace: namespace})
|
||||||
logger.Log.Infof("setting %s=%s", key, resolved)
|
logger.Log.Infof("setting %s=%s", key, resolved)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
15
agent/pkg/routes/db_routes.go
Normal file
15
agent/pkg/routes/db_routes.go
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
package routes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/up9inc/mizu/agent/pkg/controllers"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
)
|
||||||
|
|
||||||
|
// DdRoutes defines the group of database routes.
|
||||||
|
func DbRoutes(app *gin.Engine) {
|
||||||
|
routeGroup := app.Group("/db")
|
||||||
|
|
||||||
|
routeGroup.GET("/flush", controllers.Flush)
|
||||||
|
routeGroup.GET("/reset", controllers.Reset)
|
||||||
|
}
|
||||||
@@ -18,10 +18,11 @@ type ServiceMapResponse struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type ServiceMapNode struct {
|
type ServiceMapNode struct {
|
||||||
Id int `json:"id"`
|
Id int `json:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Entry *tapApi.TCP `json:"entry"`
|
Entry *tapApi.TCP `json:"entry"`
|
||||||
Count int `json:"count"`
|
Count int `json:"count"`
|
||||||
|
Resolved bool `json:"resolved"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServiceMapEdge struct {
|
type ServiceMapEdge struct {
|
||||||
|
|||||||
@@ -13,28 +13,31 @@ const (
|
|||||||
UnresolvedNodeName = "unresolved"
|
UnresolvedNodeName = "unresolved"
|
||||||
)
|
)
|
||||||
|
|
||||||
var instance *serviceMap
|
var instance *defaultServiceMap
|
||||||
var once sync.Once
|
var once sync.Once
|
||||||
|
|
||||||
func GetInstance() ServiceMap {
|
func GetDefaultServiceMapInstance() *defaultServiceMap {
|
||||||
once.Do(func() {
|
once.Do(func() {
|
||||||
instance = newServiceMap()
|
instance = NewDefaultServiceMapGenerator()
|
||||||
logger.Log.Debug("Service Map Initialized")
|
logger.Log.Debug("Service Map Initialized")
|
||||||
})
|
})
|
||||||
return instance
|
return instance
|
||||||
}
|
}
|
||||||
|
|
||||||
type serviceMap struct {
|
type defaultServiceMap struct {
|
||||||
enabled bool
|
enabled bool
|
||||||
graph *graph
|
graph *graph
|
||||||
entriesProcessed int
|
entriesProcessed int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ServiceMapSink interface {
|
||||||
|
NewTCPEntry(source *tapApi.TCP, destination *tapApi.TCP, protocol *tapApi.Protocol)
|
||||||
|
}
|
||||||
|
|
||||||
type ServiceMap interface {
|
type ServiceMap interface {
|
||||||
Enable()
|
Enable()
|
||||||
Disable()
|
Disable()
|
||||||
IsEnabled() bool
|
IsEnabled() bool
|
||||||
NewTCPEntry(source *tapApi.TCP, destination *tapApi.TCP, protocol *tapApi.Protocol)
|
|
||||||
GetStatus() ServiceMapStatus
|
GetStatus() ServiceMapStatus
|
||||||
GetNodes() []ServiceMapNode
|
GetNodes() []ServiceMapNode
|
||||||
GetEdges() []ServiceMapEdge
|
GetEdges() []ServiceMapEdge
|
||||||
@@ -44,8 +47,8 @@ type ServiceMap interface {
|
|||||||
Reset()
|
Reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
func newServiceMap() *serviceMap {
|
func NewDefaultServiceMapGenerator() *defaultServiceMap {
|
||||||
return &serviceMap{
|
return &defaultServiceMap{
|
||||||
enabled: false,
|
enabled: false,
|
||||||
entriesProcessed: 0,
|
entriesProcessed: 0,
|
||||||
graph: newDirectedGraph(),
|
graph: newDirectedGraph(),
|
||||||
@@ -105,12 +108,12 @@ func newEdgeData(p *tapApi.Protocol) *edgeData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *serviceMap) nodeExists(k key) (*nodeData, bool) {
|
func (s *defaultServiceMap) nodeExists(k key) (*nodeData, bool) {
|
||||||
n, ok := s.graph.Nodes[k]
|
n, ok := s.graph.Nodes[k]
|
||||||
return n, ok
|
return n, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *serviceMap) addNode(k key, e *tapApi.TCP) (*nodeData, bool) {
|
func (s *defaultServiceMap) addNode(k key, e *tapApi.TCP) (*nodeData, bool) {
|
||||||
nd, exists := s.nodeExists(k)
|
nd, exists := s.nodeExists(k)
|
||||||
if !exists {
|
if !exists {
|
||||||
s.graph.Nodes[k] = newNodeData(len(s.graph.Nodes)+1, e)
|
s.graph.Nodes[k] = newNodeData(len(s.graph.Nodes)+1, e)
|
||||||
@@ -119,7 +122,7 @@ func (s *serviceMap) addNode(k key, e *tapApi.TCP) (*nodeData, bool) {
|
|||||||
return nd, false
|
return nd, false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *serviceMap) addEdge(u, v *entryData, p *tapApi.Protocol) {
|
func (s *defaultServiceMap) addEdge(u, v *entryData, p *tapApi.Protocol) {
|
||||||
if n, ok := s.addNode(u.key, u.entry); !ok {
|
if n, ok := s.addNode(u.key, u.entry); !ok {
|
||||||
n.count++
|
n.count++
|
||||||
}
|
}
|
||||||
@@ -156,20 +159,20 @@ func (s *serviceMap) addEdge(u, v *entryData, p *tapApi.Protocol) {
|
|||||||
s.entriesProcessed++
|
s.entriesProcessed++
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *serviceMap) Enable() {
|
func (s *defaultServiceMap) Enable() {
|
||||||
s.enabled = true
|
s.enabled = true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *serviceMap) Disable() {
|
func (s *defaultServiceMap) Disable() {
|
||||||
s.Reset()
|
s.Reset()
|
||||||
s.enabled = false
|
s.enabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *serviceMap) IsEnabled() bool {
|
func (s *defaultServiceMap) IsEnabled() bool {
|
||||||
return s.enabled
|
return s.enabled
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *serviceMap) NewTCPEntry(src *tapApi.TCP, dst *tapApi.TCP, p *tapApi.Protocol) {
|
func (s *defaultServiceMap) NewTCPEntry(src *tapApi.TCP, dst *tapApi.TCP, p *tapApi.Protocol) {
|
||||||
if !s.IsEnabled() {
|
if !s.IsEnabled() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -206,7 +209,7 @@ func (s *serviceMap) NewTCPEntry(src *tapApi.TCP, dst *tapApi.TCP, p *tapApi.Pro
|
|||||||
s.addEdge(srcEntry, dstEntry, p)
|
s.addEdge(srcEntry, dstEntry, p)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *serviceMap) GetStatus() ServiceMapStatus {
|
func (s *defaultServiceMap) GetStatus() ServiceMapStatus {
|
||||||
status := ServiceMapDisabled
|
status := ServiceMapDisabled
|
||||||
if s.IsEnabled() {
|
if s.IsEnabled() {
|
||||||
status = ServiceMapEnabled
|
status = ServiceMapEnabled
|
||||||
@@ -220,36 +223,39 @@ func (s *serviceMap) GetStatus() ServiceMapStatus {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *serviceMap) GetNodes() []ServiceMapNode {
|
func (s *defaultServiceMap) GetNodes() []ServiceMapNode {
|
||||||
var nodes []ServiceMapNode
|
var nodes []ServiceMapNode
|
||||||
for i, n := range s.graph.Nodes {
|
for i, n := range s.graph.Nodes {
|
||||||
nodes = append(nodes, ServiceMapNode{
|
nodes = append(nodes, ServiceMapNode{
|
||||||
Id: n.id,
|
Id: n.id,
|
||||||
Name: string(i),
|
Name: string(i),
|
||||||
Entry: n.entry,
|
Resolved: n.entry.Name != UnresolvedNodeName,
|
||||||
Count: n.count,
|
Entry: n.entry,
|
||||||
|
Count: n.count,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return nodes
|
return nodes
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *serviceMap) GetEdges() []ServiceMapEdge {
|
func (s *defaultServiceMap) GetEdges() []ServiceMapEdge {
|
||||||
var edges []ServiceMapEdge
|
var edges []ServiceMapEdge
|
||||||
for u, m := range s.graph.Edges {
|
for u, m := range s.graph.Edges {
|
||||||
for v := range m {
|
for v := range m {
|
||||||
for _, p := range s.graph.Edges[u][v].data {
|
for _, p := range s.graph.Edges[u][v].data {
|
||||||
edges = append(edges, ServiceMapEdge{
|
edges = append(edges, ServiceMapEdge{
|
||||||
Source: ServiceMapNode{
|
Source: ServiceMapNode{
|
||||||
Id: s.graph.Nodes[u].id,
|
Id: s.graph.Nodes[u].id,
|
||||||
Name: string(u),
|
Name: string(u),
|
||||||
Entry: s.graph.Nodes[u].entry,
|
Entry: s.graph.Nodes[u].entry,
|
||||||
Count: s.graph.Nodes[u].count,
|
Resolved: s.graph.Nodes[u].entry.Name != UnresolvedNodeName,
|
||||||
|
Count: s.graph.Nodes[u].count,
|
||||||
},
|
},
|
||||||
Destination: ServiceMapNode{
|
Destination: ServiceMapNode{
|
||||||
Id: s.graph.Nodes[v].id,
|
Id: s.graph.Nodes[v].id,
|
||||||
Name: string(v),
|
Name: string(v),
|
||||||
Entry: s.graph.Nodes[v].entry,
|
Entry: s.graph.Nodes[v].entry,
|
||||||
Count: s.graph.Nodes[v].count,
|
Resolved: s.graph.Nodes[v].entry.Name != UnresolvedNodeName,
|
||||||
|
Count: s.graph.Nodes[v].count,
|
||||||
},
|
},
|
||||||
Count: p.count,
|
Count: p.count,
|
||||||
Protocol: p.protocol,
|
Protocol: p.protocol,
|
||||||
@@ -260,15 +266,15 @@ func (s *serviceMap) GetEdges() []ServiceMapEdge {
|
|||||||
return edges
|
return edges
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *serviceMap) GetEntriesProcessedCount() int {
|
func (s *defaultServiceMap) GetEntriesProcessedCount() int {
|
||||||
return s.entriesProcessed
|
return s.entriesProcessed
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *serviceMap) GetNodesCount() int {
|
func (s *defaultServiceMap) GetNodesCount() int {
|
||||||
return len(s.graph.Nodes)
|
return len(s.graph.Nodes)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *serviceMap) GetEdgesCount() int {
|
func (s *defaultServiceMap) GetEdgesCount() int {
|
||||||
var count int
|
var count int
|
||||||
for u, m := range s.graph.Edges {
|
for u, m := range s.graph.Edges {
|
||||||
for v := range m {
|
for v := range m {
|
||||||
@@ -280,7 +286,7 @@ func (s *serviceMap) GetEdgesCount() int {
|
|||||||
return count
|
return count
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *serviceMap) Reset() {
|
func (s *defaultServiceMap) Reset() {
|
||||||
s.entriesProcessed = 0
|
s.entriesProcessed = 0
|
||||||
s.graph = newDirectedGraph()
|
s.graph = newDirectedGraph()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,21 +80,21 @@ var (
|
|||||||
type ServiceMapDisabledSuite struct {
|
type ServiceMapDisabledSuite struct {
|
||||||
suite.Suite
|
suite.Suite
|
||||||
|
|
||||||
instance ServiceMap
|
instance *defaultServiceMap
|
||||||
}
|
}
|
||||||
|
|
||||||
type ServiceMapEnabledSuite struct {
|
type ServiceMapEnabledSuite struct {
|
||||||
suite.Suite
|
suite.Suite
|
||||||
|
|
||||||
instance ServiceMap
|
instance *defaultServiceMap
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ServiceMapDisabledSuite) SetupTest() {
|
func (s *ServiceMapDisabledSuite) SetupTest() {
|
||||||
s.instance = GetInstance()
|
s.instance = GetDefaultServiceMapInstance()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *ServiceMapEnabledSuite) SetupTest() {
|
func (s *ServiceMapEnabledSuite) SetupTest() {
|
||||||
s.instance = GetInstance()
|
s.instance = GetDefaultServiceMapInstance()
|
||||||
s.instance.Enable()
|
s.instance.Enable()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ func (s *ServiceMapDisabledSuite) TestServiceMapInstance() {
|
|||||||
func (s *ServiceMapDisabledSuite) TestServiceMapSingletonInstance() {
|
func (s *ServiceMapDisabledSuite) TestServiceMapSingletonInstance() {
|
||||||
assert := s.Assert()
|
assert := s.Assert()
|
||||||
|
|
||||||
instance2 := GetInstance()
|
instance2 := GetDefaultServiceMapInstance()
|
||||||
|
|
||||||
assert.NotNil(s.instance)
|
assert.NotNil(s.instance)
|
||||||
assert.NotNil(instance2)
|
assert.NotNil(instance2)
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ import (
|
|||||||
"github.com/up9inc/mizu/shared/logger"
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
StartTime int64 // global
|
||||||
|
)
|
||||||
|
|
||||||
// StartServer starts the server with a graceful shutdown
|
// StartServer starts the server with a graceful shutdown
|
||||||
func StartServer(app *gin.Engine) {
|
func StartServer(app *gin.Engine) {
|
||||||
signals := make(chan os.Signal, 2)
|
signals := make(chan os.Signal, 2)
|
||||||
|
|||||||
@@ -10,8 +10,6 @@ import (
|
|||||||
"net/url"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/up9inc/mizu/shared/kubernetes"
|
|
||||||
|
|
||||||
"github.com/up9inc/mizu/cli/config"
|
"github.com/up9inc/mizu/cli/config"
|
||||||
"github.com/up9inc/mizu/shared"
|
"github.com/up9inc/mizu/shared"
|
||||||
"github.com/up9inc/mizu/shared/logger"
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
@@ -83,15 +81,13 @@ func (provider *Provider) ReportTapperStatus(tapperStatus shared.TapperStatus) e
|
|||||||
func (provider *Provider) ReportTappedPods(pods []core.Pod) error {
|
func (provider *Provider) ReportTappedPods(pods []core.Pod) error {
|
||||||
tappedPodsUrl := fmt.Sprintf("%s/status/tappedPods", provider.url)
|
tappedPodsUrl := fmt.Sprintf("%s/status/tappedPods", provider.url)
|
||||||
|
|
||||||
podInfos := kubernetes.GetPodInfosForPods(pods)
|
if jsonValue, err := json.Marshal(pods); err != nil {
|
||||||
|
|
||||||
if jsonValue, err := json.Marshal(podInfos); err != nil {
|
|
||||||
return fmt.Errorf("failed Marshal the tapped pods %w", err)
|
return fmt.Errorf("failed Marshal the tapped pods %w", err)
|
||||||
} else {
|
} else {
|
||||||
if _, err := utils.Post(tappedPodsUrl, "application/json", bytes.NewBuffer(jsonValue), provider.client); err != nil {
|
if _, err := utils.Post(tappedPodsUrl, "application/json", bytes.NewBuffer(jsonValue), provider.client); err != nil {
|
||||||
return fmt.Errorf("failed sending to API server the tapped pods %w", err)
|
return fmt.Errorf("failed sending to API server the tapped pods %w", err)
|
||||||
} else {
|
} else {
|
||||||
logger.Log.Debugf("Reported to server API about %d taped pods successfully", len(podInfos))
|
logger.Log.Debugf("Reported to server API about %d taped pods successfully", len(pods))
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,4 +27,6 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
checkCmd.Flags().Bool(configStructs.PreTapCheckName, defaultCheckConfig.PreTap, "Check pre-tap Mizu installation for potential problems")
|
checkCmd.Flags().Bool(configStructs.PreTapCheckName, defaultCheckConfig.PreTap, "Check pre-tap Mizu installation for potential problems")
|
||||||
|
checkCmd.Flags().Bool(configStructs.PreInstallCheckName, defaultCheckConfig.PreInstall, "Check pre-install Mizu installation for potential problems")
|
||||||
|
checkCmd.Flags().Bool(configStructs.ImagePullCheckName, defaultCheckConfig.ImagePull, "Test connectivity to container image registry by creating and removing a temporary pod in 'default' namespace")
|
||||||
}
|
}
|
||||||
|
|||||||
102
cli/cmd/check/imagePullInCluster.go
Normal file
102
cli/cmd/check/imagePullInCluster.go
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/up9inc/mizu/cli/uiUtils"
|
||||||
|
"github.com/up9inc/mizu/shared/kubernetes"
|
||||||
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
|
core "k8s.io/api/core/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"regexp"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ImagePullInCluster(ctx context.Context, kubernetesProvider *kubernetes.Provider) bool {
|
||||||
|
logger.Log.Infof("\nimage-pull-in-cluster\n--------------------")
|
||||||
|
|
||||||
|
namespace := "default"
|
||||||
|
podName := "mizu-test"
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if err := kubernetesProvider.RemovePod(ctx, namespace, podName); err != nil {
|
||||||
|
logger.Log.Errorf("%v error while removing test pod in cluster, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if err := createImagePullInClusterPod(ctx, kubernetesProvider, namespace, podName); err != nil {
|
||||||
|
logger.Log.Errorf("%v error while creating test pod in cluster, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := checkImagePulled(ctx, kubernetesProvider, namespace, podName); err != nil {
|
||||||
|
logger.Log.Errorf("%v cluster is not able to pull mizu containers from docker hub, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Log.Infof("%v cluster is able to pull mizu containers from docker hub", fmt.Sprintf(uiUtils.Green, "√"))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkImagePulled(ctx context.Context, kubernetesProvider *kubernetes.Provider, namespace string, podName string) error {
|
||||||
|
podExactRegex := regexp.MustCompile(fmt.Sprintf("^%s$", podName))
|
||||||
|
podWatchHelper := kubernetes.NewPodWatchHelper(kubernetesProvider, podExactRegex)
|
||||||
|
eventChan, errorChan := kubernetes.FilteredWatch(ctx, podWatchHelper, []string{namespace}, podWatchHelper)
|
||||||
|
|
||||||
|
timeAfter := time.After(30 * time.Second)
|
||||||
|
|
||||||
|
for {
|
||||||
|
select {
|
||||||
|
case wEvent, ok := <-eventChan:
|
||||||
|
if !ok {
|
||||||
|
eventChan = nil
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
pod, err := wEvent.ToPod()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if pod.Status.Phase == core.PodRunning {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
case err, ok := <-errorChan:
|
||||||
|
if !ok {
|
||||||
|
errorChan = nil
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
return err
|
||||||
|
case <-timeAfter:
|
||||||
|
return fmt.Errorf("image not pulled in time")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func createImagePullInClusterPod(ctx context.Context, kubernetesProvider *kubernetes.Provider, namespace string, podName string) error {
|
||||||
|
var zero int64
|
||||||
|
pod := &core.Pod{
|
||||||
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
|
Name: podName,
|
||||||
|
},
|
||||||
|
Spec: core.PodSpec{
|
||||||
|
Containers: []core.Container{
|
||||||
|
{
|
||||||
|
Name: "probe",
|
||||||
|
Image: "up9inc/busybox",
|
||||||
|
ImagePullPolicy: "Always",
|
||||||
|
Command: []string{"cat"},
|
||||||
|
Stdin: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
TerminationGracePeriodSeconds: &zero,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
if _, err := kubernetesProvider.CreatePod(ctx, namespace, pod); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
31
cli/cmd/check/kubernetesApi.go
Normal file
31
cli/cmd/check/kubernetesApi.go
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/up9inc/mizu/cli/config"
|
||||||
|
"github.com/up9inc/mizu/cli/uiUtils"
|
||||||
|
"github.com/up9inc/mizu/shared/kubernetes"
|
||||||
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
|
"github.com/up9inc/mizu/shared/semver"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
func KubernetesApi() (*kubernetes.Provider, *semver.SemVersion, bool) {
|
||||||
|
logger.Log.Infof("\nkubernetes-api\n--------------------")
|
||||||
|
|
||||||
|
kubernetesProvider, err := kubernetes.NewProvider(config.Config.KubeConfigPath(), config.Config.KubeContext)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log.Errorf("%v can't initialize the client, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
||||||
|
return nil, nil, false
|
||||||
|
}
|
||||||
|
logger.Log.Infof("%v can initialize the client", fmt.Sprintf(uiUtils.Green, "√"))
|
||||||
|
|
||||||
|
kubernetesVersion, err := kubernetesProvider.GetKubernetesVersion()
|
||||||
|
if err != nil {
|
||||||
|
logger.Log.Errorf("%v can't query the Kubernetes API, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
||||||
|
return nil, nil, false
|
||||||
|
}
|
||||||
|
logger.Log.Infof("%v can query the Kubernetes API", fmt.Sprintf(uiUtils.Green, "√"))
|
||||||
|
|
||||||
|
return kubernetesProvider, kubernetesVersion, true
|
||||||
|
}
|
||||||
131
cli/cmd/check/kubernetesPermissions.go
Normal file
131
cli/cmd/check/kubernetesPermissions.go
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"embed"
|
||||||
|
"fmt"
|
||||||
|
"github.com/up9inc/mizu/cli/bucket"
|
||||||
|
"github.com/up9inc/mizu/cli/config"
|
||||||
|
"github.com/up9inc/mizu/cli/uiUtils"
|
||||||
|
"github.com/up9inc/mizu/shared/kubernetes"
|
||||||
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
|
rbac "k8s.io/api/rbac/v1"
|
||||||
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
"k8s.io/client-go/kubernetes/scheme"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TapKubernetesPermissions(ctx context.Context, embedFS embed.FS, kubernetesProvider *kubernetes.Provider) bool {
|
||||||
|
logger.Log.Infof("\nkubernetes-permissions\n--------------------")
|
||||||
|
|
||||||
|
var filePath string
|
||||||
|
if config.Config.IsNsRestrictedMode() {
|
||||||
|
filePath = "permissionFiles/permissions-ns-tap.yaml"
|
||||||
|
} else {
|
||||||
|
filePath = "permissionFiles/permissions-all-namespaces-tap.yaml"
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := embedFS.ReadFile(filePath)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log.Errorf("%v error while checking kubernetes permissions, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
decode := scheme.Codecs.UniversalDeserializer().Decode
|
||||||
|
obj, _, err := decode(data, nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log.Errorf("%v error while checking kubernetes permissions, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
switch resource := obj.(type) {
|
||||||
|
case *rbac.Role:
|
||||||
|
return checkRulesPermissions(ctx, kubernetesProvider, resource.Rules, config.Config.MizuResourcesNamespace)
|
||||||
|
case *rbac.ClusterRole:
|
||||||
|
return checkRulesPermissions(ctx, kubernetesProvider, resource.Rules, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Log.Errorf("%v error while checking kubernetes permissions, err: resource of type 'Role' or 'ClusterRole' not found in permission files", fmt.Sprintf(uiUtils.Red, "✗"))
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
func InstallKubernetesPermissions(ctx context.Context, kubernetesProvider *kubernetes.Provider) bool {
|
||||||
|
logger.Log.Infof("\nkubernetes-permissions\n--------------------")
|
||||||
|
|
||||||
|
bucketProvider := bucket.NewProvider(config.Config.Install.TemplateUrl, bucket.DefaultTimeout)
|
||||||
|
installTemplate, err := bucketProvider.GetInstallTemplate(config.Config.Install.TemplateName)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log.Errorf("%v error while checking kubernetes permissions, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
resourcesTemplate := strings.Split(installTemplate, "---")[1:]
|
||||||
|
|
||||||
|
permissionsExist := true
|
||||||
|
|
||||||
|
decode := scheme.Codecs.UniversalDeserializer().Decode
|
||||||
|
for _, resourceTemplate := range resourcesTemplate {
|
||||||
|
obj, _, err := decode([]byte(resourceTemplate), nil, nil)
|
||||||
|
if err != nil {
|
||||||
|
logger.Log.Errorf("%v error while checking kubernetes permissions, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
groupVersionKind := obj.GetObjectKind().GroupVersionKind()
|
||||||
|
resource := fmt.Sprintf("%vs", strings.ToLower(groupVersionKind.Kind))
|
||||||
|
permissionsExist = checkCreatePermission(ctx, kubernetesProvider, resource, groupVersionKind.Group, obj.(metav1.Object).GetNamespace()) && permissionsExist
|
||||||
|
|
||||||
|
switch resourceObj := obj.(type) {
|
||||||
|
case *rbac.Role:
|
||||||
|
permissionsExist = checkRulesPermissions(ctx, kubernetesProvider, resourceObj.Rules, resourceObj.Namespace) && permissionsExist
|
||||||
|
case *rbac.ClusterRole:
|
||||||
|
permissionsExist = checkRulesPermissions(ctx, kubernetesProvider, resourceObj.Rules, "") && permissionsExist
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return permissionsExist
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkCreatePermission(ctx context.Context, kubernetesProvider *kubernetes.Provider, resource string, group string, namespace string) bool {
|
||||||
|
exist, err := kubernetesProvider.CanI(ctx, namespace, resource, "create", group)
|
||||||
|
return checkPermissionExist(group, resource, "create", namespace, exist, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkRulesPermissions(ctx context.Context, kubernetesProvider *kubernetes.Provider, rules []rbac.PolicyRule, namespace string) bool {
|
||||||
|
permissionsExist := true
|
||||||
|
|
||||||
|
for _, rule := range rules {
|
||||||
|
for _, group := range rule.APIGroups {
|
||||||
|
for _, resource := range rule.Resources {
|
||||||
|
for _, verb := range rule.Verbs {
|
||||||
|
exist, err := kubernetesProvider.CanI(ctx, namespace, resource, verb, group)
|
||||||
|
permissionsExist = checkPermissionExist(group, resource, verb, namespace, exist, err) && permissionsExist
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return permissionsExist
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkPermissionExist(group string, resource string, verb string, namespace string, exist bool, err error) bool {
|
||||||
|
var groupAndNamespace string
|
||||||
|
if group != "" && namespace != "" {
|
||||||
|
groupAndNamespace = fmt.Sprintf("in api group '%v' and namespace '%v'", group, namespace)
|
||||||
|
} else if group != "" {
|
||||||
|
groupAndNamespace = fmt.Sprintf("in api group '%v'", group)
|
||||||
|
} else if namespace != "" {
|
||||||
|
groupAndNamespace = fmt.Sprintf("in namespace '%v'", namespace)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
logger.Log.Errorf("%v error checking permission for %v %v %v, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), verb, resource, groupAndNamespace, err)
|
||||||
|
return false
|
||||||
|
} else if !exist {
|
||||||
|
logger.Log.Errorf("%v can't %v %v %v", fmt.Sprintf(uiUtils.Red, "✗"), verb, resource, groupAndNamespace)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Log.Infof("%v can %v %v %v", fmt.Sprintf(uiUtils.Green, "√"), verb, resource, groupAndNamespace)
|
||||||
|
return true
|
||||||
|
}
|
||||||
95
cli/cmd/check/kubernetesResources.go
Normal file
95
cli/cmd/check/kubernetesResources.go
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/up9inc/mizu/cli/config"
|
||||||
|
"github.com/up9inc/mizu/cli/uiUtils"
|
||||||
|
"github.com/up9inc/mizu/shared/kubernetes"
|
||||||
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
func KubernetesResources(ctx context.Context, kubernetesProvider *kubernetes.Provider) bool {
|
||||||
|
logger.Log.Infof("\nk8s-components\n--------------------")
|
||||||
|
|
||||||
|
exist, err := kubernetesProvider.DoesNamespaceExist(ctx, config.Config.MizuResourcesNamespace)
|
||||||
|
allResourcesExist := checkResourceExist(config.Config.MizuResourcesNamespace, "namespace", exist, err)
|
||||||
|
|
||||||
|
exist, err = kubernetesProvider.DoesConfigMapExist(ctx, config.Config.MizuResourcesNamespace, kubernetes.ConfigMapName)
|
||||||
|
allResourcesExist = checkResourceExist(kubernetes.ConfigMapName, "config map", exist, err) && allResourcesExist
|
||||||
|
|
||||||
|
exist, err = kubernetesProvider.DoesServiceAccountExist(ctx, config.Config.MizuResourcesNamespace, kubernetes.ServiceAccountName)
|
||||||
|
allResourcesExist = checkResourceExist(kubernetes.ServiceAccountName, "service account", exist, err) && allResourcesExist
|
||||||
|
|
||||||
|
if config.Config.IsNsRestrictedMode() {
|
||||||
|
exist, err = kubernetesProvider.DoesRoleExist(ctx, config.Config.MizuResourcesNamespace, kubernetes.RoleName)
|
||||||
|
allResourcesExist = checkResourceExist(kubernetes.RoleName, "role", exist, err) && allResourcesExist
|
||||||
|
|
||||||
|
exist, err = kubernetesProvider.DoesRoleBindingExist(ctx, config.Config.MizuResourcesNamespace, kubernetes.RoleBindingName)
|
||||||
|
allResourcesExist = checkResourceExist(kubernetes.RoleBindingName, "role binding", exist, err) && allResourcesExist
|
||||||
|
} else {
|
||||||
|
exist, err = kubernetesProvider.DoesClusterRoleExist(ctx, kubernetes.ClusterRoleName)
|
||||||
|
allResourcesExist = checkResourceExist(kubernetes.ClusterRoleName, "cluster role", exist, err) && allResourcesExist
|
||||||
|
|
||||||
|
exist, err = kubernetesProvider.DoesClusterRoleBindingExist(ctx, kubernetes.ClusterRoleBindingName)
|
||||||
|
allResourcesExist = checkResourceExist(kubernetes.ClusterRoleBindingName, "cluster role binding", exist, err) && allResourcesExist
|
||||||
|
}
|
||||||
|
|
||||||
|
exist, err = kubernetesProvider.DoesServiceExist(ctx, config.Config.MizuResourcesNamespace, kubernetes.ApiServerPodName)
|
||||||
|
allResourcesExist = checkResourceExist(kubernetes.ApiServerPodName, "service", exist, err) && allResourcesExist
|
||||||
|
|
||||||
|
allResourcesExist = checkPodResourcesExist(ctx, kubernetesProvider) && allResourcesExist
|
||||||
|
|
||||||
|
return allResourcesExist
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkPodResourcesExist(ctx context.Context, kubernetesProvider *kubernetes.Provider) bool {
|
||||||
|
if pods, err := kubernetesProvider.ListPodsByAppLabel(ctx, config.Config.MizuResourcesNamespace, kubernetes.ApiServerPodName); err != nil {
|
||||||
|
logger.Log.Errorf("%v error checking if '%v' pod is running, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), kubernetes.ApiServerPodName, err)
|
||||||
|
return false
|
||||||
|
} else if len(pods) == 0 {
|
||||||
|
logger.Log.Errorf("%v '%v' pod doesn't exist", fmt.Sprintf(uiUtils.Red, "✗"), kubernetes.ApiServerPodName)
|
||||||
|
return false
|
||||||
|
} else if !kubernetes.IsPodRunning(&pods[0]) {
|
||||||
|
logger.Log.Errorf("%v '%v' pod not running", fmt.Sprintf(uiUtils.Red, "✗"), kubernetes.ApiServerPodName)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Log.Infof("%v '%v' pod running", fmt.Sprintf(uiUtils.Green, "√"), kubernetes.ApiServerPodName)
|
||||||
|
|
||||||
|
if pods, err := kubernetesProvider.ListPodsByAppLabel(ctx, config.Config.MizuResourcesNamespace, kubernetes.TapperPodName); err != nil {
|
||||||
|
logger.Log.Errorf("%v error checking if '%v' pods are running, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), kubernetes.TapperPodName, err)
|
||||||
|
return false
|
||||||
|
} else {
|
||||||
|
tappers := 0
|
||||||
|
notRunningTappers := 0
|
||||||
|
|
||||||
|
for _, pod := range pods {
|
||||||
|
tappers += 1
|
||||||
|
if !kubernetes.IsPodRunning(&pod) {
|
||||||
|
notRunningTappers += 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if notRunningTappers > 0 {
|
||||||
|
logger.Log.Errorf("%v '%v' %v/%v pods are not running", fmt.Sprintf(uiUtils.Red, "✗"), kubernetes.TapperPodName, notRunningTappers, tappers)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Log.Infof("%v '%v' %v pods running", fmt.Sprintf(uiUtils.Green, "√"), kubernetes.TapperPodName, tappers)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkResourceExist(resourceName string, resourceType string, exist bool, err error) bool {
|
||||||
|
if err != nil {
|
||||||
|
logger.Log.Errorf("%v error checking if '%v' %v exists, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), resourceName, resourceType, err)
|
||||||
|
return false
|
||||||
|
} else if !exist {
|
||||||
|
logger.Log.Errorf("%v '%v' %v doesn't exist", fmt.Sprintf(uiUtils.Red, "✗"), resourceName, resourceType)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Log.Infof("%v '%v' %v exists", fmt.Sprintf(uiUtils.Green, "√"), resourceName, resourceType)
|
||||||
|
return true
|
||||||
|
}
|
||||||
21
cli/cmd/check/kubernetesVersion.go
Normal file
21
cli/cmd/check/kubernetesVersion.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/up9inc/mizu/cli/uiUtils"
|
||||||
|
"github.com/up9inc/mizu/shared/kubernetes"
|
||||||
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
|
"github.com/up9inc/mizu/shared/semver"
|
||||||
|
)
|
||||||
|
|
||||||
|
func KubernetesVersion(kubernetesVersion *semver.SemVersion) bool {
|
||||||
|
logger.Log.Infof("\nkubernetes-version\n--------------------")
|
||||||
|
|
||||||
|
if err := kubernetes.ValidateKubernetesVersion(kubernetesVersion); err != nil {
|
||||||
|
logger.Log.Errorf("%v not running the minimum Kubernetes API version, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Log.Infof("%v is running the minimum Kubernetes API version", fmt.Sprintf(uiUtils.Green, "√"))
|
||||||
|
return true
|
||||||
|
}
|
||||||
83
cli/cmd/check/serverConnection.go
Normal file
83
cli/cmd/check/serverConnection.go
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
package check
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"github.com/up9inc/mizu/cli/apiserver"
|
||||||
|
"github.com/up9inc/mizu/cli/config"
|
||||||
|
"github.com/up9inc/mizu/cli/uiUtils"
|
||||||
|
"github.com/up9inc/mizu/shared/kubernetes"
|
||||||
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
|
"regexp"
|
||||||
|
)
|
||||||
|
|
||||||
|
func ServerConnection(kubernetesProvider *kubernetes.Provider) bool {
|
||||||
|
logger.Log.Infof("\nAPI-server-connectivity\n--------------------")
|
||||||
|
|
||||||
|
serverUrl := fmt.Sprintf("http://%s", kubernetes.GetMizuApiServerProxiedHostAndPath(config.Config.Tap.GuiPort))
|
||||||
|
|
||||||
|
apiServerProvider := apiserver.NewProvider(serverUrl, 1, apiserver.DefaultTimeout)
|
||||||
|
if err := apiServerProvider.TestConnection(); err == nil {
|
||||||
|
logger.Log.Infof("%v found Mizu server tunnel available and connected successfully to API server", fmt.Sprintf(uiUtils.Green, "√"))
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
connectedToApiServer := false
|
||||||
|
|
||||||
|
if err := checkProxy(serverUrl, kubernetesProvider); err != nil {
|
||||||
|
logger.Log.Errorf("%v couldn't connect to API server using proxy, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
||||||
|
} else {
|
||||||
|
connectedToApiServer = true
|
||||||
|
logger.Log.Infof("%v connected successfully to API server using proxy", fmt.Sprintf(uiUtils.Green, "√"))
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := checkPortForward(serverUrl, kubernetesProvider); err != nil {
|
||||||
|
logger.Log.Errorf("%v couldn't connect to API server using port-forward, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
||||||
|
} else {
|
||||||
|
connectedToApiServer = true
|
||||||
|
logger.Log.Infof("%v connected successfully to API server using port-forward", fmt.Sprintf(uiUtils.Green, "√"))
|
||||||
|
}
|
||||||
|
|
||||||
|
return connectedToApiServer
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkProxy(serverUrl string, kubernetesProvider *kubernetes.Provider) error {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
httpServer, err := kubernetes.StartProxy(kubernetesProvider, config.Config.Tap.ProxyHost, config.Config.Tap.GuiPort, config.Config.MizuResourcesNamespace, kubernetes.ApiServerPodName, cancel)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
apiServerProvider := apiserver.NewProvider(serverUrl, apiserver.DefaultRetries, apiserver.DefaultTimeout)
|
||||||
|
if err := apiServerProvider.TestConnection(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := httpServer.Shutdown(ctx); err != nil {
|
||||||
|
logger.Log.Debugf("Error occurred while stopping proxy, err: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkPortForward(serverUrl string, kubernetesProvider *kubernetes.Provider) error {
|
||||||
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
|
defer cancel()
|
||||||
|
|
||||||
|
podRegex, _ := regexp.Compile(kubernetes.ApiServerPodName)
|
||||||
|
forwarder, err := kubernetes.NewPortForward(kubernetesProvider, config.Config.MizuResourcesNamespace, podRegex, config.Config.Tap.GuiPort, ctx, cancel)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
apiServerProvider := apiserver.NewProvider(serverUrl, apiserver.DefaultRetries, apiserver.DefaultTimeout)
|
||||||
|
if err := apiServerProvider.TestConnection(); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
forwarder.Close()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
@@ -4,20 +4,10 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"embed"
|
"embed"
|
||||||
"fmt"
|
"fmt"
|
||||||
core "k8s.io/api/core/v1"
|
"github.com/up9inc/mizu/cli/cmd/check"
|
||||||
rbac "k8s.io/api/rbac/v1"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime"
|
|
||||||
"k8s.io/client-go/kubernetes/scheme"
|
|
||||||
"regexp"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/up9inc/mizu/cli/apiserver"
|
|
||||||
"github.com/up9inc/mizu/cli/config"
|
"github.com/up9inc/mizu/cli/config"
|
||||||
"github.com/up9inc/mizu/cli/uiUtils"
|
"github.com/up9inc/mizu/cli/uiUtils"
|
||||||
"github.com/up9inc/mizu/shared/kubernetes"
|
|
||||||
"github.com/up9inc/mizu/shared/logger"
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
"github.com/up9inc/mizu/shared/semver"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
@@ -31,27 +21,35 @@ func runMizuCheck() {
|
|||||||
ctx, cancel := context.WithCancel(context.Background())
|
ctx, cancel := context.WithCancel(context.Background())
|
||||||
defer cancel() // cancel will be called when this function exits
|
defer cancel() // cancel will be called when this function exits
|
||||||
|
|
||||||
kubernetesProvider, kubernetesVersion, checkPassed := checkKubernetesApi()
|
kubernetesProvider, kubernetesVersion, checkPassed := check.KubernetesApi()
|
||||||
|
|
||||||
if checkPassed {
|
if checkPassed {
|
||||||
checkPassed = checkKubernetesVersion(kubernetesVersion)
|
checkPassed = check.KubernetesVersion(kubernetesVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
if config.Config.Check.PreTap {
|
if config.Config.Check.PreTap || config.Config.Check.PreInstall || config.Config.Check.ImagePull {
|
||||||
if checkPassed {
|
if config.Config.Check.PreTap {
|
||||||
checkPassed = checkK8sTapPermissions(ctx, kubernetesProvider)
|
if checkPassed {
|
||||||
|
checkPassed = check.TapKubernetesPermissions(ctx, embedFS, kubernetesProvider)
|
||||||
|
}
|
||||||
|
} else if config.Config.Check.PreInstall {
|
||||||
|
if checkPassed {
|
||||||
|
checkPassed = check.InstallKubernetesPermissions(ctx, kubernetesProvider)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if checkPassed {
|
if config.Config.Check.ImagePull {
|
||||||
checkPassed = checkImagePullInCluster(ctx, kubernetesProvider)
|
if checkPassed {
|
||||||
|
checkPassed = check.ImagePullInCluster(ctx, kubernetesProvider)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if checkPassed {
|
if checkPassed {
|
||||||
checkPassed = checkK8sResources(ctx, kubernetesProvider)
|
checkPassed = check.KubernetesResources(ctx, kubernetesProvider)
|
||||||
}
|
}
|
||||||
|
|
||||||
if checkPassed {
|
if checkPassed {
|
||||||
checkPassed = checkServerConnection(kubernetesProvider)
|
checkPassed = check.ServerConnection(kubernetesProvider)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,365 +59,3 @@ func runMizuCheck() {
|
|||||||
logger.Log.Errorf("\nStatus check results are %v", fmt.Sprintf(uiUtils.Red, "✗"))
|
logger.Log.Errorf("\nStatus check results are %v", fmt.Sprintf(uiUtils.Red, "✗"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func checkKubernetesApi() (*kubernetes.Provider, *semver.SemVersion, bool) {
|
|
||||||
logger.Log.Infof("\nkubernetes-api\n--------------------")
|
|
||||||
|
|
||||||
kubernetesProvider, err := kubernetes.NewProvider(config.Config.KubeConfigPath(), config.Config.KubeContext)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Errorf("%v can't initialize the client, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
|
||||||
return nil, nil, false
|
|
||||||
}
|
|
||||||
logger.Log.Infof("%v can initialize the client", fmt.Sprintf(uiUtils.Green, "√"))
|
|
||||||
|
|
||||||
kubernetesVersion, err := kubernetesProvider.GetKubernetesVersion()
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Errorf("%v can't query the Kubernetes API, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
|
||||||
return nil, nil, false
|
|
||||||
}
|
|
||||||
logger.Log.Infof("%v can query the Kubernetes API", fmt.Sprintf(uiUtils.Green, "√"))
|
|
||||||
|
|
||||||
return kubernetesProvider, kubernetesVersion, true
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkKubernetesVersion(kubernetesVersion *semver.SemVersion) bool {
|
|
||||||
logger.Log.Infof("\nkubernetes-version\n--------------------")
|
|
||||||
|
|
||||||
if err := kubernetes.ValidateKubernetesVersion(kubernetesVersion); err != nil {
|
|
||||||
logger.Log.Errorf("%v not running the minimum Kubernetes API version, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Log.Infof("%v is running the minimum Kubernetes API version", fmt.Sprintf(uiUtils.Green, "√"))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkServerConnection(kubernetesProvider *kubernetes.Provider) bool {
|
|
||||||
logger.Log.Infof("\nAPI-server-connectivity\n--------------------")
|
|
||||||
|
|
||||||
serverUrl := GetApiServerUrl(config.Config.Tap.GuiPort)
|
|
||||||
|
|
||||||
apiServerProvider := apiserver.NewProvider(serverUrl, 1, apiserver.DefaultTimeout)
|
|
||||||
if err := apiServerProvider.TestConnection(); err == nil {
|
|
||||||
logger.Log.Infof("%v found Mizu server tunnel available and connected successfully to API server", fmt.Sprintf(uiUtils.Green, "√"))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
connectedToApiServer := false
|
|
||||||
|
|
||||||
if err := checkProxy(serverUrl, kubernetesProvider); err != nil {
|
|
||||||
logger.Log.Errorf("%v couldn't connect to API server using proxy, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
|
||||||
} else {
|
|
||||||
connectedToApiServer = true
|
|
||||||
logger.Log.Infof("%v connected successfully to API server using proxy", fmt.Sprintf(uiUtils.Green, "√"))
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := checkPortForward(serverUrl, kubernetesProvider); err != nil {
|
|
||||||
logger.Log.Errorf("%v couldn't connect to API server using port-forward, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
|
||||||
} else {
|
|
||||||
connectedToApiServer = true
|
|
||||||
logger.Log.Infof("%v connected successfully to API server using port-forward", fmt.Sprintf(uiUtils.Green, "√"))
|
|
||||||
}
|
|
||||||
|
|
||||||
return connectedToApiServer
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkProxy(serverUrl string, kubernetesProvider *kubernetes.Provider) error {
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
httpServer, err := kubernetes.StartProxy(kubernetesProvider, config.Config.Tap.ProxyHost, config.Config.Tap.GuiPort, config.Config.MizuResourcesNamespace, kubernetes.ApiServerPodName, cancel)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
apiServerProvider := apiserver.NewProvider(serverUrl, apiserver.DefaultRetries, apiserver.DefaultTimeout)
|
|
||||||
if err := apiServerProvider.TestConnection(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := httpServer.Shutdown(ctx); err != nil {
|
|
||||||
logger.Log.Debugf("Error occurred while stopping proxy, err: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkPortForward(serverUrl string, kubernetesProvider *kubernetes.Provider) error {
|
|
||||||
ctx, cancel := context.WithCancel(context.Background())
|
|
||||||
defer cancel()
|
|
||||||
|
|
||||||
podRegex, _ := regexp.Compile(kubernetes.ApiServerPodName)
|
|
||||||
forwarder, err := kubernetes.NewPortForward(kubernetesProvider, config.Config.MizuResourcesNamespace, podRegex, config.Config.Tap.GuiPort, ctx, cancel)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
apiServerProvider := apiserver.NewProvider(serverUrl, apiserver.DefaultRetries, apiserver.DefaultTimeout)
|
|
||||||
if err := apiServerProvider.TestConnection(); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
forwarder.Close()
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkK8sResources(ctx context.Context, kubernetesProvider *kubernetes.Provider) bool {
|
|
||||||
logger.Log.Infof("\nk8s-components\n--------------------")
|
|
||||||
|
|
||||||
exist, err := kubernetesProvider.DoesNamespaceExist(ctx, config.Config.MizuResourcesNamespace)
|
|
||||||
allResourcesExist := checkResourceExist(config.Config.MizuResourcesNamespace, "namespace", exist, err)
|
|
||||||
|
|
||||||
exist, err = kubernetesProvider.DoesConfigMapExist(ctx, config.Config.MizuResourcesNamespace, kubernetes.ConfigMapName)
|
|
||||||
allResourcesExist = checkResourceExist(kubernetes.ConfigMapName, "config map", exist, err) && allResourcesExist
|
|
||||||
|
|
||||||
exist, err = kubernetesProvider.DoesServiceAccountExist(ctx, config.Config.MizuResourcesNamespace, kubernetes.ServiceAccountName)
|
|
||||||
allResourcesExist = checkResourceExist(kubernetes.ServiceAccountName, "service account", exist, err) && allResourcesExist
|
|
||||||
|
|
||||||
if config.Config.IsNsRestrictedMode() {
|
|
||||||
exist, err = kubernetesProvider.DoesRoleExist(ctx, config.Config.MizuResourcesNamespace, kubernetes.RoleName)
|
|
||||||
allResourcesExist = checkResourceExist(kubernetes.RoleName, "role", exist, err) && allResourcesExist
|
|
||||||
|
|
||||||
exist, err = kubernetesProvider.DoesRoleBindingExist(ctx, config.Config.MizuResourcesNamespace, kubernetes.RoleBindingName)
|
|
||||||
allResourcesExist = checkResourceExist(kubernetes.RoleBindingName, "role binding", exist, err) && allResourcesExist
|
|
||||||
} else {
|
|
||||||
exist, err = kubernetesProvider.DoesClusterRoleExist(ctx, kubernetes.ClusterRoleName)
|
|
||||||
allResourcesExist = checkResourceExist(kubernetes.ClusterRoleName, "cluster role", exist, err) && allResourcesExist
|
|
||||||
|
|
||||||
exist, err = kubernetesProvider.DoesClusterRoleBindingExist(ctx, kubernetes.ClusterRoleBindingName)
|
|
||||||
allResourcesExist = checkResourceExist(kubernetes.ClusterRoleBindingName, "cluster role binding", exist, err) && allResourcesExist
|
|
||||||
}
|
|
||||||
|
|
||||||
exist, err = kubernetesProvider.DoesServiceExist(ctx, config.Config.MizuResourcesNamespace, kubernetes.ApiServerPodName)
|
|
||||||
allResourcesExist = checkResourceExist(kubernetes.ApiServerPodName, "service", exist, err) && allResourcesExist
|
|
||||||
|
|
||||||
allResourcesExist = checkPodResourcesExist(ctx, kubernetesProvider) && allResourcesExist
|
|
||||||
|
|
||||||
return allResourcesExist
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkPodResourcesExist(ctx context.Context, kubernetesProvider *kubernetes.Provider) bool {
|
|
||||||
if pods, err := kubernetesProvider.ListPodsByAppLabel(ctx, config.Config.MizuResourcesNamespace, kubernetes.ApiServerPodName); err != nil {
|
|
||||||
logger.Log.Errorf("%v error checking if '%v' pod is running, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), kubernetes.ApiServerPodName, err)
|
|
||||||
return false
|
|
||||||
} else if len(pods) == 0 {
|
|
||||||
logger.Log.Errorf("%v '%v' pod doesn't exist", fmt.Sprintf(uiUtils.Red, "✗"), kubernetes.ApiServerPodName)
|
|
||||||
return false
|
|
||||||
} else if !kubernetes.IsPodRunning(&pods[0]) {
|
|
||||||
logger.Log.Errorf("%v '%v' pod not running", fmt.Sprintf(uiUtils.Red, "✗"), kubernetes.ApiServerPodName)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Log.Infof("%v '%v' pod running", fmt.Sprintf(uiUtils.Green, "√"), kubernetes.ApiServerPodName)
|
|
||||||
|
|
||||||
if pods, err := kubernetesProvider.ListPodsByAppLabel(ctx, config.Config.MizuResourcesNamespace, kubernetes.TapperPodName); err != nil {
|
|
||||||
logger.Log.Errorf("%v error checking if '%v' pods are running, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), kubernetes.TapperPodName, err)
|
|
||||||
return false
|
|
||||||
} else {
|
|
||||||
tappers := 0
|
|
||||||
notRunningTappers := 0
|
|
||||||
|
|
||||||
for _, pod := range pods {
|
|
||||||
tappers += 1
|
|
||||||
if !kubernetes.IsPodRunning(&pod) {
|
|
||||||
notRunningTappers += 1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if notRunningTappers > 0 {
|
|
||||||
logger.Log.Errorf("%v '%v' %v/%v pods are not running", fmt.Sprintf(uiUtils.Red, "✗"), kubernetes.TapperPodName, notRunningTappers, tappers)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Log.Infof("%v '%v' %v pods running", fmt.Sprintf(uiUtils.Green, "√"), kubernetes.TapperPodName, tappers)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkResourceExist(resourceName string, resourceType string, exist bool, err error) bool {
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Errorf("%v error checking if '%v' %v exists, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), resourceName, resourceType, err)
|
|
||||||
return false
|
|
||||||
} else if !exist {
|
|
||||||
logger.Log.Errorf("%v '%v' %v doesn't exist", fmt.Sprintf(uiUtils.Red, "✗"), resourceName, resourceType)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Log.Infof("%v '%v' %v exists", fmt.Sprintf(uiUtils.Green, "√"), resourceName, resourceType)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkK8sTapPermissions(ctx context.Context, kubernetesProvider *kubernetes.Provider) bool {
|
|
||||||
logger.Log.Infof("\nkubernetes-permissions\n--------------------")
|
|
||||||
|
|
||||||
var filePath string
|
|
||||||
if config.Config.IsNsRestrictedMode() {
|
|
||||||
filePath = "permissionFiles/permissions-ns-tap.yaml"
|
|
||||||
} else {
|
|
||||||
filePath = "permissionFiles/permissions-all-namespaces-tap.yaml"
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := embedFS.ReadFile(filePath)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Errorf("%v error while checking kubernetes permissions, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
obj, err := getDecodedObject(data)
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Errorf("%v error while checking kubernetes permissions, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
var rules []rbac.PolicyRule
|
|
||||||
if config.Config.IsNsRestrictedMode() {
|
|
||||||
rules = obj.(*rbac.Role).Rules
|
|
||||||
} else {
|
|
||||||
rules = obj.(*rbac.ClusterRole).Rules
|
|
||||||
}
|
|
||||||
|
|
||||||
return checkPermissions(ctx, kubernetesProvider, rules)
|
|
||||||
}
|
|
||||||
|
|
||||||
func getDecodedObject(data []byte) (runtime.Object, error) {
|
|
||||||
decode := scheme.Codecs.UniversalDeserializer().Decode
|
|
||||||
|
|
||||||
obj, _, err := decode(data, nil, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return obj, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkPermissions(ctx context.Context, kubernetesProvider *kubernetes.Provider, rules []rbac.PolicyRule) bool {
|
|
||||||
permissionsExist := true
|
|
||||||
|
|
||||||
for _, rule := range rules {
|
|
||||||
for _, group := range rule.APIGroups {
|
|
||||||
for _, resource := range rule.Resources {
|
|
||||||
for _, verb := range rule.Verbs {
|
|
||||||
exist, err := kubernetesProvider.CanI(ctx, config.Config.MizuResourcesNamespace, resource, verb, group)
|
|
||||||
permissionsExist = checkPermissionExist(group, resource, verb, exist, err) && permissionsExist
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return permissionsExist
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkPermissionExist(group string, resource string, verb string, exist bool, err error) bool {
|
|
||||||
if err != nil {
|
|
||||||
logger.Log.Errorf("%v error checking permission for %v %v in group '%v', err: %v", fmt.Sprintf(uiUtils.Red, "✗"), verb, resource, group, err)
|
|
||||||
return false
|
|
||||||
} else if !exist {
|
|
||||||
logger.Log.Errorf("%v can't %v %v in group '%v'", fmt.Sprintf(uiUtils.Red, "✗"), verb, resource, group)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Log.Infof("%v can %v %v in group '%v'", fmt.Sprintf(uiUtils.Green, "√"), verb, resource, group)
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkImagePullInCluster(ctx context.Context, kubernetesProvider *kubernetes.Provider) bool {
|
|
||||||
logger.Log.Infof("\nimage-pull-in-cluster\n--------------------")
|
|
||||||
|
|
||||||
podName := "image-pull-in-cluster"
|
|
||||||
|
|
||||||
defer removeImagePullInClusterResources(ctx, kubernetesProvider, podName)
|
|
||||||
if err := createImagePullInClusterResources(ctx, kubernetesProvider, podName); err != nil {
|
|
||||||
logger.Log.Errorf("%v error while creating image pull in cluster resources, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := checkImagePulled(ctx, kubernetesProvider, podName); err != nil {
|
|
||||||
logger.Log.Errorf("%v cluster is not able to pull mizu containers from docker hub, err: %v", fmt.Sprintf(uiUtils.Red, "✗"), err)
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Log.Infof("%v cluster is able to pull mizu containers from docker hub", fmt.Sprintf(uiUtils.Green, "√"))
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
func checkImagePulled(ctx context.Context, kubernetesProvider *kubernetes.Provider, podName string) error {
|
|
||||||
podExactRegex := regexp.MustCompile(fmt.Sprintf("^%s$", podName))
|
|
||||||
podWatchHelper := kubernetes.NewPodWatchHelper(kubernetesProvider, podExactRegex)
|
|
||||||
eventChan, errorChan := kubernetes.FilteredWatch(ctx, podWatchHelper, []string{config.Config.MizuResourcesNamespace}, podWatchHelper)
|
|
||||||
|
|
||||||
timeAfter := time.After(30 * time.Second)
|
|
||||||
|
|
||||||
for {
|
|
||||||
select {
|
|
||||||
case wEvent, ok := <-eventChan:
|
|
||||||
if !ok {
|
|
||||||
eventChan = nil
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
pod, err := wEvent.ToPod()
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
if pod.Status.Phase == core.PodRunning {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
case err, ok := <-errorChan:
|
|
||||||
if !ok {
|
|
||||||
errorChan = nil
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
return err
|
|
||||||
case <-timeAfter:
|
|
||||||
return fmt.Errorf("image not pulled in time")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func removeImagePullInClusterResources(ctx context.Context, kubernetesProvider *kubernetes.Provider, podName string) {
|
|
||||||
if err := kubernetesProvider.RemovePod(ctx, config.Config.MizuResourcesNamespace, podName); err != nil {
|
|
||||||
logger.Log.Debugf("error while removing image pull in cluster resources, err: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !config.Config.IsNsRestrictedMode() {
|
|
||||||
if err := kubernetesProvider.RemoveNamespace(ctx, config.Config.MizuResourcesNamespace); err != nil {
|
|
||||||
logger.Log.Debugf("error while removing image pull in cluster resources, err: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func createImagePullInClusterResources(ctx context.Context, kubernetesProvider *kubernetes.Provider, podName string) error {
|
|
||||||
if !config.Config.IsNsRestrictedMode() {
|
|
||||||
if _, err := kubernetesProvider.CreateNamespace(ctx, config.Config.MizuResourcesNamespace); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var zero int64
|
|
||||||
pod := &core.Pod{
|
|
||||||
ObjectMeta: metav1.ObjectMeta{
|
|
||||||
Name: podName,
|
|
||||||
},
|
|
||||||
Spec: core.PodSpec{
|
|
||||||
Containers: []core.Container{
|
|
||||||
{
|
|
||||||
Name: "probe",
|
|
||||||
Image: "up9inc/busybox",
|
|
||||||
ImagePullPolicy: "Always",
|
|
||||||
Command: []string{"cat"},
|
|
||||||
Stdin: true,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
TerminationGracePeriodSeconds: &zero,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err := kubernetesProvider.CreatePod(ctx, config.Config.MizuResourcesNamespace, pod); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -40,7 +40,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,omitempty" default:"false" readonly:""`
|
OAS bool `yaml:"oas" default:"true"`
|
||||||
Elastic shared.ElasticConfig `yaml:"elastic"`
|
Elastic shared.ElasticConfig `yaml:"elastic"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,13 @@
|
|||||||
package configStructs
|
package configStructs
|
||||||
|
|
||||||
const (
|
const (
|
||||||
PreTapCheckName = "pre-tap"
|
PreTapCheckName = "pre-tap"
|
||||||
|
PreInstallCheckName = "pre-install"
|
||||||
|
ImagePullCheckName = "image-pull"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CheckConfig struct {
|
type CheckConfig struct {
|
||||||
PreTap bool `yaml:"pre-tap"`
|
PreTap bool `yaml:"pre-tap"`
|
||||||
|
PreInstall bool `yaml:"pre-install"`
|
||||||
|
ImagePull bool `yaml:"image-pull"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ require (
|
|||||||
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/basenine/server/lib v0.0.0-20220315070758-3a76cfc4378e
|
github.com/up9inc/basenine/server/lib v0.0.0-20220326121918-785f3061c8ce
|
||||||
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
|
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8
|
||||||
|
|||||||
@@ -600,8 +600,8 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69
|
|||||||
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=
|
||||||
github.com/up9inc/basenine/server/lib v0.0.0-20220315070758-3a76cfc4378e h1:reG/QwyxdfvGObfdrae7DZc3rTMiGwQ6S/4PRkwtBoE=
|
github.com/up9inc/basenine/server/lib v0.0.0-20220326121918-785f3061c8ce h1:PypqybjmuxftGkX4NmP4JAUyEykZj2r6W4r9lnRZ/kE=
|
||||||
github.com/up9inc/basenine/server/lib v0.0.0-20220315070758-3a76cfc4378e/go.mod h1:ZIkxWiJm65jYQIso9k+OZKhR7gQ1we2jNyE2kQX9IQI=
|
github.com/up9inc/basenine/server/lib v0.0.0-20220326121918-785f3061c8ce/go.mod h1:ZIkxWiJm65jYQIso9k+OZKhR7gQ1we2jNyE2kQX9IQI=
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||||
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
|
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
|
||||||
github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk=
|
github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk=
|
||||||
|
|||||||
@@ -1,18 +1,20 @@
|
|||||||
FROM dockcross/linux-arm64-musl:latest AS builder-from-amd64-to-arm64v8
|
FROM dockcross/linux-arm64-musl:latest AS builder-from-amd64-to-arm64v8
|
||||||
|
|
||||||
# Install Go
|
# Install Go
|
||||||
RUN curl https://go.dev/dl/go1.17.6.linux-amd64.tar.gz -Lo ./go.linux-amd64.tar.gz
|
RUN curl https://go.dev/dl/go1.17.6.linux-amd64.tar.gz -Lo ./go.linux-amd64.tar.gz \
|
||||||
RUN curl https://go.dev/dl/go1.17.6.linux-amd64.tar.gz.asc -Lo ./go.linux-amd64.tar.gz.asc
|
&& curl https://go.dev/dl/go1.17.6.linux-amd64.tar.gz.asc -Lo ./go.linux-amd64.tar.gz.asc \
|
||||||
RUN 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 \
|
||||||
RUN gpg --import linux_signing_key.pub && gpg --verify ./go.linux-amd64.tar.gz.asc ./go.linux-amd64.tar.gz
|
&& gpg --import linux_signing_key.pub && gpg --verify ./go.linux-amd64.tar.gz.asc ./go.linux-amd64.tar.gz \
|
||||||
RUN rm -rf /usr/local/go && tar -C /usr/local -xzf go.linux-amd64.tar.gz
|
&& rm -rf /usr/local/go && tar -C /usr/local -xzf go.linux-amd64.tar.gz
|
||||||
ENV PATH "$PATH:/usr/local/go/bin"
|
ENV PATH "$PATH:/usr/local/go/bin"
|
||||||
|
|
||||||
# Compile libpcap from source
|
# Compile libpcap from source
|
||||||
RUN curl https://www.tcpdump.org/release/libpcap-1.10.1.tar.gz -Lo ./libpcap.tar.gz
|
RUN curl https://www.tcpdump.org/release/libpcap-1.10.1.tar.gz -Lo ./libpcap.tar.gz \
|
||||||
RUN curl https://www.tcpdump.org/release/libpcap-1.10.1.tar.gz.sig -Lo ./libpcap.tar.gz.sig
|
&& curl https://www.tcpdump.org/release/libpcap-1.10.1.tar.gz.sig -Lo ./libpcap.tar.gz.sig \
|
||||||
RUN curl https://www.tcpdump.org/release/signing-key.asc -Lo ./signing-key.asc
|
&& curl https://www.tcpdump.org/release/signing-key.asc -Lo ./signing-key.asc \
|
||||||
RUN gpg --import signing-key.asc && gpg --verify libpcap.tar.gz.sig libpcap.tar.gz
|
&& gpg --import signing-key.asc && gpg --verify libpcap.tar.gz.sig libpcap.tar.gz \
|
||||||
RUN tar -xzf libpcap.tar.gz && mv ./libpcap-* ./libpcap
|
&& tar -xzf libpcap.tar.gz && mv ./libpcap-* ./libpcap
|
||||||
RUN cd ./libpcap && ./configure --host=arm && make
|
WORKDIR /work/libpcap
|
||||||
RUN cp /work/libpcap/libpcap.a /usr/xcc/aarch64-linux-musl-cross/lib/gcc/aarch64-linux-musl/*/
|
RUN ./configure --host=arm && make \
|
||||||
|
&& cp /work/libpcap/libpcap.a /usr/xcc/aarch64-linux-musl-cross/lib/gcc/aarch64-linux-musl/*/
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ const (
|
|||||||
SyncEntriesConfigEnvVar = "SYNC_ENTRIES_CONFIG"
|
SyncEntriesConfigEnvVar = "SYNC_ENTRIES_CONFIG"
|
||||||
HostModeEnvVar = "HOST_MODE"
|
HostModeEnvVar = "HOST_MODE"
|
||||||
NodeNameEnvVar = "NODE_NAME"
|
NodeNameEnvVar = "NODE_NAME"
|
||||||
TappedAddressesPerNodeDictEnvVar = "TAPPED_ADDRESSES_PER_HOST"
|
|
||||||
ConfigDirPath = "/app/config/"
|
ConfigDirPath = "/app/config/"
|
||||||
DataDirPath = "/app/data/"
|
DataDirPath = "/app/data/"
|
||||||
ValidationRulesFileName = "validation-rules.yaml"
|
ValidationRulesFileName = "validation-rules.yaml"
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ type MizuTapperSyncer struct {
|
|||||||
TapPodChangesOut chan TappedPodChangeEvent
|
TapPodChangesOut chan TappedPodChangeEvent
|
||||||
TapperStatusChangedOut chan shared.TapperStatus
|
TapperStatusChangedOut chan shared.TapperStatus
|
||||||
ErrorOut chan K8sTapManagerError
|
ErrorOut chan K8sTapManagerError
|
||||||
nodeToTappedPodMap map[string][]core.Pod
|
nodeToTappedPodMap shared.NodeToPodsMap
|
||||||
|
tappedNodes []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type TapperSyncerConfig struct {
|
type TapperSyncerConfig struct {
|
||||||
@@ -94,10 +95,6 @@ func (tapperSyncer *MizuTapperSyncer) watchTapperPods() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if tapperSyncer.startTime.After(pod.CreationTimestamp.Time) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Log.Debugf("Watching tapper pods loop, tapper: %v, node: %v, status: %v", pod.Name, pod.Spec.NodeName, pod.Status.Phase)
|
logger.Log.Debugf("Watching tapper pods loop, tapper: %v, node: %v, status: %v", pod.Name, pod.Spec.NodeName, pod.Status.Phase)
|
||||||
if pod.Spec.NodeName != "" {
|
if pod.Spec.NodeName != "" {
|
||||||
tapperStatus := shared.TapperStatus{TapperName: pod.Name, NodeName: pod.Spec.NodeName, Status: string(pod.Status.Phase)}
|
tapperStatus := shared.TapperStatus{TapperName: pod.Name, NodeName: pod.Spec.NodeName, Status: string(pod.Status.Phase)}
|
||||||
@@ -137,10 +134,6 @@ func (tapperSyncer *MizuTapperSyncer) watchTapperEvents() {
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
if tapperSyncer.startTime.After(event.CreationTimestamp.Time) {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
logger.Log.Debugf(
|
logger.Log.Debugf(
|
||||||
fmt.Sprintf("Watching tapper events loop, event %s, time: %v, resource: %s (%s), reason: %s, note: %s",
|
fmt.Sprintf("Watching tapper events loop, event %s, time: %v, resource: %s (%s), reason: %s, note: %s",
|
||||||
event.Name,
|
event.Name,
|
||||||
@@ -185,7 +178,7 @@ func (tapperSyncer *MizuTapperSyncer) watchPodsForTapping() {
|
|||||||
podWatchHelper := NewPodWatchHelper(tapperSyncer.kubernetesProvider, &tapperSyncer.config.PodFilterRegex)
|
podWatchHelper := NewPodWatchHelper(tapperSyncer.kubernetesProvider, &tapperSyncer.config.PodFilterRegex)
|
||||||
eventChan, errorChan := FilteredWatch(tapperSyncer.context, podWatchHelper, tapperSyncer.config.TargetNamespaces, podWatchHelper)
|
eventChan, errorChan := FilteredWatch(tapperSyncer.context, podWatchHelper, tapperSyncer.config.TargetNamespaces, podWatchHelper)
|
||||||
|
|
||||||
restartTappers := func() {
|
handleChangeInPods := func() {
|
||||||
err, changeFound := tapperSyncer.updateCurrentlyTappedPods()
|
err, changeFound := tapperSyncer.updateCurrentlyTappedPods()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
tapperSyncer.ErrorOut <- K8sTapManagerError{
|
tapperSyncer.ErrorOut <- K8sTapManagerError{
|
||||||
@@ -205,7 +198,7 @@ func (tapperSyncer *MizuTapperSyncer) watchPodsForTapping() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
restartTappersDebouncer := debounce.NewDebouncer(updateTappersDelay, restartTappers)
|
restartTappersDebouncer := debounce.NewDebouncer(updateTappersDelay, handleChangeInPods)
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
@@ -303,6 +296,20 @@ func (tapperSyncer *MizuTapperSyncer) updateCurrentlyTappedPods() (err error, ch
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (tapperSyncer *MizuTapperSyncer) updateMizuTappers() error {
|
func (tapperSyncer *MizuTapperSyncer) updateMizuTappers() error {
|
||||||
|
nodesToTap := make([]string, len(tapperSyncer.nodeToTappedPodMap))
|
||||||
|
i := 0
|
||||||
|
for node := range tapperSyncer.nodeToTappedPodMap {
|
||||||
|
nodesToTap[i] = node
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
|
||||||
|
if shared.EqualStringSlices(nodesToTap, tapperSyncer.tappedNodes) {
|
||||||
|
logger.Log.Debug("Skipping apply, DaemonSet is up to date")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.Log.Debugf("Updating DaemonSet to run on nodes: %v", nodesToTap)
|
||||||
|
|
||||||
if len(tapperSyncer.nodeToTappedPodMap) > 0 {
|
if len(tapperSyncer.nodeToTappedPodMap) > 0 {
|
||||||
var serviceAccountName string
|
var serviceAccountName string
|
||||||
if tapperSyncer.config.MizuServiceAccountExists {
|
if tapperSyncer.config.MizuServiceAccountExists {
|
||||||
@@ -311,6 +318,11 @@ func (tapperSyncer *MizuTapperSyncer) updateMizuTappers() error {
|
|||||||
serviceAccountName = ""
|
serviceAccountName = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nodeNames := make([]string, 0, len(tapperSyncer.nodeToTappedPodMap))
|
||||||
|
for nodeName := range tapperSyncer.nodeToTappedPodMap {
|
||||||
|
nodeNames = append(nodeNames, nodeName)
|
||||||
|
}
|
||||||
|
|
||||||
if err := tapperSyncer.kubernetesProvider.ApplyMizuTapperDaemonSet(
|
if err := tapperSyncer.kubernetesProvider.ApplyMizuTapperDaemonSet(
|
||||||
tapperSyncer.context,
|
tapperSyncer.context,
|
||||||
tapperSyncer.config.MizuResourcesNamespace,
|
tapperSyncer.config.MizuResourcesNamespace,
|
||||||
@@ -318,7 +330,7 @@ func (tapperSyncer *MizuTapperSyncer) updateMizuTappers() error {
|
|||||||
tapperSyncer.config.AgentImage,
|
tapperSyncer.config.AgentImage,
|
||||||
TapperPodName,
|
TapperPodName,
|
||||||
fmt.Sprintf("%s.%s.svc.cluster.local", ApiServerPodName, tapperSyncer.config.MizuResourcesNamespace),
|
fmt.Sprintf("%s.%s.svc.cluster.local", ApiServerPodName, tapperSyncer.config.MizuResourcesNamespace),
|
||||||
tapperSyncer.nodeToTappedPodMap,
|
nodeNames,
|
||||||
serviceAccountName,
|
serviceAccountName,
|
||||||
tapperSyncer.config.TapperResources,
|
tapperSyncer.config.TapperResources,
|
||||||
tapperSyncer.config.ImagePullPolicy,
|
tapperSyncer.config.ImagePullPolicy,
|
||||||
@@ -343,5 +355,7 @@ func (tapperSyncer *MizuTapperSyncer) updateMizuTappers() error {
|
|||||||
logger.Log.Debugf("Successfully reset tapper daemon set")
|
logger.Log.Debugf("Successfully reset tapper daemon set")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tapperSyncer.tappedNodes = nodesToTap
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -708,18 +708,13 @@ func (provider *Provider) CreateConfigMap(ctx context.Context, namespace string,
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider *Provider) ApplyMizuTapperDaemonSet(ctx context.Context, namespace string, daemonSetName string, podImage string, tapperPodName string, apiServerPodIp string, nodeToTappedPodMap map[string][]core.Pod, serviceAccountName string, resources shared.Resources, imagePullPolicy core.PullPolicy, mizuApiFilteringOptions api.TrafficFilteringOptions, logLevel logging.Level, serviceMesh bool, tls bool) error {
|
func (provider *Provider) ApplyMizuTapperDaemonSet(ctx context.Context, namespace string, daemonSetName string, podImage string, tapperPodName string, apiServerPodIp string, nodeNames []string, serviceAccountName string, resources shared.Resources, imagePullPolicy core.PullPolicy, mizuApiFilteringOptions api.TrafficFilteringOptions, logLevel logging.Level, serviceMesh bool, tls bool) error {
|
||||||
logger.Log.Debugf("Applying %d tapper daemon sets, ns: %s, daemonSetName: %s, podImage: %s, tapperPodName: %s", len(nodeToTappedPodMap), namespace, daemonSetName, podImage, tapperPodName)
|
logger.Log.Debugf("Applying %d tapper daemon sets, ns: %s, daemonSetName: %s, podImage: %s, tapperPodName: %s", len(nodeNames), namespace, daemonSetName, podImage, tapperPodName)
|
||||||
|
|
||||||
if len(nodeToTappedPodMap) == 0 {
|
if len(nodeNames) == 0 {
|
||||||
return fmt.Errorf("daemon set %s must tap at least 1 pod", daemonSetName)
|
return fmt.Errorf("daemon set %s must tap at least 1 pod", daemonSetName)
|
||||||
}
|
}
|
||||||
|
|
||||||
nodeToTappedPodMapJsonStr, err := json.Marshal(nodeToTappedPodMap)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
mizuApiFilteringOptionsJsonStr, err := json.Marshal(mizuApiFilteringOptions)
|
mizuApiFilteringOptionsJsonStr, err := json.Marshal(mizuApiFilteringOptions)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -773,7 +768,6 @@ func (provider *Provider) ApplyMizuTapperDaemonSet(ctx context.Context, namespac
|
|||||||
agentContainer.WithEnv(
|
agentContainer.WithEnv(
|
||||||
applyconfcore.EnvVar().WithName(shared.LogLevelEnvVar).WithValue(logLevel.String()),
|
applyconfcore.EnvVar().WithName(shared.LogLevelEnvVar).WithValue(logLevel.String()),
|
||||||
applyconfcore.EnvVar().WithName(shared.HostModeEnvVar).WithValue("1"),
|
applyconfcore.EnvVar().WithName(shared.HostModeEnvVar).WithValue("1"),
|
||||||
applyconfcore.EnvVar().WithName(shared.TappedAddressesPerNodeDictEnvVar).WithValue(string(nodeToTappedPodMapJsonStr)),
|
|
||||||
applyconfcore.EnvVar().WithName(shared.GoGCEnvVar).WithValue("12800"),
|
applyconfcore.EnvVar().WithName(shared.GoGCEnvVar).WithValue("12800"),
|
||||||
applyconfcore.EnvVar().WithName(shared.MizuFilteringOptionsEnvVar).WithValue(string(mizuApiFilteringOptionsJsonStr)),
|
applyconfcore.EnvVar().WithName(shared.MizuFilteringOptionsEnvVar).WithValue(string(mizuApiFilteringOptionsJsonStr)),
|
||||||
)
|
)
|
||||||
@@ -811,10 +805,6 @@ func (provider *Provider) ApplyMizuTapperDaemonSet(ctx context.Context, namespac
|
|||||||
agentResources := applyconfcore.ResourceRequirements().WithRequests(agentResourceRequests).WithLimits(agentResourceLimits)
|
agentResources := applyconfcore.ResourceRequirements().WithRequests(agentResourceRequests).WithLimits(agentResourceLimits)
|
||||||
agentContainer.WithResources(agentResources)
|
agentContainer.WithResources(agentResources)
|
||||||
|
|
||||||
nodeNames := make([]string, 0, len(nodeToTappedPodMap))
|
|
||||||
for nodeName := range nodeToTappedPodMap {
|
|
||||||
nodeNames = append(nodeNames, nodeName)
|
|
||||||
}
|
|
||||||
nodeSelectorRequirement := applyconfcore.NodeSelectorRequirement()
|
nodeSelectorRequirement := applyconfcore.NodeSelectorRequirement()
|
||||||
nodeSelectorRequirement.WithKey("kubernetes.io/hostname")
|
nodeSelectorRequirement.WithKey("kubernetes.io/hostname")
|
||||||
nodeSelectorRequirement.WithOperator(core.NodeSelectorOpIn)
|
nodeSelectorRequirement.WithOperator(core.NodeSelectorOpIn)
|
||||||
|
|||||||
@@ -5,12 +5,11 @@ import (
|
|||||||
|
|
||||||
"github.com/up9inc/mizu/shared"
|
"github.com/up9inc/mizu/shared"
|
||||||
core "k8s.io/api/core/v1"
|
core "k8s.io/api/core/v1"
|
||||||
v1 "k8s.io/api/core/v1"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
func GetNodeHostToTappedPodsMap(tappedPods []core.Pod) map[string][]core.Pod {
|
func GetNodeHostToTappedPodsMap(tappedPods []core.Pod) shared.NodeToPodsMap {
|
||||||
nodeToTappedPodMap := make(map[string][]core.Pod)
|
nodeToTappedPodMap := make(shared.NodeToPodsMap)
|
||||||
for _, pod := range tappedPods {
|
for _, pod := range tappedPods {
|
||||||
minimizedPod := getMinimizedPod(pod)
|
minimizedPod := getMinimizedPod(pod)
|
||||||
|
|
||||||
@@ -29,18 +28,18 @@ func getMinimizedPod(fullPod core.Pod) core.Pod {
|
|||||||
ObjectMeta: metav1.ObjectMeta{
|
ObjectMeta: metav1.ObjectMeta{
|
||||||
Name: fullPod.Name,
|
Name: fullPod.Name,
|
||||||
},
|
},
|
||||||
Status: v1.PodStatus{
|
Status: core.PodStatus{
|
||||||
PodIP: fullPod.Status.PodIP,
|
PodIP: fullPod.Status.PodIP,
|
||||||
ContainerStatuses: getMinimizedContainerStatuses(fullPod),
|
ContainerStatuses: getMinimizedContainerStatuses(fullPod),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getMinimizedContainerStatuses(fullPod core.Pod) []v1.ContainerStatus {
|
func getMinimizedContainerStatuses(fullPod core.Pod) []core.ContainerStatus {
|
||||||
result := make([]v1.ContainerStatus, len(fullPod.Status.ContainerStatuses))
|
result := make([]core.ContainerStatus, len(fullPod.Status.ContainerStatuses))
|
||||||
|
|
||||||
for i, container := range fullPod.Status.ContainerStatuses {
|
for i, container := range fullPod.Status.ContainerStatuses {
|
||||||
result[i] = v1.ContainerStatus{
|
result[i] = core.ContainerStatus{
|
||||||
ContainerID: container.ContainerID,
|
ContainerID: container.ContainerID,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,24 +6,25 @@ import (
|
|||||||
|
|
||||||
"github.com/op/go-logging"
|
"github.com/op/go-logging"
|
||||||
"github.com/up9inc/mizu/shared/logger"
|
"github.com/up9inc/mizu/shared/logger"
|
||||||
v1 "k8s.io/api/core/v1"
|
|
||||||
|
|
||||||
"gopkg.in/yaml.v3"
|
"gopkg.in/yaml.v3"
|
||||||
|
v1 "k8s.io/api/core/v1"
|
||||||
)
|
)
|
||||||
|
|
||||||
type WebSocketMessageType string
|
type WebSocketMessageType string
|
||||||
|
|
||||||
const (
|
const (
|
||||||
WebSocketMessageTypeEntry WebSocketMessageType = "entry"
|
WebSocketMessageTypeEntry WebSocketMessageType = "entry"
|
||||||
WebSocketMessageTypeFullEntry WebSocketMessageType = "fullEntry"
|
WebSocketMessageTypeFullEntry WebSocketMessageType = "fullEntry"
|
||||||
WebSocketMessageTypeTappedEntry WebSocketMessageType = "tappedEntry"
|
WebSocketMessageTypeTappedEntry WebSocketMessageType = "tappedEntry"
|
||||||
WebSocketMessageTypeUpdateStatus WebSocketMessageType = "status"
|
WebSocketMessageTypeUpdateStatus WebSocketMessageType = "status"
|
||||||
WebSocketMessageTypeAnalyzeStatus WebSocketMessageType = "analyzeStatus"
|
WebSocketMessageTypeUpdateTappedPods WebSocketMessageType = "tappedPods"
|
||||||
WebsocketMessageTypeOutboundLink WebSocketMessageType = "outboundLink"
|
WebSocketMessageTypeAnalyzeStatus WebSocketMessageType = "analyzeStatus"
|
||||||
WebSocketMessageTypeToast WebSocketMessageType = "toast"
|
WebsocketMessageTypeOutboundLink WebSocketMessageType = "outboundLink"
|
||||||
WebSocketMessageTypeQueryMetadata WebSocketMessageType = "queryMetadata"
|
WebSocketMessageTypeToast WebSocketMessageType = "toast"
|
||||||
WebSocketMessageTypeStartTime WebSocketMessageType = "startTime"
|
WebSocketMessageTypeQueryMetadata WebSocketMessageType = "queryMetadata"
|
||||||
WebSocketMessageTypeTapConfig WebSocketMessageType = "tapConfig"
|
WebSocketMessageTypeStartTime WebSocketMessageType = "startTime"
|
||||||
|
WebSocketMessageTypeTapConfig WebSocketMessageType = "tapConfig"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Resources struct {
|
type Resources struct {
|
||||||
@@ -75,11 +76,29 @@ type WebSocketStatusMessage struct {
|
|||||||
TappingStatus []TappedPodStatus `json:"tappingStatus"`
|
TappingStatus []TappedPodStatus `json:"tappingStatus"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type WebSocketTappedPodsMessage struct {
|
||||||
|
*WebSocketMessageMetadata
|
||||||
|
NodeToTappedPodMap NodeToPodsMap `json:"nodeToTappedPodMap"`
|
||||||
|
}
|
||||||
|
|
||||||
type WebSocketTapConfigMessage struct {
|
type WebSocketTapConfigMessage struct {
|
||||||
*WebSocketMessageMetadata
|
*WebSocketMessageMetadata
|
||||||
TapTargets []v1.Pod `json:"pods"`
|
TapTargets []v1.Pod `json:"pods"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type NodeToPodsMap map[string][]v1.Pod
|
||||||
|
|
||||||
|
func (np NodeToPodsMap) Summary() map[string][]string {
|
||||||
|
summary := make(map[string][]string)
|
||||||
|
for node, pods := range np {
|
||||||
|
for _, pod := range pods {
|
||||||
|
summary[node] = append(summary[node], pod.Namespace + "/" + pod.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return summary
|
||||||
|
}
|
||||||
|
|
||||||
type TapperStatus struct {
|
type TapperStatus struct {
|
||||||
TapperName string `json:"tapperName"`
|
TapperName string `json:"tapperName"`
|
||||||
NodeName string `json:"nodeName"`
|
NodeName string `json:"nodeName"`
|
||||||
@@ -121,6 +140,15 @@ func CreateWebSocketStatusMessage(tappedPodsStatus []TappedPodStatus) WebSocketS
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CreateWebSocketTappedPodsMessage(nodeToTappedPodMap NodeToPodsMap) WebSocketTappedPodsMessage {
|
||||||
|
return WebSocketTappedPodsMessage{
|
||||||
|
WebSocketMessageMetadata: &WebSocketMessageMetadata{
|
||||||
|
MessageType: WebSocketMessageTypeUpdateTappedPods,
|
||||||
|
},
|
||||||
|
NodeToTappedPodMap: nodeToTappedPodMap,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func CreateWebSocketMessageTypeAnalyzeStatus(analyzeStatus AnalyzeStatus) WebSocketAnalyzeStatusMessage {
|
func CreateWebSocketMessageTypeAnalyzeStatus(analyzeStatus AnalyzeStatus) WebSocketAnalyzeStatusMessage {
|
||||||
return WebSocketAnalyzeStatusMessage{
|
return WebSocketAnalyzeStatusMessage{
|
||||||
WebSocketMessageMetadata: &WebSocketMessageMetadata{
|
WebSocketMessageMetadata: &WebSocketMessageMetadata{
|
||||||
|
|||||||
@@ -32,3 +32,17 @@ func Unique(slice []string) []string {
|
|||||||
|
|
||||||
return list
|
return list
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func EqualStringSlices(slice1 []string, slice2 []string) bool {
|
||||||
|
if len(slice1) != len(slice2) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range slice1 {
|
||||||
|
if !Contains(slice2, v) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import (
|
|||||||
|
|
||||||
const mizuTestEnvVar = "MIZU_TEST"
|
const mizuTestEnvVar = "MIZU_TEST"
|
||||||
|
|
||||||
var UnknownIp net.IP = net.IP{0, 0, 0, 0}
|
var UnknownIp net.IP = net.IP{0, 0, 0, 0}
|
||||||
var UnknownPort uint16 = 0
|
var UnknownPort uint16 = 0
|
||||||
|
|
||||||
type Protocol struct {
|
type Protocol struct {
|
||||||
@@ -48,6 +48,16 @@ type Extension struct {
|
|||||||
Dissector Dissector
|
Dissector Dissector
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Capture string
|
||||||
|
|
||||||
|
const (
|
||||||
|
UndefinedCapture Capture = ""
|
||||||
|
Pcap Capture = "pcap"
|
||||||
|
Envoy Capture = "envoy"
|
||||||
|
Linkerd Capture = "linkerd"
|
||||||
|
Ebpf Capture = "ebpf"
|
||||||
|
)
|
||||||
|
|
||||||
type ConnectionInfo struct {
|
type ConnectionInfo struct {
|
||||||
ClientIP string
|
ClientIP string
|
||||||
ClientPort string
|
ClientPort string
|
||||||
@@ -73,6 +83,7 @@ type CounterPair struct {
|
|||||||
type GenericMessage struct {
|
type GenericMessage struct {
|
||||||
IsRequest bool `json:"isRequest"`
|
IsRequest bool `json:"isRequest"`
|
||||||
CaptureTime time.Time `json:"captureTime"`
|
CaptureTime time.Time `json:"captureTime"`
|
||||||
|
CaptureSize int `json:"captureSize"`
|
||||||
Payload interface{} `json:"payload"`
|
Payload interface{} `json:"payload"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,6 +95,7 @@ type RequestResponsePair struct {
|
|||||||
// `Protocol` is modified in the later stages of data propagation. Therefore it's not a pointer.
|
// `Protocol` is modified in the later stages of data propagation. Therefore it's not a pointer.
|
||||||
type OutputChannelItem struct {
|
type OutputChannelItem struct {
|
||||||
Protocol Protocol
|
Protocol Protocol
|
||||||
|
Capture Capture
|
||||||
Timestamp int64
|
Timestamp int64
|
||||||
ConnectionInfo *ConnectionInfo
|
ConnectionInfo *ConnectionInfo
|
||||||
Pair *RequestResponsePair
|
Pair *RequestResponsePair
|
||||||
@@ -99,13 +111,27 @@ type SuperIdentifier struct {
|
|||||||
IsClosedOthers bool
|
IsClosedOthers bool
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ReadProgress struct {
|
||||||
|
readBytes int
|
||||||
|
lastCurrent int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ReadProgress) Feed(n int) {
|
||||||
|
p.readBytes += n
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *ReadProgress) Current() (n int) {
|
||||||
|
p.lastCurrent = p.readBytes - p.lastCurrent
|
||||||
|
return p.lastCurrent
|
||||||
|
}
|
||||||
|
|
||||||
type Dissector interface {
|
type Dissector interface {
|
||||||
Register(*Extension)
|
Register(*Extension)
|
||||||
Ping()
|
Ping()
|
||||||
Dissect(b *bufio.Reader, isClient bool, tcpID *TcpID, counterPair *CounterPair, superTimer *SuperTimer, superIdentifier *SuperIdentifier, emitter Emitter, options *TrafficFilteringOptions, reqResMatcher RequestResponseMatcher) error
|
Dissect(b *bufio.Reader, progress *ReadProgress, capture Capture, isClient bool, tcpID *TcpID, counterPair *CounterPair, superTimer *SuperTimer, superIdentifier *SuperIdentifier, emitter Emitter, options *TrafficFilteringOptions, reqResMatcher RequestResponseMatcher) error
|
||||||
Analyze(item *OutputChannelItem, resolvedSource string, resolvedDestination string, namespace string) *Entry
|
Analyze(item *OutputChannelItem, resolvedSource string, resolvedDestination string, namespace string) *Entry
|
||||||
Summarize(entry *Entry) *BaseEntry
|
Summarize(entry *Entry) *BaseEntry
|
||||||
Represent(request map[string]interface{}, response map[string]interface{}) (object []byte, bodySize int64, err error)
|
Represent(request map[string]interface{}, response map[string]interface{}) (object []byte, err error)
|
||||||
Macros() map[string]string
|
Macros() map[string]string
|
||||||
NewResponseRequestMatcher() RequestResponseMatcher
|
NewResponseRequestMatcher() RequestResponseMatcher
|
||||||
}
|
}
|
||||||
@@ -132,6 +158,7 @@ func (e *Emitting) Emit(item *OutputChannelItem) {
|
|||||||
type Entry struct {
|
type Entry struct {
|
||||||
Id uint `json:"id"`
|
Id uint `json:"id"`
|
||||||
Protocol Protocol `json:"proto"`
|
Protocol Protocol `json:"proto"`
|
||||||
|
Capture Capture `json:"capture"`
|
||||||
Source *TCP `json:"src"`
|
Source *TCP `json:"src"`
|
||||||
Destination *TCP `json:"dst"`
|
Destination *TCP `json:"dst"`
|
||||||
Namespace string `json:"namespace,omitempty"`
|
Namespace string `json:"namespace,omitempty"`
|
||||||
@@ -140,6 +167,8 @@ type Entry struct {
|
|||||||
StartTime time.Time `json:"startTime"`
|
StartTime time.Time `json:"startTime"`
|
||||||
Request map[string]interface{} `json:"request"`
|
Request map[string]interface{} `json:"request"`
|
||||||
Response map[string]interface{} `json:"response"`
|
Response map[string]interface{} `json:"response"`
|
||||||
|
RequestSize int `json:"requestSize"`
|
||||||
|
ResponseSize int `json:"responseSize"`
|
||||||
ElapsedTime int64 `json:"elapsedTime"`
|
ElapsedTime int64 `json:"elapsedTime"`
|
||||||
Rules ApplicableRules `json:"rules,omitempty"`
|
Rules ApplicableRules `json:"rules,omitempty"`
|
||||||
ContractStatus ContractStatus `json:"contractStatus,omitempty"`
|
ContractStatus ContractStatus `json:"contractStatus,omitempty"`
|
||||||
@@ -152,7 +181,6 @@ type Entry struct {
|
|||||||
type EntryWrapper struct {
|
type EntryWrapper struct {
|
||||||
Protocol Protocol `json:"protocol"`
|
Protocol Protocol `json:"protocol"`
|
||||||
Representation string `json:"representation"`
|
Representation string `json:"representation"`
|
||||||
BodySize int64 `json:"bodySize"`
|
|
||||||
Data *Entry `json:"data"`
|
Data *Entry `json:"data"`
|
||||||
Base *BaseEntry `json:"base"`
|
Base *BaseEntry `json:"base"`
|
||||||
Rules []map[string]interface{} `json:"rulesMatched,omitempty"`
|
Rules []map[string]interface{} `json:"rulesMatched,omitempty"`
|
||||||
@@ -162,6 +190,7 @@ type EntryWrapper struct {
|
|||||||
type BaseEntry struct {
|
type BaseEntry struct {
|
||||||
Id uint `json:"id"`
|
Id uint `json:"id"`
|
||||||
Protocol Protocol `json:"proto,omitempty"`
|
Protocol Protocol `json:"proto,omitempty"`
|
||||||
|
Capture Capture `json:"capture"`
|
||||||
Summary string `json:"summary,omitempty"`
|
Summary string `json:"summary,omitempty"`
|
||||||
SummaryQuery string `json:"summaryQuery,omitempty"`
|
SummaryQuery string `json:"summaryQuery,omitempty"`
|
||||||
Status int `json:"status"`
|
Status int `json:"status"`
|
||||||
|
|||||||
@@ -13,4 +13,4 @@ test-pull-bin:
|
|||||||
|
|
||||||
test-pull-expect:
|
test-pull-expect:
|
||||||
@mkdir -p expect
|
@mkdir -p expect
|
||||||
@[ "${skipexpect}" ] && echo "Skipping downloading expected JSONs" || gsutil -o 'GSUtil:parallel_process_count=5' -o 'GSUtil:parallel_thread_count=5' -m cp -r gs://static.up9.io/mizu/test-pcap/expect3/amqp/\* expect
|
@[ "${skipexpect}" ] && echo "Skipping downloading expected JSONs" || gsutil -o 'GSUtil:parallel_process_count=5' -o 'GSUtil:parallel_thread_count=5' -m cp -r gs://static.up9.io/mizu/test-pcap/expect5/amqp/\* expect
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ type AMQPWrapper struct {
|
|||||||
Details interface{} `json:"details"`
|
Details interface{} `json:"details"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func emitAMQP(event interface{}, _type string, method string, connectionInfo *api.ConnectionInfo, captureTime time.Time, emitter api.Emitter) {
|
func emitAMQP(event interface{}, _type string, method string, connectionInfo *api.ConnectionInfo, captureTime time.Time, captureSize int, emitter api.Emitter, capture api.Capture) {
|
||||||
request := &api.GenericMessage{
|
request := &api.GenericMessage{
|
||||||
IsRequest: true,
|
IsRequest: true,
|
||||||
CaptureTime: captureTime,
|
CaptureTime: captureTime,
|
||||||
@@ -108,6 +108,7 @@ func emitAMQP(event interface{}, _type string, method string, connectionInfo *ap
|
|||||||
}
|
}
|
||||||
item := &api.OutputChannelItem{
|
item := &api.OutputChannelItem{
|
||||||
Protocol: protocol,
|
Protocol: protocol,
|
||||||
|
Capture: capture,
|
||||||
Timestamp: captureTime.UnixNano() / int64(time.Millisecond),
|
Timestamp: captureTime.UnixNano() / int64(time.Millisecond),
|
||||||
ConnectionInfo: connectionInfo,
|
ConnectionInfo: connectionInfo,
|
||||||
Pair: &api.RequestResponsePair{
|
Pair: &api.RequestResponsePair{
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ func (d dissecting) Ping() {
|
|||||||
|
|
||||||
const amqpRequest string = "amqp_request"
|
const amqpRequest string = "amqp_request"
|
||||||
|
|
||||||
func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, superIdentifier *api.SuperIdentifier, emitter api.Emitter, options *api.TrafficFilteringOptions, _reqResMatcher api.RequestResponseMatcher) error {
|
func (d dissecting) Dissect(b *bufio.Reader, progress *api.ReadProgress, capture api.Capture, isClient bool, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, superIdentifier *api.SuperIdentifier, emitter api.Emitter, options *api.TrafficFilteringOptions, _reqResMatcher api.RequestResponseMatcher) error {
|
||||||
r := AmqpReader{b}
|
r := AmqpReader{b}
|
||||||
|
|
||||||
var remaining int
|
var remaining int
|
||||||
@@ -113,11 +113,11 @@ func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, co
|
|||||||
case *BasicPublish:
|
case *BasicPublish:
|
||||||
eventBasicPublish.Body = f.Body
|
eventBasicPublish.Body = f.Body
|
||||||
superIdentifier.Protocol = &protocol
|
superIdentifier.Protocol = &protocol
|
||||||
emitAMQP(*eventBasicPublish, amqpRequest, basicMethodMap[40], connectionInfo, superTimer.CaptureTime, emitter)
|
emitAMQP(*eventBasicPublish, amqpRequest, basicMethodMap[40], connectionInfo, superTimer.CaptureTime, progress.Current(), emitter, capture)
|
||||||
case *BasicDeliver:
|
case *BasicDeliver:
|
||||||
eventBasicDeliver.Body = f.Body
|
eventBasicDeliver.Body = f.Body
|
||||||
superIdentifier.Protocol = &protocol
|
superIdentifier.Protocol = &protocol
|
||||||
emitAMQP(*eventBasicDeliver, amqpRequest, basicMethodMap[60], connectionInfo, superTimer.CaptureTime, emitter)
|
emitAMQP(*eventBasicDeliver, amqpRequest, basicMethodMap[60], connectionInfo, superTimer.CaptureTime, progress.Current(), emitter, capture)
|
||||||
}
|
}
|
||||||
|
|
||||||
case *MethodFrame:
|
case *MethodFrame:
|
||||||
@@ -138,7 +138,7 @@ func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, co
|
|||||||
Arguments: m.Arguments,
|
Arguments: m.Arguments,
|
||||||
}
|
}
|
||||||
superIdentifier.Protocol = &protocol
|
superIdentifier.Protocol = &protocol
|
||||||
emitAMQP(*eventQueueBind, amqpRequest, queueMethodMap[20], connectionInfo, superTimer.CaptureTime, emitter)
|
emitAMQP(*eventQueueBind, amqpRequest, queueMethodMap[20], connectionInfo, superTimer.CaptureTime, progress.Current(), emitter, capture)
|
||||||
|
|
||||||
case *BasicConsume:
|
case *BasicConsume:
|
||||||
eventBasicConsume := &BasicConsume{
|
eventBasicConsume := &BasicConsume{
|
||||||
@@ -151,7 +151,7 @@ func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, co
|
|||||||
Arguments: m.Arguments,
|
Arguments: m.Arguments,
|
||||||
}
|
}
|
||||||
superIdentifier.Protocol = &protocol
|
superIdentifier.Protocol = &protocol
|
||||||
emitAMQP(*eventBasicConsume, amqpRequest, basicMethodMap[20], connectionInfo, superTimer.CaptureTime, emitter)
|
emitAMQP(*eventBasicConsume, amqpRequest, basicMethodMap[20], connectionInfo, superTimer.CaptureTime, progress.Current(), emitter, capture)
|
||||||
|
|
||||||
case *BasicDeliver:
|
case *BasicDeliver:
|
||||||
eventBasicDeliver.ConsumerTag = m.ConsumerTag
|
eventBasicDeliver.ConsumerTag = m.ConsumerTag
|
||||||
@@ -171,7 +171,7 @@ func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, co
|
|||||||
Arguments: m.Arguments,
|
Arguments: m.Arguments,
|
||||||
}
|
}
|
||||||
superIdentifier.Protocol = &protocol
|
superIdentifier.Protocol = &protocol
|
||||||
emitAMQP(*eventQueueDeclare, amqpRequest, queueMethodMap[10], connectionInfo, superTimer.CaptureTime, emitter)
|
emitAMQP(*eventQueueDeclare, amqpRequest, queueMethodMap[10], connectionInfo, superTimer.CaptureTime, progress.Current(), emitter, capture)
|
||||||
|
|
||||||
case *ExchangeDeclare:
|
case *ExchangeDeclare:
|
||||||
eventExchangeDeclare := &ExchangeDeclare{
|
eventExchangeDeclare := &ExchangeDeclare{
|
||||||
@@ -185,7 +185,7 @@ func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, co
|
|||||||
Arguments: m.Arguments,
|
Arguments: m.Arguments,
|
||||||
}
|
}
|
||||||
superIdentifier.Protocol = &protocol
|
superIdentifier.Protocol = &protocol
|
||||||
emitAMQP(*eventExchangeDeclare, amqpRequest, exchangeMethodMap[10], connectionInfo, superTimer.CaptureTime, emitter)
|
emitAMQP(*eventExchangeDeclare, amqpRequest, exchangeMethodMap[10], connectionInfo, superTimer.CaptureTime, progress.Current(), emitter, capture)
|
||||||
|
|
||||||
case *ConnectionStart:
|
case *ConnectionStart:
|
||||||
eventConnectionStart := &ConnectionStart{
|
eventConnectionStart := &ConnectionStart{
|
||||||
@@ -196,7 +196,7 @@ func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, co
|
|||||||
Locales: m.Locales,
|
Locales: m.Locales,
|
||||||
}
|
}
|
||||||
superIdentifier.Protocol = &protocol
|
superIdentifier.Protocol = &protocol
|
||||||
emitAMQP(*eventConnectionStart, amqpRequest, connectionMethodMap[10], connectionInfo, superTimer.CaptureTime, emitter)
|
emitAMQP(*eventConnectionStart, amqpRequest, connectionMethodMap[10], connectionInfo, superTimer.CaptureTime, progress.Current(), emitter, capture)
|
||||||
|
|
||||||
case *ConnectionClose:
|
case *ConnectionClose:
|
||||||
eventConnectionClose := &ConnectionClose{
|
eventConnectionClose := &ConnectionClose{
|
||||||
@@ -206,7 +206,7 @@ func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, co
|
|||||||
MethodId: m.MethodId,
|
MethodId: m.MethodId,
|
||||||
}
|
}
|
||||||
superIdentifier.Protocol = &protocol
|
superIdentifier.Protocol = &protocol
|
||||||
emitAMQP(*eventConnectionClose, amqpRequest, connectionMethodMap[50], connectionInfo, superTimer.CaptureTime, emitter)
|
emitAMQP(*eventConnectionClose, amqpRequest, connectionMethodMap[50], connectionInfo, superTimer.CaptureTime, progress.Current(), emitter, capture)
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -222,6 +222,7 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string,
|
|||||||
reqDetails["method"] = request["method"]
|
reqDetails["method"] = request["method"]
|
||||||
return &api.Entry{
|
return &api.Entry{
|
||||||
Protocol: protocol,
|
Protocol: protocol,
|
||||||
|
Capture: item.Capture,
|
||||||
Source: &api.TCP{
|
Source: &api.TCP{
|
||||||
Name: resolvedSource,
|
Name: resolvedSource,
|
||||||
IP: item.ConnectionInfo.ClientIP,
|
IP: item.ConnectionInfo.ClientIP,
|
||||||
@@ -235,6 +236,7 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string,
|
|||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
Outgoing: item.ConnectionInfo.IsOutgoing,
|
Outgoing: item.ConnectionInfo.IsOutgoing,
|
||||||
Request: reqDetails,
|
Request: reqDetails,
|
||||||
|
RequestSize: item.Pair.Request.CaptureSize,
|
||||||
Timestamp: item.Timestamp,
|
Timestamp: item.Timestamp,
|
||||||
StartTime: item.Pair.Request.CaptureTime,
|
StartTime: item.Pair.Request.CaptureTime,
|
||||||
ElapsedTime: 0,
|
ElapsedTime: 0,
|
||||||
@@ -283,6 +285,7 @@ func (d dissecting) Summarize(entry *api.Entry) *api.BaseEntry {
|
|||||||
return &api.BaseEntry{
|
return &api.BaseEntry{
|
||||||
Id: entry.Id,
|
Id: entry.Id,
|
||||||
Protocol: entry.Protocol,
|
Protocol: entry.Protocol,
|
||||||
|
Capture: entry.Capture,
|
||||||
Summary: summary,
|
Summary: summary,
|
||||||
SummaryQuery: summaryQuery,
|
SummaryQuery: summaryQuery,
|
||||||
Status: 0,
|
Status: 0,
|
||||||
@@ -299,8 +302,7 @@ func (d dissecting) Summarize(entry *api.Entry) *api.BaseEntry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d dissecting) Represent(request map[string]interface{}, response map[string]interface{}) (object []byte, bodySize int64, err error) {
|
func (d dissecting) Represent(request map[string]interface{}, response map[string]interface{}) (object []byte, err error) {
|
||||||
bodySize = 0
|
|
||||||
representation := make(map[string]interface{})
|
representation := make(map[string]interface{})
|
||||||
var repRequest []interface{}
|
var repRequest []interface{}
|
||||||
switch request["method"].(string) {
|
switch request["method"].(string) {
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ func TestDissect(t *testing.T) {
|
|||||||
DstPort: "2",
|
DstPort: "2",
|
||||||
}
|
}
|
||||||
reqResMatcher := dissector.NewResponseRequestMatcher()
|
reqResMatcher := dissector.NewResponseRequestMatcher()
|
||||||
err = dissector.Dissect(bufferClient, true, tcpIDClient, counterPair, &api.SuperTimer{}, superIdentifier, emitter, options, reqResMatcher)
|
err = dissector.Dissect(bufferClient, &api.ReadProgress{}, api.Pcap, true, tcpIDClient, counterPair, &api.SuperTimer{}, superIdentifier, emitter, options, reqResMatcher)
|
||||||
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -140,7 +140,7 @@ func TestDissect(t *testing.T) {
|
|||||||
SrcPort: "2",
|
SrcPort: "2",
|
||||||
DstPort: "1",
|
DstPort: "1",
|
||||||
}
|
}
|
||||||
err = dissector.Dissect(bufferServer, false, tcpIDServer, counterPair, &api.SuperTimer{}, superIdentifier, emitter, options, reqResMatcher)
|
err = dissector.Dissect(bufferServer, &api.ReadProgress{}, api.Pcap, false, tcpIDServer, counterPair, &api.SuperTimer{}, superIdentifier, emitter, options, reqResMatcher)
|
||||||
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -319,7 +319,7 @@ func TestRepresent(t *testing.T) {
|
|||||||
|
|
||||||
var objects []string
|
var objects []string
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
object, _, err := dissector.Represent(entry.Request, entry.Response)
|
object, err := dissector.Represent(entry.Request, entry.Response)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
objects = append(objects, string(object))
|
objects = append(objects, string(object))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,4 +13,4 @@ test-pull-bin:
|
|||||||
|
|
||||||
test-pull-expect:
|
test-pull-expect:
|
||||||
@mkdir -p expect
|
@mkdir -p expect
|
||||||
@[ "${skipexpect}" ] && echo "Skipping downloading expected JSONs" || gsutil -o 'GSUtil:parallel_process_count=5' -o 'GSUtil:parallel_thread_count=5' -m cp -r gs://static.up9.io/mizu/test-pcap/expect3/http/\* expect
|
@[ "${skipexpect}" ] && echo "Skipping downloading expected JSONs" || gsutil -o 'GSUtil:parallel_process_count=5' -o 'GSUtil:parallel_thread_count=5' -m cp -r gs://static.up9.io/mizu/test-pcap/expect5/http/\* expect
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ func replaceForwardedFor(item *api.OutputChannelItem) {
|
|||||||
item.ConnectionInfo.ClientPort = ""
|
item.ConnectionInfo.ClientPort = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleHTTP2Stream(http2Assembler *Http2Assembler, tcpID *api.TcpID, superTimer *api.SuperTimer, emitter api.Emitter, options *api.TrafficFilteringOptions, reqResMatcher *requestResponseMatcher) error {
|
func handleHTTP2Stream(http2Assembler *Http2Assembler, progress *api.ReadProgress, capture api.Capture, tcpID *api.TcpID, superTimer *api.SuperTimer, emitter api.Emitter, options *api.TrafficFilteringOptions, reqResMatcher *requestResponseMatcher) error {
|
||||||
streamID, messageHTTP1, isGrpc, err := http2Assembler.readMessage()
|
streamID, messageHTTP1, isGrpc, err := http2Assembler.readMessage()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
@@ -66,7 +66,7 @@ func handleHTTP2Stream(http2Assembler *Http2Assembler, tcpID *api.TcpID, superTi
|
|||||||
streamID,
|
streamID,
|
||||||
"HTTP2",
|
"HTTP2",
|
||||||
)
|
)
|
||||||
item = reqResMatcher.registerRequest(ident, &messageHTTP1, superTimer.CaptureTime, messageHTTP1.ProtoMinor)
|
item = reqResMatcher.registerRequest(ident, &messageHTTP1, superTimer.CaptureTime, progress.Current(), messageHTTP1.ProtoMinor)
|
||||||
if item != nil {
|
if item != nil {
|
||||||
item.ConnectionInfo = &api.ConnectionInfo{
|
item.ConnectionInfo = &api.ConnectionInfo{
|
||||||
ClientIP: tcpID.SrcIP,
|
ClientIP: tcpID.SrcIP,
|
||||||
@@ -86,7 +86,7 @@ func handleHTTP2Stream(http2Assembler *Http2Assembler, tcpID *api.TcpID, superTi
|
|||||||
streamID,
|
streamID,
|
||||||
"HTTP2",
|
"HTTP2",
|
||||||
)
|
)
|
||||||
item = reqResMatcher.registerResponse(ident, &messageHTTP1, superTimer.CaptureTime, messageHTTP1.ProtoMinor)
|
item = reqResMatcher.registerResponse(ident, &messageHTTP1, superTimer.CaptureTime, progress.Current(), messageHTTP1.ProtoMinor)
|
||||||
if item != nil {
|
if item != nil {
|
||||||
item.ConnectionInfo = &api.ConnectionInfo{
|
item.ConnectionInfo = &api.ConnectionInfo{
|
||||||
ClientIP: tcpID.DstIP,
|
ClientIP: tcpID.DstIP,
|
||||||
@@ -104,13 +104,14 @@ func handleHTTP2Stream(http2Assembler *Http2Assembler, tcpID *api.TcpID, superTi
|
|||||||
} else {
|
} else {
|
||||||
item.Protocol = http2Protocol
|
item.Protocol = http2Protocol
|
||||||
}
|
}
|
||||||
|
item.Capture = capture
|
||||||
filterAndEmit(item, emitter, options)
|
filterAndEmit(item, emitter, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleHTTP1ClientStream(b *bufio.Reader, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, emitter api.Emitter, options *api.TrafficFilteringOptions, reqResMatcher *requestResponseMatcher) (switchingProtocolsHTTP2 bool, req *http.Request, err error) {
|
func handleHTTP1ClientStream(b *bufio.Reader, progress *api.ReadProgress, capture api.Capture, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, emitter api.Emitter, options *api.TrafficFilteringOptions, reqResMatcher *requestResponseMatcher) (switchingProtocolsHTTP2 bool, req *http.Request, err error) {
|
||||||
req, err = http.ReadRequest(b)
|
req, err = http.ReadRequest(b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
@@ -138,7 +139,7 @@ func handleHTTP1ClientStream(b *bufio.Reader, tcpID *api.TcpID, counterPair *api
|
|||||||
requestCounter,
|
requestCounter,
|
||||||
"HTTP1",
|
"HTTP1",
|
||||||
)
|
)
|
||||||
item := reqResMatcher.registerRequest(ident, req, superTimer.CaptureTime, req.ProtoMinor)
|
item := reqResMatcher.registerRequest(ident, req, superTimer.CaptureTime, progress.Current(), req.ProtoMinor)
|
||||||
if item != nil {
|
if item != nil {
|
||||||
item.ConnectionInfo = &api.ConnectionInfo{
|
item.ConnectionInfo = &api.ConnectionInfo{
|
||||||
ClientIP: tcpID.SrcIP,
|
ClientIP: tcpID.SrcIP,
|
||||||
@@ -147,12 +148,13 @@ func handleHTTP1ClientStream(b *bufio.Reader, tcpID *api.TcpID, counterPair *api
|
|||||||
ServerPort: tcpID.DstPort,
|
ServerPort: tcpID.DstPort,
|
||||||
IsOutgoing: true,
|
IsOutgoing: true,
|
||||||
}
|
}
|
||||||
|
item.Capture = capture
|
||||||
filterAndEmit(item, emitter, options)
|
filterAndEmit(item, emitter, options)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleHTTP1ServerStream(b *bufio.Reader, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, emitter api.Emitter, options *api.TrafficFilteringOptions, reqResMatcher *requestResponseMatcher) (switchingProtocolsHTTP2 bool, err error) {
|
func handleHTTP1ServerStream(b *bufio.Reader, progress *api.ReadProgress, capture api.Capture, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, emitter api.Emitter, options *api.TrafficFilteringOptions, reqResMatcher *requestResponseMatcher) (switchingProtocolsHTTP2 bool, err error) {
|
||||||
var res *http.Response
|
var res *http.Response
|
||||||
res, err = http.ReadResponse(b, nil)
|
res, err = http.ReadResponse(b, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -181,7 +183,7 @@ func handleHTTP1ServerStream(b *bufio.Reader, tcpID *api.TcpID, counterPair *api
|
|||||||
responseCounter,
|
responseCounter,
|
||||||
"HTTP1",
|
"HTTP1",
|
||||||
)
|
)
|
||||||
item := reqResMatcher.registerResponse(ident, res, superTimer.CaptureTime, res.ProtoMinor)
|
item := reqResMatcher.registerResponse(ident, res, superTimer.CaptureTime, progress.Current(), res.ProtoMinor)
|
||||||
if item != nil {
|
if item != nil {
|
||||||
item.ConnectionInfo = &api.ConnectionInfo{
|
item.ConnectionInfo = &api.ConnectionInfo{
|
||||||
ClientIP: tcpID.DstIP,
|
ClientIP: tcpID.DstIP,
|
||||||
@@ -190,6 +192,7 @@ func handleHTTP1ServerStream(b *bufio.Reader, tcpID *api.TcpID, counterPair *api
|
|||||||
ServerPort: tcpID.SrcPort,
|
ServerPort: tcpID.SrcPort,
|
||||||
IsOutgoing: false,
|
IsOutgoing: false,
|
||||||
}
|
}
|
||||||
|
item.Capture = capture
|
||||||
filterAndEmit(item, emitter, options)
|
filterAndEmit(item, emitter, options)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -53,7 +53,16 @@ func representMapSliceAsTable(mapSlice []interface{}, selectorPrefix string) (re
|
|||||||
h := item.(map[string]interface{})
|
h := item.(map[string]interface{})
|
||||||
key := h["name"].(string)
|
key := h["name"].(string)
|
||||||
value := h["value"]
|
value := h["value"]
|
||||||
switch reflect.TypeOf(value).Kind() {
|
|
||||||
|
var reflectKind reflect.Kind
|
||||||
|
reflectType := reflect.TypeOf(value)
|
||||||
|
if reflectType == nil {
|
||||||
|
reflectKind = reflect.Interface
|
||||||
|
} else {
|
||||||
|
reflectKind = reflect.TypeOf(value).Kind()
|
||||||
|
}
|
||||||
|
|
||||||
|
switch reflectKind {
|
||||||
case reflect.Slice:
|
case reflect.Slice:
|
||||||
fallthrough
|
fallthrough
|
||||||
case reflect.Array:
|
case reflect.Array:
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ func (d dissecting) Ping() {
|
|||||||
log.Printf("pong %s", http11protocol.Name)
|
log.Printf("pong %s", http11protocol.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, superIdentifier *api.SuperIdentifier, emitter api.Emitter, options *api.TrafficFilteringOptions, _reqResMatcher api.RequestResponseMatcher) error {
|
func (d dissecting) Dissect(b *bufio.Reader, progress *api.ReadProgress, capture api.Capture, isClient bool, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, superIdentifier *api.SuperIdentifier, emitter api.Emitter, options *api.TrafficFilteringOptions, _reqResMatcher api.RequestResponseMatcher) error {
|
||||||
reqResMatcher := _reqResMatcher.(*requestResponseMatcher)
|
reqResMatcher := _reqResMatcher.(*requestResponseMatcher)
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
@@ -121,7 +121,7 @@ func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, co
|
|||||||
}
|
}
|
||||||
|
|
||||||
if isHTTP2 {
|
if isHTTP2 {
|
||||||
err = handleHTTP2Stream(http2Assembler, tcpID, superTimer, emitter, options, reqResMatcher)
|
err = handleHTTP2Stream(http2Assembler, progress, capture, tcpID, superTimer, emitter, options, reqResMatcher)
|
||||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||||
break
|
break
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
@@ -130,7 +130,7 @@ func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, co
|
|||||||
superIdentifier.Protocol = &http11protocol
|
superIdentifier.Protocol = &http11protocol
|
||||||
} else if isClient {
|
} else if isClient {
|
||||||
var req *http.Request
|
var req *http.Request
|
||||||
switchingProtocolsHTTP2, req, err = handleHTTP1ClientStream(b, tcpID, counterPair, superTimer, emitter, options, reqResMatcher)
|
switchingProtocolsHTTP2, req, err = handleHTTP1ClientStream(b, progress, capture, tcpID, counterPair, superTimer, emitter, options, reqResMatcher)
|
||||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||||
break
|
break
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
@@ -148,7 +148,7 @@ func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, co
|
|||||||
tcpID.DstPort,
|
tcpID.DstPort,
|
||||||
"HTTP2",
|
"HTTP2",
|
||||||
)
|
)
|
||||||
item := reqResMatcher.registerRequest(ident, req, superTimer.CaptureTime, req.ProtoMinor)
|
item := reqResMatcher.registerRequest(ident, req, superTimer.CaptureTime, progress.Current(), req.ProtoMinor)
|
||||||
if item != nil {
|
if item != nil {
|
||||||
item.ConnectionInfo = &api.ConnectionInfo{
|
item.ConnectionInfo = &api.ConnectionInfo{
|
||||||
ClientIP: tcpID.SrcIP,
|
ClientIP: tcpID.SrcIP,
|
||||||
@@ -157,11 +157,12 @@ func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, co
|
|||||||
ServerPort: tcpID.DstPort,
|
ServerPort: tcpID.DstPort,
|
||||||
IsOutgoing: true,
|
IsOutgoing: true,
|
||||||
}
|
}
|
||||||
|
item.Capture = capture
|
||||||
filterAndEmit(item, emitter, options)
|
filterAndEmit(item, emitter, options)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
switchingProtocolsHTTP2, err = handleHTTP1ServerStream(b, tcpID, counterPair, superTimer, emitter, options, reqResMatcher)
|
switchingProtocolsHTTP2, err = handleHTTP1ServerStream(b, progress, capture, tcpID, counterPair, superTimer, emitter, options, reqResMatcher)
|
||||||
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
if err == io.EOF || err == io.ErrUnexpectedEOF {
|
||||||
break
|
break
|
||||||
} else if err != nil {
|
} else if err != nil {
|
||||||
@@ -259,6 +260,7 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string,
|
|||||||
httpPair, _ := json.Marshal(item.Pair)
|
httpPair, _ := json.Marshal(item.Pair)
|
||||||
return &api.Entry{
|
return &api.Entry{
|
||||||
Protocol: item.Protocol,
|
Protocol: item.Protocol,
|
||||||
|
Capture: item.Capture,
|
||||||
Source: &api.TCP{
|
Source: &api.TCP{
|
||||||
Name: resolvedSource,
|
Name: resolvedSource,
|
||||||
IP: item.ConnectionInfo.ClientIP,
|
IP: item.ConnectionInfo.ClientIP,
|
||||||
@@ -269,14 +271,16 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string,
|
|||||||
IP: item.ConnectionInfo.ServerIP,
|
IP: item.ConnectionInfo.ServerIP,
|
||||||
Port: item.ConnectionInfo.ServerPort,
|
Port: item.ConnectionInfo.ServerPort,
|
||||||
},
|
},
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
Outgoing: item.ConnectionInfo.IsOutgoing,
|
Outgoing: item.ConnectionInfo.IsOutgoing,
|
||||||
Request: reqDetails,
|
Request: reqDetails,
|
||||||
Response: resDetails,
|
Response: resDetails,
|
||||||
Timestamp: item.Timestamp,
|
RequestSize: item.Pair.Request.CaptureSize,
|
||||||
StartTime: item.Pair.Request.CaptureTime,
|
ResponseSize: item.Pair.Response.CaptureSize,
|
||||||
ElapsedTime: elapsedTime,
|
Timestamp: item.Timestamp,
|
||||||
HTTPPair: string(httpPair),
|
StartTime: item.Pair.Request.CaptureTime,
|
||||||
|
ElapsedTime: elapsedTime,
|
||||||
|
HTTPPair: string(httpPair),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -291,6 +295,7 @@ func (d dissecting) Summarize(entry *api.Entry) *api.BaseEntry {
|
|||||||
return &api.BaseEntry{
|
return &api.BaseEntry{
|
||||||
Id: entry.Id,
|
Id: entry.Id,
|
||||||
Protocol: entry.Protocol,
|
Protocol: entry.Protocol,
|
||||||
|
Capture: entry.Capture,
|
||||||
Summary: summary,
|
Summary: summary,
|
||||||
SummaryQuery: summaryQuery,
|
SummaryQuery: summaryQuery,
|
||||||
Status: status,
|
Status: status,
|
||||||
@@ -407,11 +412,9 @@ func representRequest(request map[string]interface{}) (repRequest []interface{})
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func representResponse(response map[string]interface{}) (repResponse []interface{}, bodySize int64) {
|
func representResponse(response map[string]interface{}) (repResponse []interface{}) {
|
||||||
repResponse = make([]interface{}, 0)
|
repResponse = make([]interface{}, 0)
|
||||||
|
|
||||||
bodySize = int64(response["bodySize"].(float64))
|
|
||||||
|
|
||||||
details, _ := json.Marshal([]api.TableData{
|
details, _ := json.Marshal([]api.TableData{
|
||||||
{
|
{
|
||||||
Name: "Status",
|
Name: "Status",
|
||||||
@@ -425,7 +428,7 @@ func representResponse(response map[string]interface{}) (repResponse []interface
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Body Size (bytes)",
|
Name: "Body Size (bytes)",
|
||||||
Value: bodySize,
|
Value: int64(response["bodySize"].(float64)),
|
||||||
Selector: `response.bodySize`,
|
Selector: `response.bodySize`,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
@@ -468,10 +471,10 @@ func representResponse(response map[string]interface{}) (repResponse []interface
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d dissecting) Represent(request map[string]interface{}, response map[string]interface{}) (object []byte, bodySize int64, err error) {
|
func (d dissecting) Represent(request map[string]interface{}, response map[string]interface{}) (object []byte, err error) {
|
||||||
representation := make(map[string]interface{})
|
representation := make(map[string]interface{})
|
||||||
repRequest := representRequest(request)
|
repRequest := representRequest(request)
|
||||||
repResponse, bodySize := representResponse(response)
|
repResponse := representResponse(response)
|
||||||
representation["request"] = repRequest
|
representation["request"] = repRequest
|
||||||
representation["response"] = repResponse
|
representation["response"] = repResponse
|
||||||
object, err = json.Marshal(representation)
|
object, err = json.Marshal(representation)
|
||||||
|
|||||||
@@ -124,7 +124,7 @@ func TestDissect(t *testing.T) {
|
|||||||
DstPort: "2",
|
DstPort: "2",
|
||||||
}
|
}
|
||||||
reqResMatcher := dissector.NewResponseRequestMatcher()
|
reqResMatcher := dissector.NewResponseRequestMatcher()
|
||||||
err = dissector.Dissect(bufferClient, true, tcpIDClient, counterPair, &api.SuperTimer{}, superIdentifier, emitter, options, reqResMatcher)
|
err = dissector.Dissect(bufferClient, &api.ReadProgress{}, api.Pcap, true, tcpIDClient, counterPair, &api.SuperTimer{}, superIdentifier, emitter, options, reqResMatcher)
|
||||||
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -142,7 +142,7 @@ func TestDissect(t *testing.T) {
|
|||||||
SrcPort: "2",
|
SrcPort: "2",
|
||||||
DstPort: "1",
|
DstPort: "1",
|
||||||
}
|
}
|
||||||
err = dissector.Dissect(bufferServer, false, tcpIDServer, counterPair, &api.SuperTimer{}, superIdentifier, emitter, options, reqResMatcher)
|
err = dissector.Dissect(bufferServer, &api.ReadProgress{}, api.Pcap, false, tcpIDServer, counterPair, &api.SuperTimer{}, superIdentifier, emitter, options, reqResMatcher)
|
||||||
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
@@ -321,7 +321,7 @@ func TestRepresent(t *testing.T) {
|
|||||||
|
|
||||||
var objects []string
|
var objects []string
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
object, _, err := dissector.Represent(entry.Request, entry.Response)
|
object, err := dissector.Represent(entry.Request, entry.Response)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
objects = append(objects, string(object))
|
objects = append(objects, string(object))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,10 +24,11 @@ func (matcher *requestResponseMatcher) GetMap() *sync.Map {
|
|||||||
func (matcher *requestResponseMatcher) SetMaxTry(value int) {
|
func (matcher *requestResponseMatcher) SetMaxTry(value int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (matcher *requestResponseMatcher) registerRequest(ident string, request *http.Request, captureTime time.Time, protoMinor int) *api.OutputChannelItem {
|
func (matcher *requestResponseMatcher) registerRequest(ident string, request *http.Request, captureTime time.Time, captureSize int, protoMinor int) *api.OutputChannelItem {
|
||||||
requestHTTPMessage := api.GenericMessage{
|
requestHTTPMessage := api.GenericMessage{
|
||||||
IsRequest: true,
|
IsRequest: true,
|
||||||
CaptureTime: captureTime,
|
CaptureTime: captureTime,
|
||||||
|
CaptureSize: captureSize,
|
||||||
Payload: api.HTTPPayload{
|
Payload: api.HTTPPayload{
|
||||||
Type: TypeHttpRequest,
|
Type: TypeHttpRequest,
|
||||||
Data: request,
|
Data: request,
|
||||||
@@ -47,10 +48,11 @@ func (matcher *requestResponseMatcher) registerRequest(ident string, request *ht
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (matcher *requestResponseMatcher) registerResponse(ident string, response *http.Response, captureTime time.Time, protoMinor int) *api.OutputChannelItem {
|
func (matcher *requestResponseMatcher) registerResponse(ident string, response *http.Response, captureTime time.Time, captureSize int, protoMinor int) *api.OutputChannelItem {
|
||||||
responseHTTPMessage := api.GenericMessage{
|
responseHTTPMessage := api.GenericMessage{
|
||||||
IsRequest: false,
|
IsRequest: false,
|
||||||
CaptureTime: captureTime,
|
CaptureTime: captureTime,
|
||||||
|
CaptureSize: captureSize,
|
||||||
Payload: api.HTTPPayload{
|
Payload: api.HTTPPayload{
|
||||||
Type: TypeHttpResponse,
|
Type: TypeHttpResponse,
|
||||||
Data: response,
|
Data: response,
|
||||||
|
|||||||
@@ -13,4 +13,4 @@ test-pull-bin:
|
|||||||
|
|
||||||
test-pull-expect:
|
test-pull-expect:
|
||||||
@mkdir -p expect
|
@mkdir -p expect
|
||||||
@[ "${skipexpect}" ] && echo "Skipping downloading expected JSONs" || gsutil -o 'GSUtil:parallel_process_count=5' -o 'GSUtil:parallel_thread_count=5' -m cp -r gs://static.up9.io/mizu/test-pcap/expect3/kafka/\* expect
|
@[ "${skipexpect}" ] && echo "Skipping downloading expected JSONs" || gsutil -o 'GSUtil:parallel_process_count=5' -o 'GSUtil:parallel_thread_count=5' -m cp -r gs://static.up9.io/mizu/test-pcap/expect5/kafka/\* expect
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ require (
|
|||||||
github.com/segmentio/kafka-go v0.4.27
|
github.com/segmentio/kafka-go v0.4.27
|
||||||
github.com/stretchr/testify v1.6.1
|
github.com/stretchr/testify v1.6.1
|
||||||
github.com/up9inc/mizu/tap/api v0.0.0
|
github.com/up9inc/mizu/tap/api v0.0.0
|
||||||
|
golang.org/x/text v0.3.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ golang.org/x/crypto v0.0.0-20190506204251-e1dfcc566284/go.mod h1:yigFU9vqHzYiE8U
|
|||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
|
golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg=
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
|||||||
@@ -3,6 +3,8 @@ package kafka
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"golang.org/x/text/cases"
|
||||||
|
"golang.org/x/text/language"
|
||||||
"reflect"
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -891,8 +893,9 @@ func representMapAsTable(mapData map[string]interface{}, selectorPrefix string,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
selector := fmt.Sprintf("%s[\"%s\"]", selectorPrefix, key)
|
selector := fmt.Sprintf("%s[\"%s\"]", selectorPrefix, key)
|
||||||
|
caser := cases.Title(language.Und, cases.NoLower)
|
||||||
table = append(table, api.TableData{
|
table = append(table, api.TableData{
|
||||||
Name: strings.Join(camelcase.Split(strings.Title(key)), " "),
|
Name: strings.Join(camelcase.Split(caser.String(key)), " "),
|
||||||
Value: value,
|
Value: value,
|
||||||
Selector: selector,
|
Selector: selector,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ func (d dissecting) Ping() {
|
|||||||
log.Printf("pong %s", _protocol.Name)
|
log.Printf("pong %s", _protocol.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, superIdentifier *api.SuperIdentifier, emitter api.Emitter, options *api.TrafficFilteringOptions, _reqResMatcher api.RequestResponseMatcher) error {
|
func (d dissecting) Dissect(b *bufio.Reader, progress *api.ReadProgress, capture api.Capture, isClient bool, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, superIdentifier *api.SuperIdentifier, emitter api.Emitter, options *api.TrafficFilteringOptions, _reqResMatcher api.RequestResponseMatcher) error {
|
||||||
reqResMatcher := _reqResMatcher.(*requestResponseMatcher)
|
reqResMatcher := _reqResMatcher.(*requestResponseMatcher)
|
||||||
for {
|
for {
|
||||||
if superIdentifier.Protocol != nil && superIdentifier.Protocol != &_protocol {
|
if superIdentifier.Protocol != nil && superIdentifier.Protocol != &_protocol {
|
||||||
@@ -49,7 +49,7 @@ func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, co
|
|||||||
}
|
}
|
||||||
superIdentifier.Protocol = &_protocol
|
superIdentifier.Protocol = &_protocol
|
||||||
} else {
|
} else {
|
||||||
err := ReadResponse(b, tcpID, counterPair, superTimer, emitter, reqResMatcher)
|
err := ReadResponse(b, capture, tcpID, counterPair, superTimer, emitter, reqResMatcher)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -68,6 +68,7 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string,
|
|||||||
}
|
}
|
||||||
return &api.Entry{
|
return &api.Entry{
|
||||||
Protocol: _protocol,
|
Protocol: _protocol,
|
||||||
|
Capture: item.Capture,
|
||||||
Source: &api.TCP{
|
Source: &api.TCP{
|
||||||
Name: resolvedSource,
|
Name: resolvedSource,
|
||||||
IP: item.ConnectionInfo.ClientIP,
|
IP: item.ConnectionInfo.ClientIP,
|
||||||
@@ -78,13 +79,15 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string,
|
|||||||
IP: item.ConnectionInfo.ServerIP,
|
IP: item.ConnectionInfo.ServerIP,
|
||||||
Port: item.ConnectionInfo.ServerPort,
|
Port: item.ConnectionInfo.ServerPort,
|
||||||
},
|
},
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
Outgoing: item.ConnectionInfo.IsOutgoing,
|
Outgoing: item.ConnectionInfo.IsOutgoing,
|
||||||
Request: reqDetails,
|
Request: reqDetails,
|
||||||
Response: item.Pair.Response.Payload.(map[string]interface{})["details"].(map[string]interface{}),
|
Response: item.Pair.Response.Payload.(map[string]interface{})["details"].(map[string]interface{}),
|
||||||
Timestamp: item.Timestamp,
|
RequestSize: item.Pair.Request.CaptureSize,
|
||||||
StartTime: item.Pair.Request.CaptureTime,
|
ResponseSize: item.Pair.Response.CaptureSize,
|
||||||
ElapsedTime: elapsedTime,
|
Timestamp: item.Timestamp,
|
||||||
|
StartTime: item.Pair.Request.CaptureTime,
|
||||||
|
ElapsedTime: elapsedTime,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,6 +193,7 @@ func (d dissecting) Summarize(entry *api.Entry) *api.BaseEntry {
|
|||||||
return &api.BaseEntry{
|
return &api.BaseEntry{
|
||||||
Id: entry.Id,
|
Id: entry.Id,
|
||||||
Protocol: entry.Protocol,
|
Protocol: entry.Protocol,
|
||||||
|
Capture: entry.Capture,
|
||||||
Summary: summary,
|
Summary: summary,
|
||||||
SummaryQuery: summaryQuery,
|
SummaryQuery: summaryQuery,
|
||||||
Status: status,
|
Status: status,
|
||||||
@@ -206,8 +210,7 @@ func (d dissecting) Summarize(entry *api.Entry) *api.BaseEntry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d dissecting) Represent(request map[string]interface{}, response map[string]interface{}) (object []byte, bodySize int64, err error) {
|
func (d dissecting) Represent(request map[string]interface{}, response map[string]interface{}) (object []byte, err error) {
|
||||||
bodySize = 0
|
|
||||||
representation := make(map[string]interface{})
|
representation := make(map[string]interface{})
|
||||||
|
|
||||||
apiKey := ApiKey(request["apiKey"].(float64))
|
apiKey := ApiKey(request["apiKey"].(float64))
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ func TestDissect(t *testing.T) {
|
|||||||
}
|
}
|
||||||
reqResMatcher := dissector.NewResponseRequestMatcher()
|
reqResMatcher := dissector.NewResponseRequestMatcher()
|
||||||
reqResMatcher.SetMaxTry(10)
|
reqResMatcher.SetMaxTry(10)
|
||||||
err = dissector.Dissect(bufferClient, true, tcpIDClient, counterPair, &api.SuperTimer{}, superIdentifier, emitter, options, reqResMatcher)
|
err = dissector.Dissect(bufferClient, &api.ReadProgress{}, api.Pcap, true, tcpIDClient, counterPair, &api.SuperTimer{}, superIdentifier, emitter, options, reqResMatcher)
|
||||||
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
@@ -141,7 +141,7 @@ func TestDissect(t *testing.T) {
|
|||||||
SrcPort: "2",
|
SrcPort: "2",
|
||||||
DstPort: "1",
|
DstPort: "1",
|
||||||
}
|
}
|
||||||
err = dissector.Dissect(bufferServer, false, tcpIDServer, counterPair, &api.SuperTimer{}, superIdentifier, emitter, options, reqResMatcher)
|
err = dissector.Dissect(bufferServer, &api.ReadProgress{}, api.Pcap, false, tcpIDServer, counterPair, &api.SuperTimer{}, superIdentifier, emitter, options, reqResMatcher)
|
||||||
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
if err != nil && err != io.EOF && err != io.ErrUnexpectedEOF {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
@@ -320,7 +320,7 @@ func TestRepresent(t *testing.T) {
|
|||||||
|
|
||||||
var objects []string
|
var objects []string
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
object, _, err := dissector.Represent(entry.Request, entry.Response)
|
object, err := dissector.Represent(entry.Request, entry.Response)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
objects = append(objects, string(object))
|
objects = append(objects, string(object))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ type Response struct {
|
|||||||
CaptureTime time.Time `json:"captureTime"`
|
CaptureTime time.Time `json:"captureTime"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func ReadResponse(r io.Reader, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, emitter api.Emitter, reqResMatcher *requestResponseMatcher) (err error) {
|
func ReadResponse(r io.Reader, capture api.Capture, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, emitter api.Emitter, reqResMatcher *requestResponseMatcher) (err error) {
|
||||||
d := &decoder{reader: r, remain: 4}
|
d := &decoder{reader: r, remain: 4}
|
||||||
size := d.readInt32()
|
size := d.readInt32()
|
||||||
|
|
||||||
@@ -258,12 +258,14 @@ func ReadResponse(r io.Reader, tcpID *api.TcpID, counterPair *api.CounterPair, s
|
|||||||
|
|
||||||
item := &api.OutputChannelItem{
|
item := &api.OutputChannelItem{
|
||||||
Protocol: _protocol,
|
Protocol: _protocol,
|
||||||
|
Capture: capture,
|
||||||
Timestamp: reqResPair.Request.CaptureTime.UnixNano() / int64(time.Millisecond),
|
Timestamp: reqResPair.Request.CaptureTime.UnixNano() / int64(time.Millisecond),
|
||||||
ConnectionInfo: connectionInfo,
|
ConnectionInfo: connectionInfo,
|
||||||
Pair: &api.RequestResponsePair{
|
Pair: &api.RequestResponsePair{
|
||||||
Request: api.GenericMessage{
|
Request: api.GenericMessage{
|
||||||
IsRequest: true,
|
IsRequest: true,
|
||||||
CaptureTime: reqResPair.Request.CaptureTime,
|
CaptureTime: reqResPair.Request.CaptureTime,
|
||||||
|
CaptureSize: int(reqResPair.Request.Size),
|
||||||
Payload: KafkaPayload{
|
Payload: KafkaPayload{
|
||||||
Data: &KafkaWrapper{
|
Data: &KafkaWrapper{
|
||||||
Method: apiNames[apiKey],
|
Method: apiNames[apiKey],
|
||||||
@@ -275,6 +277,7 @@ func ReadResponse(r io.Reader, tcpID *api.TcpID, counterPair *api.CounterPair, s
|
|||||||
Response: api.GenericMessage{
|
Response: api.GenericMessage{
|
||||||
IsRequest: false,
|
IsRequest: false,
|
||||||
CaptureTime: reqResPair.Response.CaptureTime,
|
CaptureTime: reqResPair.Response.CaptureTime,
|
||||||
|
CaptureSize: int(reqResPair.Response.Size),
|
||||||
Payload: KafkaPayload{
|
Payload: KafkaPayload{
|
||||||
Data: &KafkaWrapper{
|
Data: &KafkaWrapper{
|
||||||
Method: apiNames[apiKey],
|
Method: apiNames[apiKey],
|
||||||
|
|||||||
@@ -13,4 +13,4 @@ test-pull-bin:
|
|||||||
|
|
||||||
test-pull-expect:
|
test-pull-expect:
|
||||||
@mkdir -p expect
|
@mkdir -p expect
|
||||||
@[ "${skipexpect}" ] && echo "Skipping downloading expected JSONs" || gsutil -o 'GSUtil:parallel_process_count=5' -o 'GSUtil:parallel_thread_count=5' -m cp -r gs://static.up9.io/mizu/test-pcap/expect3/redis/\* expect
|
@[ "${skipexpect}" ] && echo "Skipping downloading expected JSONs" || gsutil -o 'GSUtil:parallel_process_count=5' -o 'GSUtil:parallel_thread_count=5' -m cp -r gs://static.up9.io/mizu/test-pcap/expect5/redis/\* expect
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"github.com/up9inc/mizu/tap/api"
|
"github.com/up9inc/mizu/tap/api"
|
||||||
)
|
)
|
||||||
|
|
||||||
func handleClientStream(tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, emitter api.Emitter, request *RedisPacket, reqResMatcher *requestResponseMatcher) error {
|
func handleClientStream(progress *api.ReadProgress, capture api.Capture, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, emitter api.Emitter, request *RedisPacket, reqResMatcher *requestResponseMatcher) error {
|
||||||
counterPair.Lock()
|
counterPair.Lock()
|
||||||
counterPair.Request++
|
counterPair.Request++
|
||||||
requestCounter := counterPair.Request
|
requestCounter := counterPair.Request
|
||||||
@@ -21,8 +21,9 @@ func handleClientStream(tcpID *api.TcpID, counterPair *api.CounterPair, superTim
|
|||||||
requestCounter,
|
requestCounter,
|
||||||
)
|
)
|
||||||
|
|
||||||
item := reqResMatcher.registerRequest(ident, request, superTimer.CaptureTime)
|
item := reqResMatcher.registerRequest(ident, request, superTimer.CaptureTime, progress.Current())
|
||||||
if item != nil {
|
if item != nil {
|
||||||
|
item.Capture = capture
|
||||||
item.ConnectionInfo = &api.ConnectionInfo{
|
item.ConnectionInfo = &api.ConnectionInfo{
|
||||||
ClientIP: tcpID.SrcIP,
|
ClientIP: tcpID.SrcIP,
|
||||||
ClientPort: tcpID.SrcPort,
|
ClientPort: tcpID.SrcPort,
|
||||||
@@ -35,7 +36,7 @@ func handleClientStream(tcpID *api.TcpID, counterPair *api.CounterPair, superTim
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleServerStream(tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, emitter api.Emitter, response *RedisPacket, reqResMatcher *requestResponseMatcher) error {
|
func handleServerStream(progress *api.ReadProgress, capture api.Capture, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, emitter api.Emitter, response *RedisPacket, reqResMatcher *requestResponseMatcher) error {
|
||||||
counterPair.Lock()
|
counterPair.Lock()
|
||||||
counterPair.Response++
|
counterPair.Response++
|
||||||
responseCounter := counterPair.Response
|
responseCounter := counterPair.Response
|
||||||
@@ -50,8 +51,9 @@ func handleServerStream(tcpID *api.TcpID, counterPair *api.CounterPair, superTim
|
|||||||
responseCounter,
|
responseCounter,
|
||||||
)
|
)
|
||||||
|
|
||||||
item := reqResMatcher.registerResponse(ident, response, superTimer.CaptureTime)
|
item := reqResMatcher.registerResponse(ident, response, superTimer.CaptureTime, progress.Current())
|
||||||
if item != nil {
|
if item != nil {
|
||||||
|
item.Capture = capture
|
||||||
item.ConnectionInfo = &api.ConnectionInfo{
|
item.ConnectionInfo = &api.ConnectionInfo{
|
||||||
ClientIP: tcpID.DstIP,
|
ClientIP: tcpID.DstIP,
|
||||||
ClientPort: tcpID.DstPort,
|
ClientPort: tcpID.DstPort,
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ func (d dissecting) Ping() {
|
|||||||
log.Printf("pong %s", protocol.Name)
|
log.Printf("pong %s", protocol.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, superIdentifier *api.SuperIdentifier, emitter api.Emitter, options *api.TrafficFilteringOptions, _reqResMatcher api.RequestResponseMatcher) error {
|
func (d dissecting) Dissect(b *bufio.Reader, progress *api.ReadProgress, capture api.Capture, isClient bool, tcpID *api.TcpID, counterPair *api.CounterPair, superTimer *api.SuperTimer, superIdentifier *api.SuperIdentifier, emitter api.Emitter, options *api.TrafficFilteringOptions, _reqResMatcher api.RequestResponseMatcher) error {
|
||||||
reqResMatcher := _reqResMatcher.(*requestResponseMatcher)
|
reqResMatcher := _reqResMatcher.(*requestResponseMatcher)
|
||||||
is := &RedisInputStream{
|
is := &RedisInputStream{
|
||||||
Reader: b,
|
Reader: b,
|
||||||
@@ -48,9 +48,9 @@ func (d dissecting) Dissect(b *bufio.Reader, isClient bool, tcpID *api.TcpID, co
|
|||||||
}
|
}
|
||||||
|
|
||||||
if isClient {
|
if isClient {
|
||||||
err = handleClientStream(tcpID, counterPair, superTimer, emitter, redisPacket, reqResMatcher)
|
err = handleClientStream(progress, capture, tcpID, counterPair, superTimer, emitter, redisPacket, reqResMatcher)
|
||||||
} else {
|
} else {
|
||||||
err = handleServerStream(tcpID, counterPair, superTimer, emitter, redisPacket, reqResMatcher)
|
err = handleServerStream(progress, capture, tcpID, counterPair, superTimer, emitter, redisPacket, reqResMatcher)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -71,6 +71,7 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string,
|
|||||||
}
|
}
|
||||||
return &api.Entry{
|
return &api.Entry{
|
||||||
Protocol: protocol,
|
Protocol: protocol,
|
||||||
|
Capture: item.Capture,
|
||||||
Source: &api.TCP{
|
Source: &api.TCP{
|
||||||
Name: resolvedSource,
|
Name: resolvedSource,
|
||||||
IP: item.ConnectionInfo.ClientIP,
|
IP: item.ConnectionInfo.ClientIP,
|
||||||
@@ -81,13 +82,15 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string,
|
|||||||
IP: item.ConnectionInfo.ServerIP,
|
IP: item.ConnectionInfo.ServerIP,
|
||||||
Port: item.ConnectionInfo.ServerPort,
|
Port: item.ConnectionInfo.ServerPort,
|
||||||
},
|
},
|
||||||
Namespace: namespace,
|
Namespace: namespace,
|
||||||
Outgoing: item.ConnectionInfo.IsOutgoing,
|
Outgoing: item.ConnectionInfo.IsOutgoing,
|
||||||
Request: reqDetails,
|
Request: reqDetails,
|
||||||
Response: resDetails,
|
Response: resDetails,
|
||||||
Timestamp: item.Timestamp,
|
RequestSize: item.Pair.Request.CaptureSize,
|
||||||
StartTime: item.Pair.Request.CaptureTime,
|
ResponseSize: item.Pair.Response.CaptureSize,
|
||||||
ElapsedTime: elapsedTime,
|
Timestamp: item.Timestamp,
|
||||||
|
StartTime: item.Pair.Request.CaptureTime,
|
||||||
|
ElapsedTime: elapsedTime,
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -113,6 +116,7 @@ func (d dissecting) Summarize(entry *api.Entry) *api.BaseEntry {
|
|||||||
return &api.BaseEntry{
|
return &api.BaseEntry{
|
||||||
Id: entry.Id,
|
Id: entry.Id,
|
||||||
Protocol: entry.Protocol,
|
Protocol: entry.Protocol,
|
||||||
|
Capture: entry.Capture,
|
||||||
Summary: summary,
|
Summary: summary,
|
||||||
SummaryQuery: summaryQuery,
|
SummaryQuery: summaryQuery,
|
||||||
Status: status,
|
Status: status,
|
||||||
@@ -129,8 +133,7 @@ func (d dissecting) Summarize(entry *api.Entry) *api.BaseEntry {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d dissecting) Represent(request map[string]interface{}, response map[string]interface{}) (object []byte, bodySize int64, err error) {
|
func (d dissecting) Represent(request map[string]interface{}, response map[string]interface{}) (object []byte, err error) {
|
||||||
bodySize = 0
|
|
||||||
representation := make(map[string]interface{})
|
representation := make(map[string]interface{})
|
||||||
repRequest := representGeneric(request, `request.`)
|
repRequest := representGeneric(request, `request.`)
|
||||||
repResponse := representGeneric(response, `response.`)
|
repResponse := representGeneric(response, `response.`)
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ func TestDissect(t *testing.T) {
|
|||||||
DstPort: "2",
|
DstPort: "2",
|
||||||
}
|
}
|
||||||
reqResMatcher := dissector.NewResponseRequestMatcher()
|
reqResMatcher := dissector.NewResponseRequestMatcher()
|
||||||
err = dissector.Dissect(bufferClient, true, tcpIDClient, counterPair, &api.SuperTimer{}, superIdentifier, emitter, options, reqResMatcher)
|
err = dissector.Dissect(bufferClient, &api.ReadProgress{}, api.Pcap, true, tcpIDClient, counterPair, &api.SuperTimer{}, superIdentifier, emitter, options, reqResMatcher)
|
||||||
if err != nil && reflect.TypeOf(err) != reflect.TypeOf(&ConnectError{}) && err != io.EOF && err != io.ErrUnexpectedEOF {
|
if err != nil && reflect.TypeOf(err) != reflect.TypeOf(&ConnectError{}) && err != io.EOF && err != io.ErrUnexpectedEOF {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
@@ -141,7 +141,7 @@ func TestDissect(t *testing.T) {
|
|||||||
SrcPort: "2",
|
SrcPort: "2",
|
||||||
DstPort: "1",
|
DstPort: "1",
|
||||||
}
|
}
|
||||||
err = dissector.Dissect(bufferServer, false, tcpIDServer, counterPair, &api.SuperTimer{}, superIdentifier, emitter, options, reqResMatcher)
|
err = dissector.Dissect(bufferServer, &api.ReadProgress{}, api.Pcap, false, tcpIDServer, counterPair, &api.SuperTimer{}, superIdentifier, emitter, options, reqResMatcher)
|
||||||
if err != nil && reflect.TypeOf(err) != reflect.TypeOf(&ConnectError{}) && err != io.EOF && err != io.ErrUnexpectedEOF {
|
if err != nil && reflect.TypeOf(err) != reflect.TypeOf(&ConnectError{}) && err != io.EOF && err != io.ErrUnexpectedEOF {
|
||||||
log.Println(err)
|
log.Println(err)
|
||||||
}
|
}
|
||||||
@@ -320,7 +320,7 @@ func TestRepresent(t *testing.T) {
|
|||||||
|
|
||||||
var objects []string
|
var objects []string
|
||||||
for _, entry := range entries {
|
for _, entry := range entries {
|
||||||
object, _, err := dissector.Represent(entry.Request, entry.Response)
|
object, err := dissector.Represent(entry.Request, entry.Response)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
objects = append(objects, string(object))
|
objects = append(objects, string(object))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,10 +22,11 @@ func (matcher *requestResponseMatcher) GetMap() *sync.Map {
|
|||||||
func (matcher *requestResponseMatcher) SetMaxTry(value int) {
|
func (matcher *requestResponseMatcher) SetMaxTry(value int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (matcher *requestResponseMatcher) registerRequest(ident string, request *RedisPacket, captureTime time.Time) *api.OutputChannelItem {
|
func (matcher *requestResponseMatcher) registerRequest(ident string, request *RedisPacket, captureTime time.Time, captureSize int) *api.OutputChannelItem {
|
||||||
requestRedisMessage := api.GenericMessage{
|
requestRedisMessage := api.GenericMessage{
|
||||||
IsRequest: true,
|
IsRequest: true,
|
||||||
CaptureTime: captureTime,
|
CaptureTime: captureTime,
|
||||||
|
CaptureSize: captureSize,
|
||||||
Payload: RedisPayload{
|
Payload: RedisPayload{
|
||||||
Data: &RedisWrapper{
|
Data: &RedisWrapper{
|
||||||
Method: string(request.Command),
|
Method: string(request.Command),
|
||||||
@@ -48,10 +49,11 @@ func (matcher *requestResponseMatcher) registerRequest(ident string, request *Re
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (matcher *requestResponseMatcher) registerResponse(ident string, response *RedisPacket, captureTime time.Time) *api.OutputChannelItem {
|
func (matcher *requestResponseMatcher) registerResponse(ident string, response *RedisPacket, captureTime time.Time, captureSize int) *api.OutputChannelItem {
|
||||||
responseRedisMessage := api.GenericMessage{
|
responseRedisMessage := api.GenericMessage{
|
||||||
IsRequest: false,
|
IsRequest: false,
|
||||||
CaptureTime: captureTime,
|
CaptureTime: captureTime,
|
||||||
|
CaptureSize: captureSize,
|
||||||
Payload: RedisPayload{
|
Payload: RedisPayload{
|
||||||
Data: &RedisWrapper{
|
Data: &RedisWrapper{
|
||||||
Method: string(response.Command),
|
Method: string(response.Command),
|
||||||
|
|||||||
@@ -59,7 +59,6 @@ var memprofile = flag.String("memprofile", "", "Write memory profile")
|
|||||||
|
|
||||||
type TapOpts struct {
|
type TapOpts struct {
|
||||||
HostMode bool
|
HostMode bool
|
||||||
FilterAuthorities []v1.Pod
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var extensions []*api.Extension // global
|
var extensions []*api.Extension // global
|
||||||
@@ -67,6 +66,7 @@ var filteringOptions *api.TrafficFilteringOptions // global
|
|||||||
var tapTargets []v1.Pod // global
|
var tapTargets []v1.Pod // global
|
||||||
var packetSourceManager *source.PacketSourceManager // global
|
var packetSourceManager *source.PacketSourceManager // global
|
||||||
var mainPacketInputChan chan source.TcpPacketInfo // global
|
var mainPacketInputChan chan source.TcpPacketInfo // global
|
||||||
|
var tlsTapperInstance *tlstapper.TlsTapper // global
|
||||||
|
|
||||||
func inArrayInt(arr []int, valueToCheck int) bool {
|
func inArrayInt(arr []int, valueToCheck int) bool {
|
||||||
for _, value := range arr {
|
for _, value := range arr {
|
||||||
@@ -90,16 +90,10 @@ func StartPassiveTapper(opts *TapOpts, outputItems chan *api.OutputChannelItem,
|
|||||||
extensions = extensionsRef
|
extensions = extensionsRef
|
||||||
filteringOptions = options
|
filteringOptions = options
|
||||||
|
|
||||||
if opts.FilterAuthorities == nil {
|
|
||||||
tapTargets = []v1.Pod{}
|
|
||||||
} else {
|
|
||||||
tapTargets = opts.FilterAuthorities
|
|
||||||
}
|
|
||||||
|
|
||||||
if *tls {
|
if *tls {
|
||||||
for _, e := range extensions {
|
for _, e := range extensions {
|
||||||
if e.Protocol.Name == "http" {
|
if e.Protocol.Name == "http" {
|
||||||
startTlsTapper(e, outputItems, options)
|
tlsTapperInstance = startTlsTapper(e, outputItems, options)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,24 +103,39 @@ func StartPassiveTapper(opts *TapOpts, outputItems chan *api.OutputChannelItem,
|
|||||||
diagnose.StartMemoryProfiler(os.Getenv(MemoryProfilingDumpPath), os.Getenv(MemoryProfilingTimeIntervalSeconds))
|
diagnose.StartMemoryProfiler(os.Getenv(MemoryProfilingDumpPath), os.Getenv(MemoryProfilingTimeIntervalSeconds))
|
||||||
}
|
}
|
||||||
|
|
||||||
go startPassiveTapper(opts, outputItems)
|
streamsMap, assembler := initializePassiveTapper(opts, outputItems)
|
||||||
|
go startPassiveTapper(streamsMap, assembler)
|
||||||
}
|
}
|
||||||
|
|
||||||
func UpdateTapTargets(newTapTargets []v1.Pod) {
|
func UpdateTapTargets(newTapTargets []v1.Pod) {
|
||||||
|
success := true
|
||||||
|
|
||||||
tapTargets = newTapTargets
|
tapTargets = newTapTargets
|
||||||
if err := initializePacketSources(); err != nil {
|
|
||||||
logger.Log.Fatal(err)
|
packetSourceManager.UpdatePods(tapTargets, !*nodefrag, mainPacketInputChan)
|
||||||
|
|
||||||
|
if tlsTapperInstance != nil {
|
||||||
|
if err := tlstapper.UpdateTapTargets(tlsTapperInstance, &tapTargets, *procfs); err != nil {
|
||||||
|
tlstapper.LogError(err)
|
||||||
|
success = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
printNewTapTargets()
|
|
||||||
|
printNewTapTargets(success)
|
||||||
}
|
}
|
||||||
|
|
||||||
func printNewTapTargets() {
|
func printNewTapTargets(success bool) {
|
||||||
printStr := ""
|
printStr := ""
|
||||||
for _, tapTarget := range tapTargets {
|
for _, tapTarget := range tapTargets {
|
||||||
printStr += fmt.Sprintf("%s (%s), ", tapTarget.Status.PodIP, tapTarget.Name)
|
printStr += fmt.Sprintf("%s (%s), ", tapTarget.Status.PodIP, tapTarget.Name)
|
||||||
}
|
}
|
||||||
printStr = strings.TrimRight(printStr, ", ")
|
printStr = strings.TrimRight(printStr, ", ")
|
||||||
logger.Log.Infof("Now tapping: %s", printStr)
|
|
||||||
|
if success {
|
||||||
|
logger.Log.Infof("Now tapping: %s", printStr)
|
||||||
|
} else {
|
||||||
|
logger.Log.Errorf("Failed to start tapping: %s", printStr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func printPeriodicStats(cleaner *Cleaner) {
|
func printPeriodicStats(cleaner *Cleaner) {
|
||||||
@@ -189,17 +198,12 @@ func initializePacketSources() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
if packetSourceManager, err = source.NewPacketSourceManager(*procfs, *fname, *iface, *servicemesh, tapTargets, behaviour); err != nil {
|
packetSourceManager, err = source.NewPacketSourceManager(*procfs, *fname, *iface, *servicemesh, tapTargets, behaviour, !*nodefrag, mainPacketInputChan)
|
||||||
return err
|
return err
|
||||||
} else {
|
|
||||||
packetSourceManager.ReadPackets(!*nodefrag, mainPacketInputChan)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func startPassiveTapper(opts *TapOpts, outputItems chan *api.OutputChannelItem) {
|
func initializePassiveTapper(opts *TapOpts, outputItems chan *api.OutputChannelItem) (*tcpStreamMap, *tcpAssembler) {
|
||||||
streamsMap := NewTcpStreamMap()
|
streamsMap := NewTcpStreamMap()
|
||||||
go streamsMap.closeTimedoutTcpStreamChannels()
|
|
||||||
|
|
||||||
diagnose.InitializeErrorsMap(*debug, *verbose, *quiet)
|
diagnose.InitializeErrorsMap(*debug, *verbose, *quiet)
|
||||||
diagnose.InitializeTapperInternalStats()
|
diagnose.InitializeTapperInternalStats()
|
||||||
@@ -212,6 +216,12 @@ func startPassiveTapper(opts *TapOpts, outputItems chan *api.OutputChannelItem)
|
|||||||
|
|
||||||
assembler := NewTcpAssembler(outputItems, streamsMap, opts)
|
assembler := NewTcpAssembler(outputItems, streamsMap, opts)
|
||||||
|
|
||||||
|
return streamsMap, assembler
|
||||||
|
}
|
||||||
|
|
||||||
|
func startPassiveTapper(streamsMap *tcpStreamMap, assembler *tcpAssembler) {
|
||||||
|
go streamsMap.closeTimedoutTcpStreamChannels()
|
||||||
|
|
||||||
diagnose.AppStats.SetStartTime(time.Now())
|
diagnose.AppStats.SetStartTime(time.Now())
|
||||||
|
|
||||||
staleConnectionTimeout := time.Second * time.Duration(*staleTimeoutSeconds)
|
staleConnectionTimeout := time.Second * time.Duration(*staleTimeoutSeconds)
|
||||||
@@ -243,13 +253,19 @@ func startPassiveTapper(opts *TapOpts, outputItems chan *api.OutputChannelItem)
|
|||||||
logger.Log.Infof("AppStats: %v", diagnose.AppStats)
|
logger.Log.Infof("AppStats: %v", diagnose.AppStats)
|
||||||
}
|
}
|
||||||
|
|
||||||
func startTlsTapper(extension *api.Extension, outputItems chan *api.OutputChannelItem, options *api.TrafficFilteringOptions) {
|
func startTlsTapper(extension *api.Extension, outputItems chan *api.OutputChannelItem, options *api.TrafficFilteringOptions) *tlstapper.TlsTapper {
|
||||||
tls := tlstapper.TlsTapper{}
|
tls := tlstapper.TlsTapper{}
|
||||||
tlsPerfBufferSize := os.Getpagesize() * 100
|
chunksBufferSize := os.Getpagesize() * 100
|
||||||
|
logBufferSize := os.Getpagesize()
|
||||||
|
|
||||||
if err := tls.Init(tlsPerfBufferSize, *procfs, extension); err != nil {
|
if err := tls.Init(chunksBufferSize, logBufferSize, *procfs, extension); err != nil {
|
||||||
tlstapper.LogError(err)
|
tlstapper.LogError(err)
|
||||||
return
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tlstapper.UpdateTapTargets(&tls, &tapTargets, *procfs); err != nil {
|
||||||
|
tlstapper.LogError(err)
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// A quick way to instrument libssl.so without PID filtering - used for debuging and troubleshooting
|
// A quick way to instrument libssl.so without PID filtering - used for debuging and troubleshooting
|
||||||
@@ -257,19 +273,17 @@ func startTlsTapper(extension *api.Extension, outputItems chan *api.OutputChanne
|
|||||||
if os.Getenv("MIZU_GLOBAL_SSL_LIBRARY") != "" {
|
if os.Getenv("MIZU_GLOBAL_SSL_LIBRARY") != "" {
|
||||||
if err := tls.GlobalTap(os.Getenv("MIZU_GLOBAL_SSL_LIBRARY")); err != nil {
|
if err := tls.GlobalTap(os.Getenv("MIZU_GLOBAL_SSL_LIBRARY")); err != nil {
|
||||||
tlstapper.LogError(err)
|
tlstapper.LogError(err)
|
||||||
return
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := tlstapper.UpdateTapTargets(&tls, &tapTargets, *procfs); err != nil {
|
|
||||||
tlstapper.LogError(err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
var emitter api.Emitter = &api.Emitting{
|
var emitter api.Emitter = &api.Emitting{
|
||||||
AppStats: &diagnose.AppStats,
|
AppStats: &diagnose.AppStats,
|
||||||
OutputChannel: outputItems,
|
OutputChannel: outputItems,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
go tls.PollForLogging()
|
||||||
go tls.Poll(emitter, options)
|
go tls.Poll(emitter, options)
|
||||||
|
|
||||||
|
return &tls
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,12 +11,20 @@ import (
|
|||||||
const bpfFilterMaxPods = 150
|
const bpfFilterMaxPods = 150
|
||||||
const hostSourcePid = "0"
|
const hostSourcePid = "0"
|
||||||
|
|
||||||
|
type PacketSourceManagerConfig struct {
|
||||||
|
mtls bool
|
||||||
|
procfs string
|
||||||
|
interfaceName string
|
||||||
|
behaviour TcpPacketSourceBehaviour
|
||||||
|
}
|
||||||
|
|
||||||
type PacketSourceManager struct {
|
type PacketSourceManager struct {
|
||||||
sources map[string]*tcpPacketSource
|
sources map[string]*tcpPacketSource
|
||||||
|
config PacketSourceManagerConfig
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewPacketSourceManager(procfs string, filename string, interfaceName string,
|
func NewPacketSourceManager(procfs string, filename string, interfaceName string,
|
||||||
mtls bool, pods []v1.Pod, behaviour TcpPacketSourceBehaviour) (*PacketSourceManager, error) {
|
mtls bool, pods []v1.Pod, behaviour TcpPacketSourceBehaviour, ipdefrag bool, packets chan<- TcpPacketInfo) (*PacketSourceManager, error) {
|
||||||
hostSource, err := newHostPacketSource(filename, interfaceName, behaviour)
|
hostSource, err := newHostPacketSource(filename, interfaceName, behaviour)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -28,7 +36,14 @@ func NewPacketSourceManager(procfs string, filename string, interfaceName string
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceManager.UpdatePods(mtls, procfs, pods, interfaceName, behaviour)
|
sourceManager.config = PacketSourceManagerConfig{
|
||||||
|
mtls: mtls,
|
||||||
|
procfs: procfs,
|
||||||
|
interfaceName: interfaceName,
|
||||||
|
behaviour: behaviour,
|
||||||
|
}
|
||||||
|
|
||||||
|
go hostSource.readPackets(ipdefrag, packets)
|
||||||
return sourceManager, nil
|
return sourceManager, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -49,17 +64,16 @@ func newHostPacketSource(filename string, interfaceName string,
|
|||||||
return source, nil
|
return source, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *PacketSourceManager) UpdatePods(mtls bool, procfs string, pods []v1.Pod,
|
func (m *PacketSourceManager) UpdatePods(pods []v1.Pod, ipdefrag bool, packets chan<- TcpPacketInfo) {
|
||||||
interfaceName string, behaviour TcpPacketSourceBehaviour) {
|
if m.config.mtls {
|
||||||
if mtls {
|
m.updateMtlsPods(m.config.procfs, pods, m.config.interfaceName, m.config.behaviour, ipdefrag, packets)
|
||||||
m.updateMtlsPods(procfs, pods, interfaceName, behaviour)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m.setBPFFilter(pods)
|
m.setBPFFilter(pods)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *PacketSourceManager) updateMtlsPods(procfs string, pods []v1.Pod,
|
func (m *PacketSourceManager) updateMtlsPods(procfs string, pods []v1.Pod,
|
||||||
interfaceName string, behaviour TcpPacketSourceBehaviour) {
|
interfaceName string, behaviour TcpPacketSourceBehaviour, ipdefrag bool, packets chan<- TcpPacketInfo) {
|
||||||
|
|
||||||
relevantPids := m.getRelevantPids(procfs, pods)
|
relevantPids := m.getRelevantPids(procfs, pods)
|
||||||
logger.Log.Infof("Updating mtls pods (new: %v) (current: %v)", relevantPids, m.sources)
|
logger.Log.Infof("Updating mtls pods (new: %v) (current: %v)", relevantPids, m.sources)
|
||||||
@@ -76,6 +90,7 @@ func (m *PacketSourceManager) updateMtlsPods(procfs string, pods []v1.Pod,
|
|||||||
source, err := newNetnsPacketSource(procfs, pid, interfaceName, behaviour)
|
source, err := newNetnsPacketSource(procfs, pid, interfaceName, behaviour)
|
||||||
|
|
||||||
if err == nil {
|
if err == nil {
|
||||||
|
go source.readPackets(ipdefrag, packets)
|
||||||
m.sources[pid] = source
|
m.sources[pid] = source
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -139,12 +154,6 @@ func (m *PacketSourceManager) setBPFFilter(pods []v1.Pod) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *PacketSourceManager) ReadPackets(ipdefrag bool, packets chan<- TcpPacketInfo) {
|
|
||||||
for _, src := range m.sources {
|
|
||||||
go src.readPackets(ipdefrag, packets)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *PacketSourceManager) Close() {
|
func (m *PacketSourceManager) Close() {
|
||||||
for _, src := range m.sources {
|
for _, src := range m.sources {
|
||||||
src.close()
|
src.close()
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ type tcpReader struct {
|
|||||||
isOutgoing bool
|
isOutgoing bool
|
||||||
msgQueue chan tcpReaderDataMsg // Channel of captured reassembled tcp payload
|
msgQueue chan tcpReaderDataMsg // Channel of captured reassembled tcp payload
|
||||||
data []byte
|
data []byte
|
||||||
|
progress *api.ReadProgress
|
||||||
superTimer *api.SuperTimer
|
superTimer *api.SuperTimer
|
||||||
parent *tcpStream
|
parent *tcpStream
|
||||||
packetsSeen uint
|
packetsSeen uint
|
||||||
@@ -80,6 +81,8 @@ func (h *tcpReader) Read(p []byte) (int, error) {
|
|||||||
|
|
||||||
l := copy(p, h.data)
|
l := copy(p, h.data)
|
||||||
h.data = h.data[l:]
|
h.data = h.data[l:]
|
||||||
|
h.progress.Feed(l)
|
||||||
|
|
||||||
return l, nil
|
return l, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,7 +98,8 @@ func (h *tcpReader) Close() {
|
|||||||
func (h *tcpReader) run(wg *sync.WaitGroup) {
|
func (h *tcpReader) run(wg *sync.WaitGroup) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
b := bufio.NewReader(h)
|
b := bufio.NewReader(h)
|
||||||
err := h.extension.Dissector.Dissect(b, h.isClient, h.tcpID, h.counterPair, h.superTimer, h.parent.superIdentifier, h.emitter, filteringOptions, h.reqResMatcher)
|
// TODO: Add api.Pcap, api.Envoy and api.Linkerd distinction by refactoring NewPacketSourceManager method
|
||||||
|
err := h.extension.Dissector.Dissect(b, h.progress, api.Pcap, h.isClient, h.tcpID, h.counterPair, h.superTimer, h.parent.superIdentifier, h.emitter, filteringOptions, h.reqResMatcher)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
_, err = io.Copy(ioutil.Discard, b)
|
_, err = io.Copy(ioutil.Discard, b)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ func (factory *tcpStreamFactory) New(net, transport gopacket.Flow, tcp *layers.T
|
|||||||
}
|
}
|
||||||
stream.clients = append(stream.clients, tcpReader{
|
stream.clients = append(stream.clients, tcpReader{
|
||||||
msgQueue: make(chan tcpReaderDataMsg),
|
msgQueue: make(chan tcpReaderDataMsg),
|
||||||
|
progress: &api.ReadProgress{},
|
||||||
superTimer: &api.SuperTimer{},
|
superTimer: &api.SuperTimer{},
|
||||||
ident: fmt.Sprintf("%s %s", net, transport),
|
ident: fmt.Sprintf("%s %s", net, transport),
|
||||||
tcpID: &api.TcpID{
|
tcpID: &api.TcpID{
|
||||||
@@ -108,6 +109,7 @@ func (factory *tcpStreamFactory) New(net, transport gopacket.Flow, tcp *layers.T
|
|||||||
})
|
})
|
||||||
stream.servers = append(stream.servers, tcpReader{
|
stream.servers = append(stream.servers, tcpReader{
|
||||||
msgQueue: make(chan tcpReaderDataMsg),
|
msgQueue: make(chan tcpReaderDataMsg),
|
||||||
|
progress: &api.ReadProgress{},
|
||||||
superTimer: &api.SuperTimer{},
|
superTimer: &api.SuperTimer{},
|
||||||
ident: fmt.Sprintf("%s %s", net, transport),
|
ident: fmt.Sprintf("%s %s", net, transport),
|
||||||
tcpID: &api.TcpID{
|
tcpID: &api.TcpID{
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
|
pushd "$(dirname "$0")" || exit 1
|
||||||
|
|
||||||
MIZU_HOME=$(realpath ../../../)
|
MIZU_HOME=$(realpath ../../../)
|
||||||
|
|
||||||
docker build -t mizu-ebpf-builder . || exit 1
|
docker build -t mizu-ebpf-builder . || exit 1
|
||||||
@@ -7,6 +9,7 @@ docker build -t mizu-ebpf-builder . || exit 1
|
|||||||
docker run --rm \
|
docker run --rm \
|
||||||
--name mizu-ebpf-builder \
|
--name mizu-ebpf-builder \
|
||||||
-v $MIZU_HOME:/mizu \
|
-v $MIZU_HOME:/mizu \
|
||||||
|
-v $(go env GOPATH):/root/go \
|
||||||
-it mizu-ebpf-builder \
|
-it mizu-ebpf-builder \
|
||||||
sh -c "
|
sh -c "
|
||||||
go generate tap/tlstapper/tls_tapper.go
|
go generate tap/tlstapper/tls_tapper.go
|
||||||
@@ -15,3 +18,5 @@ docker run --rm \
|
|||||||
chown $(id -u):$(id -g) tap/tlstapper/tlstapper_bpfel.go
|
chown $(id -u):$(id -g) tap/tlstapper/tlstapper_bpfel.go
|
||||||
chown $(id -u):$(id -g) tap/tlstapper/tlstapper_bpfel.o
|
chown $(id -u):$(id -g) tap/tlstapper/tlstapper_bpfel.o
|
||||||
" || exit 1
|
" || exit 1
|
||||||
|
|
||||||
|
popd
|
||||||
|
|||||||
@@ -7,8 +7,12 @@ Copyright (C) UP9 Inc.
|
|||||||
#include "include/headers.h"
|
#include "include/headers.h"
|
||||||
#include "include/util.h"
|
#include "include/util.h"
|
||||||
#include "include/maps.h"
|
#include "include/maps.h"
|
||||||
|
#include "include/log.h"
|
||||||
|
#include "include/logger_messages.h"
|
||||||
#include "include/pids.h"
|
#include "include/pids.h"
|
||||||
|
|
||||||
|
#define IPV4_ADDR_LEN (16)
|
||||||
|
|
||||||
struct accept_info {
|
struct accept_info {
|
||||||
__u64* sockaddr;
|
__u64* sockaddr;
|
||||||
__u32* addrlen;
|
__u32* addrlen;
|
||||||
@@ -41,9 +45,7 @@ void sys_enter_accept4(struct sys_enter_accept4_ctx *ctx) {
|
|||||||
long err = bpf_map_update_elem(&accept_syscall_context, &id, &info, BPF_ANY);
|
long err = bpf_map_update_elem(&accept_syscall_context, &id, &info, BPF_ANY);
|
||||||
|
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
char msg[] = "Error putting accept info (id: %ld) (err: %ld)";
|
log_error(ctx, LOG_ERROR_PUTTING_ACCEPT_INFO, id, err, 0l);
|
||||||
bpf_trace_printk(msg, sizeof(msg), id, err);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,7 +71,8 @@ void sys_exit_accept4(struct sys_exit_accept4_ctx *ctx) {
|
|||||||
|
|
||||||
struct accept_info *infoPtr = bpf_map_lookup_elem(&accept_syscall_context, &id);
|
struct accept_info *infoPtr = bpf_map_lookup_elem(&accept_syscall_context, &id);
|
||||||
|
|
||||||
if (infoPtr == 0) {
|
if (infoPtr == NULL) {
|
||||||
|
log_error(ctx, LOG_ERROR_GETTING_ACCEPT_INFO, id, 0l, 0l);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,15 +82,14 @@ void sys_exit_accept4(struct sys_exit_accept4_ctx *ctx) {
|
|||||||
bpf_map_delete_elem(&accept_syscall_context, &id);
|
bpf_map_delete_elem(&accept_syscall_context, &id);
|
||||||
|
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
char msg[] = "Error reading accept info from accept syscall (id: %ld) (err: %ld)";
|
log_error(ctx, LOG_ERROR_READING_ACCEPT_INFO, id, err, 0l);
|
||||||
bpf_trace_printk(msg, sizeof(msg), id, err);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
__u32 addrlen;
|
__u32 addrlen;
|
||||||
bpf_probe_read(&addrlen, sizeof(__u32), info.addrlen);
|
bpf_probe_read(&addrlen, sizeof(__u32), info.addrlen);
|
||||||
|
|
||||||
if (addrlen != 16) {
|
if (addrlen != IPV4_ADDR_LEN) {
|
||||||
// Currently only ipv4 is supported linux-src/include/linux/inet.h
|
// Currently only ipv4 is supported linux-src/include/linux/inet.h
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -105,9 +107,7 @@ void sys_exit_accept4(struct sys_exit_accept4_ctx *ctx) {
|
|||||||
err = bpf_map_update_elem(&file_descriptor_to_ipv4, &key, &fdinfo, BPF_ANY);
|
err = bpf_map_update_elem(&file_descriptor_to_ipv4, &key, &fdinfo, BPF_ANY);
|
||||||
|
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
char msg[] = "Error putting fd to address mapping from accept (key: %ld) (err: %ld)";
|
log_error(ctx, LOG_ERROR_PUTTING_FD_MAPPING, id, err, ORIGIN_SYS_EXIT_ACCEPT4_CODE);
|
||||||
bpf_trace_printk(msg, sizeof(msg), key, err);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,9 +145,7 @@ void sys_enter_connect(struct sys_enter_connect_ctx *ctx) {
|
|||||||
long err = bpf_map_update_elem(&connect_syscall_info, &id, &info, BPF_ANY);
|
long err = bpf_map_update_elem(&connect_syscall_info, &id, &info, BPF_ANY);
|
||||||
|
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
char msg[] = "Error putting connect info (id: %ld) (err: %ld)";
|
log_error(ctx, LOG_ERROR_PUTTING_CONNECT_INFO, id, err, 0l);
|
||||||
bpf_trace_printk(msg, sizeof(msg), id, err);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,7 +173,8 @@ void sys_exit_connect(struct sys_exit_connect_ctx *ctx) {
|
|||||||
|
|
||||||
struct connect_info *infoPtr = bpf_map_lookup_elem(&connect_syscall_info, &id);
|
struct connect_info *infoPtr = bpf_map_lookup_elem(&connect_syscall_info, &id);
|
||||||
|
|
||||||
if (infoPtr == 0) {
|
if (infoPtr == NULL) {
|
||||||
|
log_error(ctx, LOG_ERROR_GETTING_CONNECT_INFO, id, 0l, 0l);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,12 +184,11 @@ void sys_exit_connect(struct sys_exit_connect_ctx *ctx) {
|
|||||||
bpf_map_delete_elem(&connect_syscall_info, &id);
|
bpf_map_delete_elem(&connect_syscall_info, &id);
|
||||||
|
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
char msg[] = "Error reading connect info from connect syscall (id: %ld) (err: %ld)";
|
log_error(ctx, LOG_ERROR_READING_CONNECT_INFO, id, err, 0l);
|
||||||
bpf_trace_printk(msg, sizeof(msg), id, err);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info.addrlen != 16) {
|
if (info.addrlen != IPV4_ADDR_LEN) {
|
||||||
// Currently only ipv4 is supported linux-src/include/linux/inet.h
|
// Currently only ipv4 is supported linux-src/include/linux/inet.h
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -208,8 +206,6 @@ void sys_exit_connect(struct sys_exit_connect_ctx *ctx) {
|
|||||||
err = bpf_map_update_elem(&file_descriptor_to_ipv4, &key, &fdinfo, BPF_ANY);
|
err = bpf_map_update_elem(&file_descriptor_to_ipv4, &key, &fdinfo, BPF_ANY);
|
||||||
|
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
char msg[] = "Error putting fd to address mapping from connect (key: %ld) (err: %ld)";
|
log_error(ctx, LOG_ERROR_PUTTING_FD_MAPPING, id, err, ORIGIN_SYS_EXIT_CONNECT_CODE);
|
||||||
bpf_trace_printk(msg, sizeof(msg), key, err);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ Copyright (C) UP9 Inc.
|
|||||||
#include "include/headers.h"
|
#include "include/headers.h"
|
||||||
#include "include/util.h"
|
#include "include/util.h"
|
||||||
#include "include/maps.h"
|
#include "include/maps.h"
|
||||||
|
#include "include/log.h"
|
||||||
|
#include "include/logger_messages.h"
|
||||||
#include "include/pids.h"
|
#include "include/pids.h"
|
||||||
|
|
||||||
struct sys_enter_read_ctx {
|
struct sys_enter_read_ctx {
|
||||||
@@ -28,7 +30,7 @@ void sys_enter_read(struct sys_enter_read_ctx *ctx) {
|
|||||||
|
|
||||||
struct ssl_info *infoPtr = bpf_map_lookup_elem(&ssl_read_context, &id);
|
struct ssl_info *infoPtr = bpf_map_lookup_elem(&ssl_read_context, &id);
|
||||||
|
|
||||||
if (infoPtr == 0) {
|
if (infoPtr == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,8 +38,7 @@ void sys_enter_read(struct sys_enter_read_ctx *ctx) {
|
|||||||
long err = bpf_probe_read(&info, sizeof(struct ssl_info), infoPtr);
|
long err = bpf_probe_read(&info, sizeof(struct ssl_info), infoPtr);
|
||||||
|
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
char msg[] = "Error reading read info from read syscall (id: %ld) (err: %ld)";
|
log_error(ctx, LOG_ERROR_READING_SSL_CONTEXT, id, err, ORIGIN_SYS_ENTER_READ_CODE);
|
||||||
bpf_trace_printk(msg, sizeof(msg), id, err);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,9 +47,7 @@ void sys_enter_read(struct sys_enter_read_ctx *ctx) {
|
|||||||
err = bpf_map_update_elem(&ssl_read_context, &id, &info, BPF_ANY);
|
err = bpf_map_update_elem(&ssl_read_context, &id, &info, BPF_ANY);
|
||||||
|
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
char msg[] = "Error putting file descriptor from read syscall (id: %ld) (err: %ld)";
|
log_error(ctx, LOG_ERROR_PUTTING_FILE_DESCRIPTOR, id, err, ORIGIN_SYS_ENTER_READ_CODE);
|
||||||
bpf_trace_printk(msg, sizeof(msg), id, err);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -71,7 +70,7 @@ void sys_enter_write(struct sys_enter_write_ctx *ctx) {
|
|||||||
|
|
||||||
struct ssl_info *infoPtr = bpf_map_lookup_elem(&ssl_write_context, &id);
|
struct ssl_info *infoPtr = bpf_map_lookup_elem(&ssl_write_context, &id);
|
||||||
|
|
||||||
if (infoPtr == 0) {
|
if (infoPtr == NULL) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,8 +78,7 @@ void sys_enter_write(struct sys_enter_write_ctx *ctx) {
|
|||||||
long err = bpf_probe_read(&info, sizeof(struct ssl_info), infoPtr);
|
long err = bpf_probe_read(&info, sizeof(struct ssl_info), infoPtr);
|
||||||
|
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
char msg[] = "Error reading write context from write syscall (id: %ld) (err: %ld)";
|
log_error(ctx, LOG_ERROR_READING_SSL_CONTEXT, id, err, ORIGIN_SYS_ENTER_WRITE_CODE);
|
||||||
bpf_trace_printk(msg, sizeof(msg), id, err);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,8 +87,6 @@ void sys_enter_write(struct sys_enter_write_ctx *ctx) {
|
|||||||
err = bpf_map_update_elem(&ssl_write_context, &id, &info, BPF_ANY);
|
err = bpf_map_update_elem(&ssl_write_context, &id, &info, BPF_ANY);
|
||||||
|
|
||||||
if (err != 0) {
|
if (err != 0) {
|
||||||
char msg[] = "Error putting file descriptor from write syscall (id: %ld) (err: %ld)";
|
log_error(ctx, LOG_ERROR_PUTTING_FILE_DESCRIPTOR, id, err, ORIGIN_SYS_ENTER_WRITE_CODE);
|
||||||
bpf_trace_printk(msg, sizeof(msg), id, err);
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
79
tap/tlstapper/bpf/include/log.h
Normal file
79
tap/tlstapper/bpf/include/log.h
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
Note: This file is licenced differently from the rest of the project
|
||||||
|
SPDX-License-Identifier: GPL-2.0
|
||||||
|
Copyright (C) UP9 Inc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __LOG__
|
||||||
|
#define __LOG__
|
||||||
|
|
||||||
|
// The same consts defined in bpf_logger.go
|
||||||
|
//
|
||||||
|
#define LOG_LEVEL_ERROR (0)
|
||||||
|
#define LOG_LEVEL_INFO (1)
|
||||||
|
#define LOG_LEVEL_DEBUG (2)
|
||||||
|
|
||||||
|
// The same struct can be found in bpf_logger.go
|
||||||
|
//
|
||||||
|
// Be careful when editing, alignment and padding should be exactly the same in go/c.
|
||||||
|
//
|
||||||
|
struct log_message {
|
||||||
|
__u32 level;
|
||||||
|
__u32 message_code;
|
||||||
|
__u64 arg1;
|
||||||
|
__u64 arg2;
|
||||||
|
__u64 arg3;
|
||||||
|
};
|
||||||
|
|
||||||
|
static __always_inline void log_error(void* ctx, __u16 message_code, __u64 arg1, __u64 arg2, __u64 arg3) {
|
||||||
|
struct log_message entry = {};
|
||||||
|
|
||||||
|
entry.level = LOG_LEVEL_ERROR;
|
||||||
|
entry.message_code = message_code;
|
||||||
|
entry.arg1 = arg1;
|
||||||
|
entry.arg2 = arg2;
|
||||||
|
entry.arg3 = arg3;
|
||||||
|
|
||||||
|
long err = bpf_perf_event_output(ctx, &log_buffer, BPF_F_CURRENT_CPU, &entry, sizeof(struct log_message));
|
||||||
|
|
||||||
|
if (err != 0) {
|
||||||
|
char msg[] = "Error writing log error to perf buffer - %ld";
|
||||||
|
bpf_trace_printk(msg, sizeof(msg), err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static __always_inline void log_info(void* ctx, __u16 message_code, __u64 arg1, __u64 arg2, __u64 arg3) {
|
||||||
|
struct log_message entry = {};
|
||||||
|
|
||||||
|
entry.level = LOG_LEVEL_INFO;
|
||||||
|
entry.message_code = message_code;
|
||||||
|
entry.arg1 = arg1;
|
||||||
|
entry.arg2 = arg2;
|
||||||
|
entry.arg3 = arg3;
|
||||||
|
|
||||||
|
long err = bpf_perf_event_output(ctx, &log_buffer, BPF_F_CURRENT_CPU, &entry, sizeof(struct log_message));
|
||||||
|
|
||||||
|
if (err != 0) {
|
||||||
|
char msg[] = "Error writing log info to perf buffer - %ld";
|
||||||
|
bpf_trace_printk(msg, sizeof(msg), arg1, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static __always_inline void log_debug(void* ctx, __u16 message_code, __u64 arg1, __u64 arg2, __u64 arg3) {
|
||||||
|
struct log_message entry = {};
|
||||||
|
|
||||||
|
entry.level = LOG_LEVEL_DEBUG;
|
||||||
|
entry.message_code = message_code;
|
||||||
|
entry.arg1 = arg1;
|
||||||
|
entry.arg2 = arg2;
|
||||||
|
entry.arg3 = arg3;
|
||||||
|
|
||||||
|
long err = bpf_perf_event_output(ctx, &log_buffer, BPF_F_CURRENT_CPU, &entry, sizeof(struct log_message));
|
||||||
|
|
||||||
|
if (err != 0) {
|
||||||
|
char msg[] = "Error writing log debug to perf buffer - %ld";
|
||||||
|
bpf_trace_printk(msg, sizeof(msg), arg1, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* __LOG__ */
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user