Compare commits

..

48 Commits

Author SHA1 Message Date
Nimrod Gilboa Markevich
692c500b0f Improve Go TLS address availability (#1207)
Fetch source and destination addresses with bpf from tcp kprobes, similar to how it is done for openssl lib.
Chunk contains both source address and destination address.
FD is no longer used to obtain addresses.
2022-07-19 14:31:27 +03:00
gadotroee
5525214d0a Fix memory of acceptanceTests minikube cluster (#1209) 2022-07-19 12:55:44 +03:00
RoyIsland
efd414a2ed Removed telemetry (#1208) 2022-07-19 12:29:48 +03:00
AmitUp9
b3e79ff244 Grooming Traffic Stats Modal - change font and time picker position (#1206)
* font change and time picker position update

* add font-family to variables scss
2022-07-17 17:19:44 +03:00
AmitUp9
d4b9fea5a7 fix elastic time picker ui css (#1204) 2022-07-14 11:11:05 +03:00
leon-up9
d11770681b full height (#1202)
Co-authored-by: Leon <>
2022-07-13 18:37:22 +03:00
gadotroee
e9719cba3a Add time range to stats (#1199) 2022-07-13 17:21:18 +03:00
leon-up9
15f7b889e2 height change (#1201)
Co-authored-by: Leon <>
2022-07-13 13:37:08 +03:00
RoyUP9
d98ac0e8f7 Removed redundant IgnoredUserAgents field (#1198) 2022-07-12 20:41:42 +03:00
gadotroee
a3c236ff0a Fix colors map initialization (#1200) 2022-07-12 20:05:21 +03:00
gadotroee
4b280ecd6d Hide Response tab if there is no response (#1197) 2022-07-12 18:38:39 +03:00
leon-up9
de554f5fb6 ui/ include scss files in common (#1195)
* include scss files

* exported color

Co-authored-by: Leon <>
2022-07-12 11:50:24 +03:00
RoyUP9
7c159fffc0 Added redact using insertion filter (#1196) 2022-07-12 10:19:24 +03:00
M. Mert Yıldıran
1f2f63d11b Implement AMQP request-response matcher (#1091)
* Implement the basis of AMQP request-response matching

* Fix `package.json`

* Add `ExchangeDeclareOk`

* Add `ConnectionCloseOk`

* Add `BasicConsumeOk`

* Add `QueueBindOk`

* Add `representEmptyResponse` and fix `BasicPublish` and `BasicDeliver`

* Fix ident and matcher, add `connectionOpen`, `channelOpen`, `connectionTune`, `basicCancel`

* Fix linter

* Fix the unit tests

* #run_acceptance_tests

* #run_acceptance_tests

* Fix the tests #run_acceptance_tests

* Log don't panic

* Don't skip AMQP acceptance tests #run_acceptance_tests

* Revert "Don't skip AMQP acceptance tests #run_acceptance_tests"

This reverts commit c60e9cf747.

* Remove `Details` section from `representEmpty`

* Add `This request or response has no data.` text
2022-07-11 17:33:25 +03:00
RoyUP9
e2544aea12 Remove duplication of Headers, Cookies and QueryString (#1192) 2022-07-11 13:16:22 +03:00
Nimrod Gilboa Markevich
57e60073f5 Generate bpf files before running tests (#1194) 2022-07-11 12:31:45 +03:00
Nimrod Gilboa Markevich
f220ad2f1a Delete ebpf object files (#1190)
Do not track object files in git.
Generate the files with `make bpf` or during `make agent`.
2022-07-11 12:08:20 +03:00
RoyUP9
5875ba0eb3 Fixed panic in socket cleanup (#1193) 2022-07-11 11:18:58 +03:00
leon-up9
9aaf3f1423 Ui/Download request replay (#1188)
* added icon

* download & upload

* button changes

* clean up

* changes

* pkj json

* img

* removed codeEditor options

* changes

Co-authored-by: Leon <>
2022-07-10 16:48:18 +03:00
Nimrod Gilboa Markevich
a2463b739a Improve tls info for openssl with kprobes (#1177)
Instead of going through the socket fd, addresses are obtained in kprobe/tcp_sendmsg on ssl write and kprobe/tcp_recvmsg on ssl read. The tcp kprobes and the openssl uprobes communicate through the id->sslInfo bpf map.
2022-07-07 19:11:54 +03:00
AmitUp9
c010d336bb add date to timeline ticks (#1191) 2022-07-07 14:09:41 +03:00
RoyUP9
710411e112 Replaced ProtocolId with Protocol Summary (#1189) 2022-07-07 12:05:59 +03:00
AmitUp9
274fbeb34a warning cleaning from console (#1187)
* warning cleaning from console

* code cleaning
2022-07-06 13:13:04 +03:00
leon-up9
38c05a6634 UI/feature flag for replay modal (#1186)
* context added

* import added

* chnages

* ui enabled

* moved to Consts

* changes to recoil

* change

* new useEffect

Co-authored-by: Leon <>
2022-07-06 11:19:46 +03:00
leon-up9
d857935889 move icon to right side (#1185)
Co-authored-by: Leon <>
2022-07-05 16:35:03 +03:00
gadotroee
ec11b21b51 Add available protocols to the stats endpoint (colors for methods are coming from server) (#1184)
* add protocols array to the endpoint

* no message

* no message

* fix tests and small fix for the iteration

* fix the color of the protocol

* Get protocols list and method colors from server

* fix tests

* cr fixes

Co-authored-by: Amit Fainholts <amit@up9.com>
2022-07-05 15:30:39 +03:00
M. Mert Yıldıran
52c9251c00 Add ABI0 support to Go crypto/tls eBPF tracer (#1169)
* Determine the Go ABI and get `goid` offset from DWARF

* Add `ABI` enum and morph the function according to the detected ABI

* Pass `goid` offset to an eBPF map to retrieve it in eBPF context

* Add `vmlinux.h` and implement `get_goid_from_thread_local_storage`

* Fix BPF verifier errors

* Update the comments

* Add `go_abi_0.h` and implement `ABI0` specific reads for `arm64`

* Upgrade `github.com/cilium/ebpf` to `v0.9.0`

* Add a comment

* Add macros for x86 specific parts

* Update `x86.o`

* Fix the map key type

* Add `user_pt_regs`

* Update arm64 object file

* Fix the version detection logic

* Add `getGStructOffset` method

* Define `goid_offsets`, `goid_offsets_map` structs and pass the offsets correctly

* Fix the `net.TCPConn` and buffer addresses for `ABI0`

* Remove comment

* Fix the issues for arm64 build

* Update x86.o

* Revert "Fix the issues for arm64 build"

This reverts commit 48b041b1b6.

* Revert `user_pt_regs`

* Add `vmlinux` directory

* Fix the `build.sh` and `Dockerfile`

* Add vmlinux_arm64.h

* Disable `get_goid_from_thread_local_storage` on ARM64 with a macro

* Update x86.o

* Update arm64.o

* x86

* arm64

* Fix the cross-compilation issue from x86 to arm64

* Fix the same thing for x86

* Use `BPF_CORE_READ` macro instead of `bpf_ringbuf_reserve` to support kernel versions older than 5.8

Also;
Add legacy version of thread_struct: thread_struct___v46
Build an additional object file for the kernel versions older than or equal to 4.6 and load them accordingly.
Add github.com/moby/moby

* Make #define directives more definitive

* Select the x86 and arm64 versions of `vmlinux.h` using macros

* Put `goid` offsets into the map before installing `uprobe`(s)

* arm64

* #run_acceptance_tests

* Remove a forgotten `fmt.Printf`

* Log the detected Linux kernel version
2022-07-05 14:35:30 +03:00
leon-up9
f3a6b3a9d4 with loading HOC (#1181)
* withLoading

* optional props

* LoadingWrapper

* pr comments

* changes

Co-authored-by: Leon <>
2022-07-05 12:23:47 +03:00
leon-up9
5f73c2d50a allow skipping formating error (#1183)
Co-authored-by: Leon <>
2022-07-04 16:24:23 +03:00
gadotroee
d6944d467c Merge traffic stats endpoints to one and add auto interval logic (#1174) 2022-07-04 10:01:49 +03:00
leon-up9
57078517a4 Ui/replay demo notes (#1180)
* close ws on open

* chech if json before parsing

* setting defualt tab reponse and missing dep

* remove redundant

* space

* PR fixes

* remove redundant

* changed order

* Revert "remove redundant"

This reverts commit 2f0bef5d33.

* revert order change

* changes

* change

* changes

Co-authored-by: Leon <>
2022-07-03 15:36:16 +03:00
AmitUp9
b4bc09637c fix select in traffic stats ui (#1179) 2022-07-03 11:48:38 +03:00
lirazyehezkel
302333b4ae TRA-4622 Remove rules feature UI (#1178)
* Removed policy rules (validation rules) feature

* updated test pcap

* Remove rules

* fix replay in rules

Co-authored-by: Roy Island <roy@up9.com>
Co-authored-by: RoyUP9 <87927115+RoyUP9@users.noreply.github.com>
Co-authored-by: Roee Gadot <roee.gadot@up9.com>
2022-07-03 11:32:23 +03:00
leon-up9
13ed8eb58a Ui/TRA-4607 - replay mizu requests (#1165)
* modal & keyValueTable added

* added pulse animation
KeyValueTable Behavior improved
CodeEditor addded

* style changed

* codeEditor styling
support query params

* send request data

* finally stop loading

* select width

* methods and requesr format

* icon changed & moved near request tab

* accordions added and response presented

* 2 way params biding

* remove redundant

* host path fixed

* fix path input

* icon styles

* fallback for format body

* refresh button

* changes

* remove redundant

* closing tag

* capitilized character

* PR comments

* removed props

* small changes

* color added to reponse data

Co-authored-by: Leon <>
2022-07-03 09:48:56 +03:00
David Levanon
48619b3e1c fix small regression with openssl (#1176) 2022-06-30 17:39:03 +03:00
AmitUp9
3b0b311e1e TRA_4623 - methods view on timeline stats with coordination to the pie stats (#1175)
* Add select protocol → when selected, the view will be on commands of that exact protocol

* CR fixes

* added const instead of free string

* remove redundant sass file
2022-06-30 13:35:08 +03:00
gadotroee
3a9236a381 Fix replay to be like the test (#1173)
Represent should get entry that Marshaled and UnMarshaled
2022-06-29 11:54:16 +03:00
AmitUp9
2e7fd34210 Move general functions from timeline stats to helpers utils (#1170)
* no message

* format document
2022-06-29 11:15:22 +03:00
gadotroee
01af6aa19c Add reply endpoint for http (#1168) 2022-06-28 18:39:23 +03:00
David Levanon
2bfae1baae allow to configure max live streams from mizu cli (#1172)
* allow to configure max live streams from mizu cli

* Update cli/cmd/tap.go

Co-authored-by: Nimrod Gilboa Markevich <59927337+nimrod-up9@users.noreply.github.com>

Co-authored-by: Nimrod Gilboa Markevich <59927337+nimrod-up9@users.noreply.github.com>
2022-06-28 14:41:47 +03:00
RoyUP9
2df9fb49db Changed entry protocol field from struct to unique string (#1167) 2022-06-26 17:08:09 +03:00
M. Mert Yıldıran
c1b2cda468 Change the log level from ERROR to INFO for cases; not a Go binary or symbol table is stripped (#1164) 2022-06-26 15:25:26 +03:00
M. Mert Yıldıran
cf91f3dab4 Fix Go crypto/tls eBPF tracer on ARM64 (#1162)
* Handle the Go `ABIInternal` differences on ARM64

* Log the Capstone version, arch and mode

* Upgrade Capstone from `4.0.2` to `5.0-rc2` to have ARM64 instructions fix

* Use the correct register on ARM64 for reading buffer length

* Fix the addresses on ARM64

* #run_acceptance_tests

* Update `x86.o`

* Update `arm64.o`

* #run_acceptance_tests
2022-06-26 14:11:04 +03:00
RoyUP9
1ebc51b45e Remove OAS contract monitoring feature (#1163) 2022-06-26 12:22:25 +03:00
gadotroee
a96072623f Fix problems that golang inspection reported (#1158) 2022-06-23 16:49:56 +03:00
gadotroee
8c187179b0 Adding tests to the bucket statistics (#1160) 2022-06-23 11:04:12 +03:00
lirazyehezkel
d7d802830f TRA-4274 fix ui common linter issues (#1161)
* fix lint issues

* fix all ui-common line issues

* max warnings 0
2022-06-22 09:56:27 +03:00
AmitUp9
4d64dd4b04 TRA-4602_timeline bar charts to traffic statistics (#1159)
* pie chart for protocols and methods by requests and volume

* protocols legend

* timeline bar chart component created

* timeline can view requests and volume

* sorting the bra charts by timestemp

* disable view of <1% pieces in pie

* space added to the end of the file

* package.json update

* cr fixes

* remove spave

* remove unnecessary react fragment

Co-authored-by: Liraz Yehezkel <lirazy@up9.com>
2022-06-21 14:54:56 +03:00
219 changed files with 347072 additions and 14143 deletions

View File

@@ -32,6 +32,10 @@ jobs:
id: agent_modified_files id: agent_modified_files
run: devops/check_modified_files.sh agent/ run: devops/check_modified_files.sh agent/
- name: Generate eBPF object files and go bindings
id: generate_ebpf
run: make bpf
- 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' if: steps.agent_modified_files.outputs.matched == 'true'

View File

@@ -40,6 +40,10 @@ jobs:
run: | run: |
./devops/install-capstone.sh ./devops/install-capstone.sh
- name: Generate eBPF object files and go bindings
id: generate_ebpf
run: make bpf
- 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/

3
.gitignore vendored
View File

@@ -56,3 +56,6 @@ tap/extensions/*/expect
# Ignore *.log files # Ignore *.log files
*.log *.log
# Object files
*.o

View File

@@ -54,14 +54,14 @@ ENV BPF_TARGET=arm64 BPF_CFLAGS="-O2 -g -D__TARGET_ARCH_arm64"
### Builder image for x86-64 to AArch64 cross-compilation ### Builder image for x86-64 to AArch64 cross-compilation
FROM up9inc/linux-arm64-musl-go-libpcap-capstone-bpf AS builder-from-amd64-to-arm64v8 FROM up9inc/linux-arm64-musl-go-libpcap-capstone-bpf:capstone-5.0-rc2 AS builder-from-amd64-to-arm64v8
ENV CGO_ENABLED=1 GOOS=linux ENV CGO_ENABLED=1 GOOS=linux
ENV GOARCH=arm64 CGO_CFLAGS="-I/work/libpcap -I/work/capstone/include" ENV GOARCH=arm64 CGO_CFLAGS="-I/work/libpcap -I/work/capstone/include"
ENV BPF_TARGET=arm64 BPF_CFLAGS="-O2 -g -D__TARGET_ARCH_arm64 -I/usr/xcc/aarch64-linux-musl-cross/aarch64-linux-musl/include/" ENV BPF_TARGET=arm64 BPF_CFLAGS="-O2 -g -D__TARGET_ARCH_arm64 -I/usr/xcc/aarch64-linux-musl-cross/aarch64-linux-musl/include/"
### Builder image for AArch64 to x86-64 cross-compilation ### Builder image for AArch64 to x86-64 cross-compilation
FROM up9inc/linux-x86_64-musl-go-libpcap-capstone-bpf AS builder-from-arm64v8-to-amd64 FROM up9inc/linux-x86_64-musl-go-libpcap-capstone-bpf:capstone-5.0-rc2 AS builder-from-arm64v8-to-amd64
ENV CGO_ENABLED=1 GOOS=linux ENV CGO_ENABLED=1 GOOS=linux
ENV GOARCH=amd64 CGO_CFLAGS="-I/libpcap -I/capstone/include" ENV GOARCH=amd64 CGO_CFLAGS="-I/libpcap -I/capstone/include"
ENV BPF_TARGET=amd64 BPF_CFLAGS="-O2 -g -D__TARGET_ARCH_x86 -I/usr/local/musl/x86_64-unknown-linux-musl/include/" ENV BPF_TARGET=amd64 BPF_CFLAGS="-O2 -g -D__TARGET_ARCH_x86 -I/usr/local/musl/x86_64-unknown-linux-musl/include/"

View File

@@ -8,7 +8,7 @@ SHELL=/bin/bash
# HELP # HELP
# This will output the help for each task # This will output the help for each task
# thanks to https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html # thanks to https://marmelab.com/blog/2016/02/29/auto-documented-makefile.html
.PHONY: help ui agent agent-debug cli tap docker .PHONY: help ui agent agent-debug cli tap docker bpf clean-bpf
help: ## This help. help: ## This help.
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST)
@@ -20,6 +20,13 @@ TS_SUFFIX="$(shell date '+%s')"
GIT_BRANCH="$(shell git branch | grep \* | cut -d ' ' -f2 | tr '[:upper:]' '[:lower:]' | tr '/' '_')" GIT_BRANCH="$(shell git branch | grep \* | cut -d ' ' -f2 | tr '[:upper:]' '[:lower:]' | tr '/' '_')"
BUCKET_PATH=static.up9.io/mizu/$(GIT_BRANCH) BUCKET_PATH=static.up9.io/mizu/$(GIT_BRANCH)
export VER?=0.0 export VER?=0.0
ARCH=$(shell uname -m)
ifeq ($(ARCH),$(filter $(ARCH),aarch64 arm64))
BPF_O_ARCH_LABEL=arm64
else
BPF_O_ARCH_LABEL=x86
endif
BPF_O_FILES = tap/tlstapper/tlstapper46_bpfel_$(BPF_O_ARCH_LABEL).o tap/tlstapper/tlstapper_bpfel_$(BPF_O_ARCH_LABEL).o
ui: ## Build UI. ui: ## Build UI.
@(cd ui; npm i ; npm run build; ) @(cd ui; npm i ; npm run build; )
@@ -31,11 +38,17 @@ cli: ## Build CLI.
cli-debug: ## Build CLI. cli-debug: ## Build CLI.
@echo "building cli"; cd cli && $(MAKE) build-debug @echo "building cli"; cd cli && $(MAKE) build-debug
agent: ## Build agent. agent: bpf ## Build agent.
@(echo "building mizu agent .." ) @(echo "building mizu agent .." )
@(cd agent; go build -o build/mizuagent main.go) @(cd agent; go build -o build/mizuagent main.go)
@ls -l agent/build @ls -l agent/build
bpf: $(BPF_O_FILES)
$(BPF_O_FILES): $(wildcard tap/tlstapper/bpf/**/*.[ch])
@(echo "building tlstapper bpf")
@(./tap/tlstapper/bpf-builder/build.sh)
agent-debug: ## Build agent for debug. agent-debug: ## Build agent for debug.
@(echo "building mizu agent for debug.." ) @(echo "building mizu agent for debug.." )
@(cd agent; go build -gcflags="all=-N -l" -o build/mizuagent main.go) @(cd agent; go build -gcflags="all=-N -l" -o build/mizuagent main.go)
@@ -76,6 +89,9 @@ clean-cli: ## Clean CLI.
clean-docker: ## Run clean docker clean-docker: ## Run clean docker
@(echo "DOCKER cleanup - NOT IMPLEMENTED YET " ) @(echo "DOCKER cleanup - NOT IMPLEMENTED YET " )
clean-bpf:
@(rm $(BPF_O_FILES) ; echo "bpf cleanup done" )
test-lint: ## Run lint on all modules test-lint: ## Run lint on all modules
cd agent && golangci-lint run cd agent && golangci-lint run
cd shared && golangci-lint run cd shared && golangci-lint run

View File

@@ -11,7 +11,6 @@ module.exports = defineConfig({
testUrl: 'http://localhost:8899/', testUrl: 'http://localhost:8899/',
redactHeaderContent: 'User-Header[REDACTED]', redactHeaderContent: 'User-Header[REDACTED]',
redactBodyContent: '{ "User": "[REDACTED]" }', redactBodyContent: '{ "User": "[REDACTED]" }',
regexMaskingBodyContent: '[REDACTED]',
greenFilterColor: 'rgb(210, 250, 210)', greenFilterColor: 'rgb(210, 250, 210)',
redFilterColor: 'rgb(250, 214, 220)', redFilterColor: 'rgb(250, 214, 220)',
bodyJsonClass: '.hljs', bodyJsonClass: '.hljs',

View File

@@ -1,7 +0,0 @@
import {isValueExistsInElement} from "../testHelpers/TrafficHelper";
it('Loading Mizu', function () {
cy.visit(Cypress.env('testUrl'));
});
isValueExistsInElement(true, Cypress.env('regexMaskingBodyContent'), Cypress.env('bodyJsonClass'));

View File

@@ -18,7 +18,6 @@ require (
github.com/fsnotify/fsnotify v1.5.1 // indirect github.com/fsnotify/fsnotify v1.5.1 // indirect
github.com/go-logr/logr v1.2.2 // indirect github.com/go-logr/logr v1.2.2 // 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/protobuf v1.5.2 // indirect github.com/golang/protobuf v1.5.2 // 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
@@ -29,7 +28,6 @@ require (
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 // indirect github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
github.com/up9inc/mizu/logger v0.0.0 // 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
golang.org/x/sys v0.0.0-20220207234003-57398862261d // indirect golang.org/x/sys v0.0.0-20220207234003-57398862261d // indirect

View File

@@ -206,7 +206,6 @@ github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zV
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.0.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang-jwt/jwt/v4 v4.2.0 h1:besgBTC8w8HjP6NzQdxwKH9Z5oQMZ24ThTrHp3cZ8eU=
github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= github.com/golang-jwt/jwt/v4 v4.2.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=

View File

@@ -27,7 +27,7 @@ else
fi fi
echo "Starting minikube..." echo "Starting minikube..."
minikube start --cpus 2 --memory 6946 minikube start --cpus 2 --memory 6000
echo "Creating mizu tests namespaces" echo "Creating mizu tests namespaces"
kubectl create namespace mizu-tests --dry-run=client -o yaml | kubectl apply -f - kubectl create namespace mizu-tests --dry-run=client -o yaml | kubectl apply -f -
@@ -57,7 +57,6 @@ kubectl expose deployment redis --type=LoadBalancer --port=6379 -n mizu-tests --
echo "Creating rabbitmq service" echo "Creating rabbitmq service"
kubectl expose deployment rabbitmq --type=LoadBalancer --port=5672 -n mizu-tests --dry-run=client -o yaml | kubectl apply -f - kubectl expose deployment rabbitmq --type=LoadBalancer --port=5672 -n mizu-tests --dry-run=client -o yaml | kubectl apply -f -
# TODO: need to understand how to fail if address already in use
echo "Starting proxy" echo "Starting proxy"
rm -f ${PROXY_LOG} rm -f ${PROXY_LOG}
kubectl proxy --port=8080 > ${PROXY_LOG} & kubectl proxy --port=8080 > ${PROXY_LOG} &
@@ -78,7 +77,6 @@ minikube image load "${MIZU_CI_IMAGE}"
echo "Build cli" echo "Build cli"
cd cli && make build GIT_BRANCH=ci SUFFIX=ci cd cli && make build GIT_BRANCH=ci SUFFIX=ci
# TODO: need to understand how to fail if password is asked (sudo)
echo "Starting tunnel" echo "Starting tunnel"
rm -f ${TUNNEL_LOG} rm -f ${TUNNEL_LOG}
minikube tunnel > ${TUNNEL_LOG} & minikube tunnel > ${TUNNEL_LOG} &

View File

@@ -2,10 +2,8 @@ package acceptanceTests
import ( import (
"archive/zip" "archive/zip"
"bytes"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net/http"
"os/exec" "os/exec"
"path" "path"
"strings" "strings"
@@ -343,7 +341,7 @@ func TestTapRedact(t *testing.T) {
tapNamespace := GetDefaultTapNamespace() tapNamespace := GetDefaultTapNamespace()
tapCmdArgs = append(tapCmdArgs, tapNamespace...) tapCmdArgs = append(tapCmdArgs, tapNamespace...)
tapCmdArgs = append(tapCmdArgs, "--redact") tapCmdArgs = append(tapCmdArgs, "--redact", "--set", "tap.redact-patterns.request-headers=User-Header", "--set", "tap.redact-patterns.request-body=User")
tapCmd := exec.Command(cliPath, tapCmdArgs...) tapCmd := exec.Command(cliPath, tapCmdArgs...)
t.Logf("running command: %v", tapCmd.String()) t.Logf("running command: %v", tapCmd.String())
@@ -429,60 +427,6 @@ func TestTapNoRedact(t *testing.T) {
RunCypressTests(t, "npx cypress run --spec \"cypress/e2e/tests/NoRedact.js\"") RunCypressTests(t, "npx cypress run --spec \"cypress/e2e/tests/NoRedact.js\"")
} }
func TestTapRegexMasking(t *testing.T) {
if testing.Short() {
t.Skip("ignored acceptance test")
}
cliPath, cliPathErr := GetCliPath()
if cliPathErr != nil {
t.Errorf("failed to get cli path, err: %v", cliPathErr)
return
}
tapCmdArgs := GetDefaultTapCommandArgs()
tapNamespace := GetDefaultTapNamespace()
tapCmdArgs = append(tapCmdArgs, tapNamespace...)
tapCmdArgs = append(tapCmdArgs, "--redact")
tapCmdArgs = append(tapCmdArgs, "-r", "Mizu")
tapCmd := exec.Command(cliPath, tapCmdArgs...)
t.Logf("running command: %v", tapCmd.String())
t.Cleanup(func() {
if err := CleanupCommand(tapCmd); err != nil {
t.Logf("failed to cleanup tap command, err: %v", err)
}
})
if err := tapCmd.Start(); err != nil {
t.Errorf("failed to start tap command, err: %v", err)
return
}
apiServerUrl := GetApiServerUrl(DefaultApiServerPort)
if err := WaitTapPodsReady(apiServerUrl); err != nil {
t.Errorf("failed to start tap pods on time, err: %v", err)
return
}
proxyUrl := GetProxyUrl(DefaultNamespaceName, DefaultServiceName)
for i := 0; i < DefaultEntriesCount; i++ {
response, requestErr := http.Post(fmt.Sprintf("%v/post", proxyUrl), "text/plain", bytes.NewBufferString("Mizu"))
if _, requestErr = ExecuteHttpRequest(response, requestErr); requestErr != nil {
t.Errorf("failed to send proxy request, err: %v", requestErr)
return
}
}
RunCypressTests(t, "npx cypress run --spec \"cypress/e2e/tests/RegexMasking.js\"")
}
func TestTapIgnoredUserAgents(t *testing.T) { func TestTapIgnoredUserAgents(t *testing.T) {
if testing.Short() { if testing.Short() {
t.Skip("ignored acceptance test") t.Skip("ignored acceptance test")

View File

@@ -6,10 +6,6 @@ import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil" "io/ioutil"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
"net/http" "net/http"
"os" "os"
"os/exec" "os/exec"
@@ -20,6 +16,11 @@ import (
"testing" "testing"
"time" "time"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/clientcmd"
"k8s.io/client-go/util/homedir"
"github.com/up9inc/mizu/shared" "github.com/up9inc/mizu/shared"
) )
@@ -175,7 +176,7 @@ func ApplyKubeFilesForTest(t *testing.T, kubeContext string, namespace string, f
return nil return nil
} }
func ApplyKubeFile(kubeContext string, namespace string, filename string) (error) { func ApplyKubeFile(kubeContext string, namespace string, filename string) error {
cmdArgs := []string{ cmdArgs := []string{
"apply", "apply",
"--context", kubeContext, "--context", kubeContext,
@@ -214,12 +215,11 @@ func DeleteKubeFile(kubeContext string, namespace string, filename string) error
func getDefaultCommandArgs() []string { func getDefaultCommandArgs() []string {
agentImageValue := os.Getenv("MIZU_CI_IMAGE") agentImageValue := os.Getenv("MIZU_CI_IMAGE")
setFlag := "--set" setFlag := "--set"
telemetry := "telemetry=false"
agentImage := fmt.Sprintf("agent-image=%s", agentImageValue) agentImage := fmt.Sprintf("agent-image=%s", agentImageValue)
imagePullPolicy := "image-pull-policy=IfNotPresent" imagePullPolicy := "image-pull-policy=IfNotPresent"
headless := "headless=true" headless := "headless=true"
return []string{setFlag, telemetry, setFlag, agentImage, setFlag, imagePullPolicy, setFlag, headless} return []string{setFlag, agentImage, setFlag, imagePullPolicy, setFlag, headless}
} }
func GetDefaultTapCommandArgs() []string { func GetDefaultTapCommandArgs() []string {

View File

@@ -6,7 +6,6 @@ require (
github.com/antelman107/net-wait-go v0.0.0-20210623112055-cf684aebda7b github.com/antelman107/net-wait-go v0.0.0-20210623112055-cf684aebda7b
github.com/chanced/openapi v0.0.8 github.com/chanced/openapi v0.0.8
github.com/djherbis/atime v1.1.0 github.com/djherbis/atime v1.1.0
github.com/getkin/kin-openapi v0.89.0
github.com/gin-contrib/pprof v1.3.0 github.com/gin-contrib/pprof v1.3.0
github.com/gin-contrib/static v0.0.1 github.com/gin-contrib/static v0.0.1
github.com/gin-gonic/gin v1.7.7 github.com/gin-gonic/gin v1.7.7
@@ -31,7 +30,6 @@ require (
github.com/up9inc/mizu/tap/extensions/kafka v0.0.0 github.com/up9inc/mizu/tap/extensions/kafka v0.0.0
github.com/up9inc/mizu/tap/extensions/redis v0.0.0 github.com/up9inc/mizu/tap/extensions/redis v0.0.0
github.com/wI2L/jsondiff v0.1.1 github.com/wI2L/jsondiff v0.1.1
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0
k8s.io/api v0.23.3 k8s.io/api v0.23.3
k8s.io/apimachinery v0.23.3 k8s.io/apimachinery v0.23.3
k8s.io/client-go v0.23.3 k8s.io/client-go v0.23.3
@@ -50,16 +48,14 @@ require (
github.com/Masterminds/semver v1.5.0 // indirect github.com/Masterminds/semver v1.5.0 // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/beevik/etree v1.1.0 // indirect
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect
github.com/chanced/dynamic v0.0.0-20211210164248-f8fadb1d735b // indirect github.com/chanced/dynamic v0.0.0-20211210164248-f8fadb1d735b // indirect
github.com/cilium/ebpf v0.8.1 // indirect github.com/cilium/ebpf v0.9.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/evanphx/json-patch v5.6.0+incompatible // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
github.com/fatih/camelcase v1.0.0 // indirect github.com/fatih/camelcase v1.0.0 // indirect
github.com/fvbommel/sortorder v1.0.2 // indirect github.com/fvbommel/sortorder v1.0.2 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-errors/errors v1.4.2 // indirect github.com/go-errors/errors v1.4.2 // indirect
github.com/go-logr/logr v1.2.2 // indirect github.com/go-logr/logr v1.2.2 // indirect
@@ -85,13 +81,14 @@ require (
github.com/josharian/intern v1.0.0 // indirect github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/compress v1.14.2 // indirect github.com/klauspost/compress v1.14.2 // indirect
github.com/knightsc/gapstone v0.0.0-20211014144438-5e0e64002a6e // indirect github.com/knightsc/gapstone v0.0.0-20191231144527-6fa5afaf11a9 // indirect
github.com/leodido/go-urn v1.2.1 // indirect github.com/leodido/go-urn v1.2.1 // indirect
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
github.com/mailru/easyjson v0.7.7 // indirect github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mertyildiran/gqlparser/v2 v2.4.6 // indirect github.com/mertyildiran/gqlparser/v2 v2.4.6 // indirect
github.com/mitchellh/go-wordwrap v1.0.1 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect
github.com/moby/moby v20.10.17+incompatible // indirect
github.com/moby/spdystream v0.2.0 // indirect github.com/moby/spdystream v0.2.0 // indirect
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
@@ -107,6 +104,7 @@ require (
github.com/santhosh-tekuri/jsonschema/v5 v5.0.0 // indirect github.com/santhosh-tekuri/jsonschema/v5 v5.0.0 // indirect
github.com/segmentio/kafka-go v0.4.27 // indirect github.com/segmentio/kafka-go v0.4.27 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible // indirect github.com/shirou/gopsutil v3.21.11+incompatible // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/spf13/cobra v1.3.0 // indirect github.com/spf13/cobra v1.3.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect github.com/spf13/pflag v1.0.5 // indirect
github.com/struCoder/pidusage v0.2.1 // indirect github.com/struCoder/pidusage v0.2.1 // indirect

View File

@@ -101,7 +101,6 @@ github.com/armon/go-metrics v0.3.10/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb
github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/beevik/etree v1.1.0 h1:T0xke/WvNtMoCqgzPhkX2r4rjY3GDZFi+FjpRZY2Jbs=
github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A=
github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM= github.com/benbjohnson/clock v1.0.3/go.mod h1:bGMdMPoPVvcYyt1gHDf4J2KE153Yf9BuiUKYMaxlTDM=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
@@ -128,8 +127,8 @@ github.com/chanced/openapi v0.0.8/go.mod h1:SxE2VMLPw+T7Vq8nwbVVhDF2PigvRF4n5Xyq
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/cilium/ebpf v0.8.1 h1:bLSSEbBLqGPXxls55pGr5qWZaTqcmfDJHhou7t254ao= github.com/cilium/ebpf v0.9.0 h1:ldiV+FscPCQ/p3mNEV4O02EPbUZJFsoEtHvIr9xLTvk=
github.com/cilium/ebpf v0.8.1/go.mod h1:f5zLIM0FSNuAkSyLAN7X+Hy6yznlF1mNiWUMfxMtrgk= github.com/cilium/ebpf v0.9.0/go.mod h1:+OhNOIXx/Fnu1IE8bJz2dzOA+VSfyTfdNUVdlQnxUFY=
github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag=
github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
@@ -211,9 +210,6 @@ github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui72
github.com/fvbommel/sortorder v1.0.2 h1:mV4o8B2hKboCdkJm+a7uX/SIpZob4JzUpc5GGnM45eo= github.com/fvbommel/sortorder v1.0.2 h1:mV4o8B2hKboCdkJm+a7uX/SIpZob4JzUpc5GGnM45eo=
github.com/fvbommel/sortorder v1.0.2/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/fvbommel/sortorder v1.0.2/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
github.com/getkin/kin-openapi v0.89.0 h1:p4nagHchUKGn85z/f+pse4aSh50nIBOYjOhMIku2hiA=
github.com/getkin/kin-openapi v0.89.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/gin-contrib/pprof v1.3.0 h1:G9eK6HnbkSqDZBYbzG4wrjCsA4e+cvYAHUZw6W+W9K0= github.com/gin-contrib/pprof v1.3.0 h1:G9eK6HnbkSqDZBYbzG4wrjCsA4e+cvYAHUZw6W+W9K0=
github.com/gin-contrib/pprof v1.3.0/go.mod h1:waMjT1H9b179t3CxuG1cV3DHpga6ybizwfBaM5OXaB0= github.com/gin-contrib/pprof v1.3.0/go.mod h1:waMjT1H9b179t3CxuG1cV3DHpga6ybizwfBaM5OXaB0=
@@ -373,7 +369,6 @@ github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2c
github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw= github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw=
github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA= github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So= github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
@@ -457,8 +452,8 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
github.com/klauspost/compress v1.9.8/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= github.com/klauspost/compress v1.9.8/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A=
github.com/klauspost/compress v1.14.2 h1:S0OHlFk/Gbon/yauFJ4FfJJF5V0fc5HbBTJazi28pRw= github.com/klauspost/compress v1.14.2 h1:S0OHlFk/Gbon/yauFJ4FfJJF5V0fc5HbBTJazi28pRw=
github.com/klauspost/compress v1.14.2/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.14.2/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/knightsc/gapstone v0.0.0-20211014144438-5e0e64002a6e h1:6J5obSn9umEThiYzWzndcPOZR0Qj/sVCZpH6V1G7yNE= github.com/knightsc/gapstone v0.0.0-20191231144527-6fa5afaf11a9 h1:1KszOoXSFt0aRQ6wxxcKm7QKgfLPI0TWO47UcY/f+vA=
github.com/knightsc/gapstone v0.0.0-20211014144438-5e0e64002a6e/go.mod h1:1K5hEzsMBLTPdRJKEHqBFJ8Zt2VRqDhomcQ11KH0WW4= github.com/knightsc/gapstone v0.0.0-20191231144527-6fa5afaf11a9/go.mod h1:1K5hEzsMBLTPdRJKEHqBFJ8Zt2VRqDhomcQ11KH0WW4=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg=
@@ -521,6 +516,8 @@ github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:F
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/moby/moby v20.10.17+incompatible h1:TJJfyk2fLEgK+RzqVpFNkDkm0oEi+MLUfwt9lEYnp5g=
github.com/moby/moby v20.10.17+incompatible/go.mod h1:fDXVQ6+S340veQPv35CzDahGBmHsiclFwfEygB/TWMc=
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8= github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c= github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A= github.com/moby/term v0.0.0-20210610120745-9d4ed1856297/go.mod h1:vgPCkQMyxTZ7IDy8SXRufE172gr8+K/JE/7hHFxHW3A=
@@ -633,6 +630,8 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
@@ -711,8 +710,6 @@ github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6Ut
github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk= github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk=
github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0= github.com/xlab/treeprint v1.1.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0 h1:6fRhSjgLCkTD3JnJxvaJ4Sj+TYblw757bqYgZaOq5ZY=
github.com/yalp/jsonpath v0.0.0-20180802001716-5cc68e5049a0/go.mod h1:/LWChgwKmvncFJFHJ7Gvn9wZArjbV5/FppcK2fKk/tI=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
@@ -1255,8 +1252,9 @@ gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk= gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
gotest.tools/v3 v3.0.3 h1:4AuOwCGf4lLR9u3YOe2awrHygurzhO/HeQ6laiA6Sx0=
gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8= gotest.tools/v3 v3.0.3/go.mod h1:Z7Lb0S5l+klDB31fvDQX8ss/FlKDxtlFlw3Oa8Ymbl8=
gotest.tools/v3 v3.3.0 h1:MfDY1b1/0xN1CyMlQDac0ziEy9zJQd9CXBRRDHw2jJo=
gotest.tools/v3 v3.3.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=

View File

@@ -131,6 +131,7 @@ func hostApi(socketHarOutputChannel chan<- *tapApi.OutputChannelItem) *gin.Engin
routes.MetadataRoutes(ginApp) routes.MetadataRoutes(ginApp)
routes.StatusRoutes(ginApp) routes.StatusRoutes(ginApp)
routes.DbRoutes(ginApp) routes.DbRoutes(ginApp)
routes.ReplayRoutes(ginApp)
return ginApp return ginApp
} }
@@ -155,7 +156,7 @@ func runInTapperMode() {
hostMode := os.Getenv(shared.HostModeEnvVar) == "1" hostMode := os.Getenv(shared.HostModeEnvVar) == "1"
tapOpts := &tap.TapOpts{ tapOpts := &tap.TapOpts{
HostMode: hostMode, HostMode: hostMode,
} }
filteredOutputItemsChannel := make(chan *tapApi.OutputChannelItem) filteredOutputItemsChannel := make(chan *tapApi.OutputChannelItem)

View File

@@ -1,107 +0,0 @@
package api
import (
"bytes"
"context"
"fmt"
"io/ioutil"
"net/http"
"github.com/getkin/kin-openapi/openapi3"
"github.com/getkin/kin-openapi/openapi3filter"
"github.com/getkin/kin-openapi/routers"
legacyrouter "github.com/getkin/kin-openapi/routers/legacy"
"github.com/up9inc/mizu/shared"
"github.com/up9inc/mizu/tap/api"
)
const (
ContractNotApplicable api.ContractStatus = 0
ContractPassed api.ContractStatus = 1
ContractFailed api.ContractStatus = 2
)
func loadOAS(ctx context.Context) (doc *openapi3.T, contractContent string, router routers.Router, err error) {
path := fmt.Sprintf("%s%s", shared.ConfigDirPath, shared.ContractFileName)
bytes, err := ioutil.ReadFile(path)
if err != nil {
return
}
contractContent = string(bytes)
loader := &openapi3.Loader{Context: ctx}
doc, _ = loader.LoadFromData(bytes)
err = doc.Validate(ctx)
if err != nil {
return
}
router, _ = legacyrouter.NewRouter(doc)
return
}
func validateOAS(ctx context.Context, doc *openapi3.T, router routers.Router, req *http.Request, res *http.Response) (isValid bool, reqErr error, resErr error) {
isValid = true
reqErr = nil
resErr = nil
// Find route
route, pathParams, err := router.FindRoute(req)
if err != nil {
return
}
// Validate request
requestValidationInput := &openapi3filter.RequestValidationInput{
Request: req,
PathParams: pathParams,
Route: route,
}
if reqErr = openapi3filter.ValidateRequest(ctx, requestValidationInput); reqErr != nil {
isValid = false
}
responseValidationInput := &openapi3filter.ResponseValidationInput{
RequestValidationInput: requestValidationInput,
Status: res.StatusCode,
Header: res.Header,
}
if res.Body != nil {
body, _ := ioutil.ReadAll(res.Body)
res.Body = ioutil.NopCloser(bytes.NewBuffer(body))
responseValidationInput.SetBodyBytes(body)
}
// Validate response.
if resErr = openapi3filter.ValidateResponse(ctx, responseValidationInput); resErr != nil {
isValid = false
}
return
}
func handleOAS(ctx context.Context, doc *openapi3.T, router routers.Router, req *http.Request, res *http.Response, contractContent string) (contract api.Contract) {
contract = api.Contract{
Content: contractContent,
Status: ContractNotApplicable,
}
isValid, reqErr, resErr := validateOAS(ctx, doc, router, req, res)
if isValid {
contract.Status = ContractPassed
} else {
contract.Status = ContractFailed
if reqErr != nil {
contract.RequestReason = reqErr.Error()
} else {
contract.RequestReason = ""
}
if resErr != nil {
contract.ResponseReason = resErr.Error()
} else {
contract.ResponseReason = ""
}
}
return
}

View File

@@ -22,7 +22,16 @@ func (e *DefaultEntryStreamerSocketConnector) SendEntry(socketId int, entry *tap
if params.EnableFullEntries { if params.EnableFullEntries {
message, _ = models.CreateFullEntryWebSocketMessage(entry) message, _ = models.CreateFullEntryWebSocketMessage(entry)
} else { } else {
extension := extensionsMap[entry.Protocol.Name] protocol, ok := protocolsMap[entry.Protocol.ToString()]
if !ok {
return fmt.Errorf("protocol not found, protocol: %v", protocol)
}
extension, ok := extensionsMap[protocol.Name]
if !ok {
return fmt.Errorf("extension not found, extension: %v", protocol.Name)
}
base := extension.Dissector.Summarize(entry) base := extension.Dissector.Summarize(entry)
message, _ = models.CreateBaseEntryWebSocketMessage(base) message, _ = models.CreateBaseEntryWebSocketMessage(base)
} }

View File

@@ -12,7 +12,6 @@ import (
"time" "time"
"github.com/up9inc/mizu/agent/pkg/dependency" "github.com/up9inc/mizu/agent/pkg/dependency"
"github.com/up9inc/mizu/agent/pkg/models"
"github.com/up9inc/mizu/agent/pkg/oas" "github.com/up9inc/mizu/agent/pkg/oas"
"github.com/up9inc/mizu/agent/pkg/servicemap" "github.com/up9inc/mizu/agent/pkg/servicemap"
@@ -99,43 +98,15 @@ func startReadingChannel(outputItems <-chan *tapApi.OutputChannelItem, extension
panic("Channel of captured messages is nil") panic("Channel of captured messages is nil")
} }
disableOASValidation := false
ctx := context.Background()
doc, contractContent, router, err := loadOAS(ctx)
if err != nil {
logger.Log.Infof("Disabled OAS validation: %s", err.Error())
disableOASValidation = true
}
for item := range outputItems { for item := range outputItems {
extension := extensionsMap[item.Protocol.Name] extension := extensionsMap[item.Protocol.Name]
resolvedSource, resolvedDestionation, namespace := resolveIP(item.ConnectionInfo) resolvedSource, resolvedDestination, namespace := resolveIP(item.ConnectionInfo)
if namespace == "" && item.Namespace != tapApi.UNKNOWN_NAMESPACE { if namespace == "" && item.Namespace != tapApi.UnknownNamespace {
namespace = item.Namespace namespace = item.Namespace
} }
mizuEntry := extension.Dissector.Analyze(item, resolvedSource, resolvedDestionation, namespace) mizuEntry := extension.Dissector.Analyze(item, resolvedSource, resolvedDestination, namespace)
if extension.Protocol.Name == "http" {
if !disableOASValidation {
var httpPair tapApi.HTTPRequestResponsePair
if err := json.Unmarshal([]byte(mizuEntry.HTTPPair), &httpPair); err != nil {
logger.Log.Error(err)
} else {
contract := handleOAS(ctx, doc, router, httpPair.Request.Payload.RawRequest, httpPair.Response.Payload.RawResponse, contractContent)
mizuEntry.ContractStatus = contract.Status
mizuEntry.ContractRequestReason = contract.RequestReason
mizuEntry.ContractResponseReason = contract.ResponseReason
mizuEntry.ContractContent = contract.Content
}
}
harEntry, err := har.NewEntry(mizuEntry.Request, mizuEntry.Response, mizuEntry.StartTime, mizuEntry.ElapsedTime)
if err == nil {
rules, _, _ := models.RunValidationRulesState(*harEntry, mizuEntry.Destination.Name)
mizuEntry.Rules = rules
}
}
data, err := json.Marshal(mizuEntry) data, err := json.Marshal(mizuEntry)
if err != nil { if err != nil {

View File

@@ -14,10 +14,14 @@ import (
tapApi "github.com/up9inc/mizu/tap/api" tapApi "github.com/up9inc/mizu/tap/api"
) )
var extensionsMap map[string]*tapApi.Extension // global var (
extensionsMap map[string]*tapApi.Extension // global
protocolsMap map[string]*tapApi.Protocol //global
)
func InitExtensionsMap(ref map[string]*tapApi.Extension) { func InitMaps(extensions map[string]*tapApi.Extension, protocols map[string]*tapApi.Protocol) {
extensionsMap = ref extensionsMap = extensions
protocolsMap = protocols
} }
type EventHandlers interface { type EventHandlers interface {
@@ -93,7 +97,9 @@ func websocketHandler(c *gin.Context, eventHandlers EventHandlers, isTapper bool
websocketIdsLock.Unlock() websocketIdsLock.Unlock()
defer func() { defer func() {
socketCleanup(socketId, connectedWebsockets[socketId]) if socketConnection := connectedWebsockets[socketId]; socketConnection != nil {
socketCleanup(socketId, socketConnection)
}
}() }()
eventHandlers.WebSocketConnect(c, socketId, isTapper) eventHandlers.WebSocketConnect(c, socketId, isTapper)

View File

@@ -9,10 +9,11 @@ import (
"github.com/op/go-logging" "github.com/op/go-logging"
basenine "github.com/up9inc/basenine/client/go" basenine "github.com/up9inc/basenine/client/go"
"github.com/up9inc/mizu/agent/pkg/api" "github.com/up9inc/mizu/agent/pkg/api"
"github.com/up9inc/mizu/agent/pkg/providers"
"github.com/up9inc/mizu/agent/pkg/utils" "github.com/up9inc/mizu/agent/pkg/utils"
"github.com/up9inc/mizu/logger" "github.com/up9inc/mizu/logger"
"github.com/up9inc/mizu/tap/dbgctl"
tapApi "github.com/up9inc/mizu/tap/api" tapApi "github.com/up9inc/mizu/tap/api"
"github.com/up9inc/mizu/tap/dbgctl"
amqpExt "github.com/up9inc/mizu/tap/extensions/amqp" amqpExt "github.com/up9inc/mizu/tap/extensions/amqp"
httpExt "github.com/up9inc/mizu/tap/extensions/http" httpExt "github.com/up9inc/mizu/tap/extensions/http"
kafkaExt "github.com/up9inc/mizu/tap/extensions/kafka" kafkaExt "github.com/up9inc/mizu/tap/extensions/kafka"
@@ -22,11 +23,13 @@ import (
var ( var (
Extensions []*tapApi.Extension // global Extensions []*tapApi.Extension // global
ExtensionsMap map[string]*tapApi.Extension // global ExtensionsMap map[string]*tapApi.Extension // global
ProtocolsMap map[string]*tapApi.Protocol //global
) )
func LoadExtensions() { func LoadExtensions() {
Extensions = make([]*tapApi.Extension, 0) Extensions = make([]*tapApi.Extension, 0)
ExtensionsMap = make(map[string]*tapApi.Extension) ExtensionsMap = make(map[string]*tapApi.Extension)
ProtocolsMap = make(map[string]*tapApi.Protocol)
extensionHttp := &tapApi.Extension{} extensionHttp := &tapApi.Extension{}
dissectorHttp := httpExt.NewDissector() dissectorHttp := httpExt.NewDissector()
@@ -34,6 +37,10 @@ func LoadExtensions() {
extensionHttp.Dissector = dissectorHttp extensionHttp.Dissector = dissectorHttp
Extensions = append(Extensions, extensionHttp) Extensions = append(Extensions, extensionHttp)
ExtensionsMap[extensionHttp.Protocol.Name] = extensionHttp ExtensionsMap[extensionHttp.Protocol.Name] = extensionHttp
protocolsHttp := dissectorHttp.GetProtocols()
for k, v := range protocolsHttp {
ProtocolsMap[k] = v
}
if !dbgctl.MizuTapperDisableNonHttpExtensions { if !dbgctl.MizuTapperDisableNonHttpExtensions {
extensionAmqp := &tapApi.Extension{} extensionAmqp := &tapApi.Extension{}
@@ -42,6 +49,10 @@ func LoadExtensions() {
extensionAmqp.Dissector = dissectorAmqp extensionAmqp.Dissector = dissectorAmqp
Extensions = append(Extensions, extensionAmqp) Extensions = append(Extensions, extensionAmqp)
ExtensionsMap[extensionAmqp.Protocol.Name] = extensionAmqp ExtensionsMap[extensionAmqp.Protocol.Name] = extensionAmqp
protocolsAmqp := dissectorAmqp.GetProtocols()
for k, v := range protocolsAmqp {
ProtocolsMap[k] = v
}
extensionKafka := &tapApi.Extension{} extensionKafka := &tapApi.Extension{}
dissectorKafka := kafkaExt.NewDissector() dissectorKafka := kafkaExt.NewDissector()
@@ -49,6 +60,10 @@ func LoadExtensions() {
extensionKafka.Dissector = dissectorKafka extensionKafka.Dissector = dissectorKafka
Extensions = append(Extensions, extensionKafka) Extensions = append(Extensions, extensionKafka)
ExtensionsMap[extensionKafka.Protocol.Name] = extensionKafka ExtensionsMap[extensionKafka.Protocol.Name] = extensionKafka
protocolsKafka := dissectorKafka.GetProtocols()
for k, v := range protocolsKafka {
ProtocolsMap[k] = v
}
extensionRedis := &tapApi.Extension{} extensionRedis := &tapApi.Extension{}
dissectorRedis := redisExt.NewDissector() dissectorRedis := redisExt.NewDissector()
@@ -56,13 +71,18 @@ func LoadExtensions() {
extensionRedis.Dissector = dissectorRedis extensionRedis.Dissector = dissectorRedis
Extensions = append(Extensions, extensionRedis) Extensions = append(Extensions, extensionRedis)
ExtensionsMap[extensionRedis.Protocol.Name] = extensionRedis ExtensionsMap[extensionRedis.Protocol.Name] = extensionRedis
protocolsRedis := dissectorRedis.GetProtocols()
for k, v := range protocolsRedis {
ProtocolsMap[k] = v
}
} }
sort.Slice(Extensions, func(i, j int) bool { sort.Slice(Extensions, func(i, j int) bool {
return Extensions[i].Protocol.Priority < Extensions[j].Protocol.Priority return Extensions[i].Protocol.Priority < Extensions[j].Protocol.Priority
}) })
api.InitExtensionsMap(ExtensionsMap) api.InitMaps(ExtensionsMap, ProtocolsMap)
providers.InitProtocolToColor(ProtocolsMap)
} }
func ConfigureBasenineServer(host string, port string, dbSize int64, logLevel logging.Level, insertionFilter string) { func ConfigureBasenineServer(host string, port string, dbSize int64, logLevel logging.Level, insertionFilter string) {

View File

@@ -44,10 +44,10 @@ func GetEntries(c *gin.Context) {
} }
entriesProvider := dependency.GetInstance(dependency.EntriesProvider).(entries.EntriesProvider) entriesProvider := dependency.GetInstance(dependency.EntriesProvider).(entries.EntriesProvider)
entries, metadata, err := entriesProvider.GetEntries(entriesRequest) entryWrappers, metadata, err := entriesProvider.GetEntries(entriesRequest)
if !HandleEntriesError(c, err) { if !HandleEntriesError(c, err) {
baseEntries := make([]interface{}, 0) baseEntries := make([]interface{}, 0)
for _, entry := range entries { for _, entry := range entryWrappers {
baseEntries = append(baseEntries, entry.Base) baseEntries = append(baseEntries, entry.Base)
} }
c.JSON(http.StatusOK, models.EntriesResponse{ c.JSON(http.StatusOK, models.EntriesResponse{

View File

@@ -0,0 +1,34 @@
package controllers
import (
"net/http"
"time"
"github.com/gin-gonic/gin"
"github.com/up9inc/mizu/agent/pkg/replay"
"github.com/up9inc/mizu/agent/pkg/validation"
"github.com/up9inc/mizu/logger"
)
const (
replayTimeout = 10 * time.Second
)
func ReplayRequest(c *gin.Context) {
logger.Log.Debug("Starting replay")
replayDetails := &replay.Details{}
if err := c.Bind(replayDetails); err != nil {
c.JSON(http.StatusBadRequest, err)
return
}
logger.Log.Debugf("Validating replay, %v", replayDetails)
if err := validation.Validate(replayDetails); err != nil {
c.JSON(http.StatusBadRequest, err)
return
}
logger.Log.Debug("Executing replay, %v", replayDetails)
result := replay.ExecuteRequest(replayDetails, replayTimeout)
c.JSON(http.StatusOK, result)
}

View File

@@ -36,11 +36,13 @@ var (
) )
var ProtocolHttp = &tapApi.Protocol{ var ProtocolHttp = &tapApi.Protocol{
Name: "http", ProtocolSummary: tapApi.ProtocolSummary{
Name: "http",
Version: "1.1",
Abbreviation: "HTTP",
},
LongName: "Hypertext Transfer Protocol -- HTTP/1.1", LongName: "Hypertext Transfer Protocol -- HTTP/1.1",
Abbreviation: "HTTP",
Macro: "http", Macro: "http",
Version: "1.1",
BackgroundColor: "#205cf5", BackgroundColor: "#205cf5",
ForegroundColor: "#ffffff", ForegroundColor: "#ffffff",
FontSize: 12, FontSize: 12,

View File

@@ -1,7 +1,10 @@
package controllers package controllers
import ( import (
"fmt"
"net/http" "net/http"
"strconv"
"time"
core "k8s.io/api/core/v1" core "k8s.io/api/core/v1"
@@ -79,13 +82,25 @@ func GetGeneralStats(c *gin.Context) {
c.JSON(http.StatusOK, providers.GetGeneralStats()) c.JSON(http.StatusOK, providers.GetGeneralStats())
} }
func GetAccumulativeStats(c *gin.Context) { func GetTrafficStats(c *gin.Context) {
c.JSON(http.StatusOK, providers.GetAccumulativeStats()) startTime, endTime, err := getStartEndTime(c)
if err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
c.JSON(http.StatusOK, providers.GetTrafficStats(startTime, endTime))
} }
func GetAccumulativeStatsTiming(c *gin.Context) { func getStartEndTime(c *gin.Context) (time.Time, time.Time, error) {
// for now hardcoded 10 bars of 5 minutes interval startTimeValue, err := strconv.Atoi(c.Query("startTimeMs"))
c.JSON(http.StatusOK, providers.GetAccumulativeStatsTiming(300, 10)) if err != nil {
return time.UnixMilli(0), time.UnixMilli(0), fmt.Errorf("invalid start time: %v", err)
}
endTimeValue, err := strconv.Atoi(c.Query("endTimeMs"))
if err != nil {
return time.UnixMilli(0), time.UnixMilli(0), fmt.Errorf("invalid end time: %v", err)
}
return time.UnixMilli(int64(startTimeValue)), time.UnixMilli(int64(endTimeValue)), nil
} }
func GetCurrentResolvingInformation(c *gin.Context) { func GetCurrentResolvingInformation(c *gin.Context) {

View File

@@ -1,11 +1,11 @@
package dependency package dependency
var typeIntializerMap = make(map[DependencyContainerType]func() interface{}, 0) var typeInitializerMap = make(map[ContainerType]func() interface{}, 0)
func RegisterGenerator(name DependencyContainerType, fn func() interface{}) { func RegisterGenerator(name ContainerType, fn func() interface{}) {
typeIntializerMap[name] = fn typeInitializerMap[name] = fn
} }
func GetInstance(name DependencyContainerType) interface{} { func GetInstance(name ContainerType) interface{} {
return typeIntializerMap[name]() return typeInitializerMap[name]()
} }

View File

@@ -1,12 +1,12 @@
package dependency package dependency
type DependencyContainerType string type ContainerType string
const ( const (
ServiceMapGeneratorDependency = "ServiceMapGeneratorDependency" ServiceMapGeneratorDependency ContainerType = "ServiceMapGeneratorDependency"
OasGeneratorDependency = "OasGeneratorDependency" OasGeneratorDependency ContainerType = "OasGeneratorDependency"
EntriesInserter = "EntriesInserter" EntriesInserter ContainerType = "EntriesInserter"
EntriesProvider = "EntriesProvider" EntriesProvider ContainerType = "EntriesProvider"
EntriesSocketStreamer = "EntriesSocketStreamer" EntriesSocketStreamer ContainerType = "EntriesSocketStreamer"
EntryStreamerSocketConnector = "EntryStreamerSocketConnector" EntryStreamerSocketConnector ContainerType = "EntryStreamerSocketConnector"
) )

View File

@@ -3,11 +3,11 @@ package entries
import ( import (
"encoding/json" "encoding/json"
"errors" "errors"
"fmt"
"time" "time"
basenine "github.com/up9inc/basenine/client/go" basenine "github.com/up9inc/basenine/client/go"
"github.com/up9inc/mizu/agent/pkg/app" "github.com/up9inc/mizu/agent/pkg/app"
"github.com/up9inc/mizu/agent/pkg/har"
"github.com/up9inc/mizu/agent/pkg/models" "github.com/up9inc/mizu/agent/pkg/models"
"github.com/up9inc/mizu/logger" "github.com/up9inc/mizu/logger"
"github.com/up9inc/mizu/shared" "github.com/up9inc/mizu/shared"
@@ -38,11 +38,20 @@ func (e *BasenineEntriesProvider) GetEntries(entriesRequest *models.EntriesReque
return nil, nil, err return nil, nil, err
} }
extension := app.ExtensionsMap[entry.Protocol.Name] protocol, ok := app.ProtocolsMap[entry.Protocol.ToString()]
if !ok {
return nil, nil, fmt.Errorf("protocol not found, protocol: %v", protocol)
}
extension, ok := app.ExtensionsMap[protocol.Name]
if !ok {
return nil, nil, fmt.Errorf("extension not found, extension: %v", protocol.Name)
}
base := extension.Dissector.Summarize(entry) base := extension.Dissector.Summarize(entry)
dataSlice = append(dataSlice, &tapApi.EntryWrapper{ dataSlice = append(dataSlice, &tapApi.EntryWrapper{
Protocol: entry.Protocol, Protocol: *protocol,
Data: entry, Data: entry,
Base: base, Base: base,
}) })
@@ -68,7 +77,16 @@ func (e *BasenineEntriesProvider) GetEntry(singleEntryRequest *models.SingleEntr
return nil, errors.New(string(bytes)) return nil, errors.New(string(bytes))
} }
extension := app.ExtensionsMap[entry.Protocol.Name] protocol, ok := app.ProtocolsMap[entry.Protocol.ToString()]
if !ok {
return nil, fmt.Errorf("protocol not found, protocol: %v", protocol)
}
extension, ok := app.ExtensionsMap[protocol.Name]
if !ok {
return nil, fmt.Errorf("extension not found, extension: %v", protocol.Name)
}
base := extension.Dissector.Summarize(entry) base := extension.Dissector.Summarize(entry)
var representation []byte var representation []byte
representation, err = extension.Dissector.Represent(entry.Request, entry.Response) representation, err = extension.Dissector.Represent(entry.Request, entry.Response)
@@ -76,24 +94,10 @@ func (e *BasenineEntriesProvider) GetEntry(singleEntryRequest *models.SingleEntr
return nil, err return nil, err
} }
var rules []map[string]interface{}
var isRulesEnabled bool
if entry.Protocol.Name == "http" {
harEntry, _ := har.NewEntry(entry.Request, entry.Response, entry.StartTime, entry.ElapsedTime)
_, rulesMatched, _isRulesEnabled := models.RunValidationRulesState(*harEntry, entry.Destination.Name)
isRulesEnabled = _isRulesEnabled
inrec, _ := json.Marshal(rulesMatched)
if err := json.Unmarshal(inrec, &rules); err != nil {
logger.Log.Error(err)
}
}
return &tapApi.EntryWrapper{ return &tapApi.EntryWrapper{
Protocol: entry.Protocol, Protocol: *protocol,
Representation: string(representation), Representation: string(representation),
Data: entry, Data: entry,
Base: base, Base: base,
Rules: rules,
IsRulesEnabled: isRulesEnabled,
}, nil }, nil
} }

View File

@@ -11,75 +11,30 @@ import (
"github.com/up9inc/mizu/logger" "github.com/up9inc/mizu/logger"
) )
// Keep it because we might want cookies in the future func BuildHeaders(rawHeaders map[string]interface{}) ([]Header, string, string, string, string, string) {
//func BuildCookies(rawCookies []interface{}) []har.Cookie {
// cookies := make([]har.Cookie, 0, len(rawCookies))
//
// for _, cookie := range rawCookies {
// c := cookie.(map[string]interface{})
// expiresStr := ""
// if c["expires"] != nil {
// expiresStr = c["expires"].(string)
// }
// expires, _ := time.Parse(time.RFC3339, expiresStr)
// httpOnly := false
// if c["httponly"] != nil {
// httpOnly, _ = strconv.ParseBool(c["httponly"].(string))
// }
// secure := false
// if c["secure"] != nil {
// secure, _ = strconv.ParseBool(c["secure"].(string))
// }
// path := ""
// if c["path"] != nil {
// path = c["path"].(string)
// }
// domain := ""
// if c["domain"] != nil {
// domain = c["domain"].(string)
// }
//
// cookies = append(cookies, har.Cookie{
// Name: c["name"].(string),
// Value: c["value"].(string),
// Path: path,
// Domain: domain,
// HTTPOnly: httpOnly,
// Secure: secure,
// Expires: expires,
// Expires8601: expiresStr,
// })
// }
//
// return cookies
//}
func BuildHeaders(rawHeaders []interface{}) ([]Header, string, string, string, string, string) {
var host, scheme, authority, path, status string var host, scheme, authority, path, status string
headers := make([]Header, 0, len(rawHeaders)) headers := make([]Header, 0, len(rawHeaders))
for _, header := range rawHeaders { for key, value := range rawHeaders {
h := header.(map[string]interface{})
headers = append(headers, Header{ headers = append(headers, Header{
Name: h["name"].(string), Name: key,
Value: h["value"].(string), Value: value.(string),
}) })
if h["name"] == "Host" { if key == "Host" {
host = h["value"].(string) host = value.(string)
} }
if h["name"] == ":authority" { if key == ":authority" {
authority = h["value"].(string) authority = value.(string)
} }
if h["name"] == ":scheme" { if key == ":scheme" {
scheme = h["value"].(string) scheme = value.(string)
} }
if h["name"] == ":path" { if key == ":path" {
path = h["value"].(string) path = value.(string)
} }
if h["name"] == ":status" { if key == ":status" {
status = h["value"].(string) status = value.(string)
} }
} }
@@ -119,8 +74,8 @@ func BuildPostParams(rawParams []interface{}) []Param {
} }
func NewRequest(request map[string]interface{}) (harRequest *Request, err error) { func NewRequest(request map[string]interface{}) (harRequest *Request, err error) {
headers, host, scheme, authority, path, _ := BuildHeaders(request["_headers"].([]interface{})) headers, host, scheme, authority, path, _ := BuildHeaders(request["headers"].(map[string]interface{}))
cookies := make([]Cookie, 0) // BuildCookies(request["_cookies"].([]interface{})) cookies := make([]Cookie, 0)
postData, _ := request["postData"].(map[string]interface{}) postData, _ := request["postData"].(map[string]interface{})
mimeType := postData["mimeType"] mimeType := postData["mimeType"]
@@ -134,12 +89,20 @@ func NewRequest(request map[string]interface{}) (harRequest *Request, err error)
} }
queryString := make([]QueryString, 0) queryString := make([]QueryString, 0)
for _, _qs := range request["_queryString"].([]interface{}) { for key, value := range request["queryString"].(map[string]interface{}) {
qs := _qs.(map[string]interface{}) if valuesInterface, ok := value.([]interface{}); ok {
queryString = append(queryString, QueryString{ for _, valueInterface := range valuesInterface {
Name: qs["name"].(string), queryString = append(queryString, QueryString{
Value: qs["value"].(string), Name: key,
}) Value: valueInterface.(string),
})
}
} else {
queryString = append(queryString, QueryString{
Name: key,
Value: value.(string),
})
}
} }
url := fmt.Sprintf("http://%s%s", host, request["url"].(string)) url := fmt.Sprintf("http://%s%s", host, request["url"].(string))
@@ -172,8 +135,8 @@ func NewRequest(request map[string]interface{}) (harRequest *Request, err error)
} }
func NewResponse(response map[string]interface{}) (harResponse *Response, err error) { func NewResponse(response map[string]interface{}) (harResponse *Response, err error) {
headers, _, _, _, _, _status := BuildHeaders(response["_headers"].([]interface{})) headers, _, _, _, _, _status := BuildHeaders(response["headers"].(map[string]interface{}))
cookies := make([]Cookie, 0) // BuildCookies(response["_cookies"].([]interface{})) cookies := make([]Cookie, 0)
content, _ := response["content"].(map[string]interface{}) content, _ := response["content"].(map[string]interface{})
mimeType := content["mimeType"] mimeType := content["mimeType"]

View File

@@ -4,7 +4,6 @@ import (
"encoding/json" "encoding/json"
"github.com/up9inc/mizu/agent/pkg/har" "github.com/up9inc/mizu/agent/pkg/har"
"github.com/up9inc/mizu/agent/pkg/rules"
tapApi "github.com/up9inc/mizu/tap/api" tapApi "github.com/up9inc/mizu/tap/api"
basenine "github.com/up9inc/basenine/client/go" basenine "github.com/up9inc/basenine/client/go"
@@ -143,9 +142,3 @@ type ExtendedCreator struct {
*har.Creator *har.Creator
Source *string `json:"_source"` Source *string `json:"_source"`
} }
func RunValidationRulesState(harEntry har.Entry, service string) (tapApi.ApplicableRules, []rules.RulesMatched, bool) {
resultPolicyToSend, isEnabled := rules.MatchRequestPolicy(harEntry, service)
statusPolicyToSend, latency, numberOfRules := rules.PassedValidationRules(resultPolicyToSend)
return tapApi.ApplicableRules{Status: statusPolicyToSend, Latency: latency, NumberOfRules: numberOfRules}, resultPolicyToSend, isEnabled
}

View File

@@ -6,9 +6,8 @@ import (
"sync" "sync"
"github.com/up9inc/mizu/agent/pkg/har" "github.com/up9inc/mizu/agent/pkg/har"
"github.com/up9inc/mizu/tap/api"
"github.com/up9inc/mizu/logger" "github.com/up9inc/mizu/logger"
"github.com/up9inc/mizu/tap/api"
) )
var ( var (

View File

@@ -1,6 +1,9 @@
package providers package providers
import ( import (
"crypto/md5"
"encoding/hex"
"fmt"
"reflect" "reflect"
"sync" "sync"
"time" "time"
@@ -26,7 +29,6 @@ type TimeFrameStatsValue struct {
type ProtocolStats struct { type ProtocolStats struct {
MethodsStats map[string]*SizeAndEntriesCount `json:"methods"` MethodsStats map[string]*SizeAndEntriesCount `json:"methods"`
Color string `json:"color"`
} }
type SizeAndEntriesCount struct { type SizeAndEntriesCount struct {
@@ -36,13 +38,13 @@ type SizeAndEntriesCount struct {
type AccumulativeStatsCounter struct { type AccumulativeStatsCounter struct {
Name string `json:"name"` Name string `json:"name"`
Color string `json:"color"`
EntriesCount int `json:"entriesCount"` EntriesCount int `json:"entriesCount"`
VolumeSizeBytes int `json:"volumeSizeBytes"` VolumeSizeBytes int `json:"volumeSizeBytes"`
} }
type AccumulativeStatsProtocol struct { type AccumulativeStatsProtocol struct {
AccumulativeStatsCounter AccumulativeStatsCounter
Color string `json:"color"`
Methods []*AccumulativeStatsCounter `json:"methods"` Methods []*AccumulativeStatsCounter `json:"methods"`
} }
@@ -51,171 +53,46 @@ type AccumulativeStatsProtocolTime struct {
Time int64 `json:"timestamp"` Time int64 `json:"timestamp"`
} }
type TrafficStatsResponse struct {
Protocols []string `json:"protocols"`
PieStats []*AccumulativeStatsProtocol `json:"pie"`
TimelineStats []*AccumulativeStatsProtocolTime `json:"timeline"`
}
var ( var (
generalStats = GeneralStats{} generalStats = GeneralStats{}
bucketsStats = BucketStats{} bucketsStats = BucketStats{}
bucketStatsLocker = sync.Mutex{} bucketStatsLocker = sync.Mutex{}
protocolToColor = map[string]string{}
) )
const ( const (
InternalBucketThreshold = time.Minute * 1 InternalBucketThreshold = time.Minute * 1
MaxNumberOfBars = 30
) )
func ResetGeneralStats() { func ResetGeneralStats() {
generalStats = GeneralStats{} generalStats = GeneralStats{}
} }
func GetGeneralStats() GeneralStats { func GetGeneralStats() *GeneralStats {
return generalStats return &generalStats
} }
func getBucketStatsCopy() BucketStats { func InitProtocolToColor(protocolMap map[string]*api.Protocol) {
bucketStatsCopy := BucketStats{} for item, value := range protocolMap {
bucketStatsLocker.Lock() protocolToColor[api.GetProtocolSummary(item).Abbreviation] = value.BackgroundColor
if err := copier.Copy(&bucketStatsCopy, bucketsStats); err != nil {
logger.Log.Errorf("Error while copying src stats into temporary copied object")
return nil
} }
bucketStatsLocker.Unlock()
return bucketStatsCopy
} }
func GetAccumulativeStats() []*AccumulativeStatsProtocol { func GetTrafficStats(startTime time.Time, endTime time.Time) *TrafficStatsResponse {
bucketStatsCopy := getBucketStatsCopy() bucketsStatsCopy := getFilteredBucketStatsCopy(startTime, endTime)
if bucketStatsCopy == nil {
return make([]*AccumulativeStatsProtocol, 0) return &TrafficStatsResponse{
Protocols: getAvailableProtocols(bucketsStatsCopy),
PieStats: getAccumulativeStats(bucketsStatsCopy),
TimelineStats: getAccumulativeStatsTiming(bucketsStatsCopy),
} }
protocolToColor := make(map[string]string, 0)
methodsPerProtocolAggregated := make(map[string]map[string]*AccumulativeStatsCounter, 0)
for _, countersOfTimeFrame := range bucketStatsCopy {
for protocolName, value := range countersOfTimeFrame.ProtocolStats {
if _, ok := protocolToColor[protocolName]; !ok {
protocolToColor[protocolName] = value.Color
}
for method, countersValue := range value.MethodsStats {
if _, found := methodsPerProtocolAggregated[protocolName]; !found {
methodsPerProtocolAggregated[protocolName] = map[string]*AccumulativeStatsCounter{}
}
if _, found := methodsPerProtocolAggregated[protocolName][method]; !found {
methodsPerProtocolAggregated[protocolName][method] = &AccumulativeStatsCounter{
Name: method,
EntriesCount: 0,
VolumeSizeBytes: 0,
}
}
methodsPerProtocolAggregated[protocolName][method].EntriesCount += countersValue.EntriesCount
methodsPerProtocolAggregated[protocolName][method].VolumeSizeBytes += countersValue.VolumeInBytes
}
}
}
return ConvertToPieData(methodsPerProtocolAggregated, protocolToColor)
}
func ConvertToPieData(methodsPerProtocolAggregated map[string]map[string]*AccumulativeStatsCounter, protocolToColor map[string]string) []*AccumulativeStatsProtocol {
protocolsData := make([]*AccumulativeStatsProtocol, 0)
for protocolName, value := range methodsPerProtocolAggregated {
entriesCount := 0
volumeSizeBytes := 0
methods := make([]*AccumulativeStatsCounter, 0)
for _, methodAccData := range value {
entriesCount += methodAccData.EntriesCount
volumeSizeBytes += methodAccData.VolumeSizeBytes
methods = append(methods, methodAccData)
}
protocolsData = append(protocolsData, &AccumulativeStatsProtocol{
AccumulativeStatsCounter: AccumulativeStatsCounter{
Name: protocolName,
EntriesCount: entriesCount,
VolumeSizeBytes: volumeSizeBytes,
},
Color: protocolToColor[protocolName],
Methods: methods,
})
}
return protocolsData
}
func GetAccumulativeStatsTiming(intervalSeconds int, numberOfBars int) []*AccumulativeStatsProtocolTime {
bucketStatsCopy := getBucketStatsCopy()
if len(bucketStatsCopy) == 0 {
return make([]*AccumulativeStatsProtocolTime, 0)
}
protocolToColor := make(map[string]string, 0)
methodsPerProtocolPerTimeAggregated := make(map[time.Time]map[string]map[string]*AccumulativeStatsCounter, 0)
// TODO: Extract to function and add tests for those values
lastBucketTime := time.Now().UTC().Add(-1 * InternalBucketThreshold / 2).Round(InternalBucketThreshold)
firstBucketTime := lastBucketTime.Add(-1 * time.Second * time.Duration(intervalSeconds*(numberOfBars-1)))
bucketStatsIndex := len(bucketStatsCopy) - 1
for bucketStatsIndex >= 0 {
currentBucketTime := bucketStatsCopy[bucketStatsIndex].BucketTime
if currentBucketTime.After(firstBucketTime) || currentBucketTime.Equal(firstBucketTime) {
resultBucketRoundedKey := currentBucketTime.Add(-1 * time.Second * time.Duration(intervalSeconds) / 2).Round(time.Second * time.Duration(intervalSeconds))
for protocolName, data := range bucketStatsCopy[bucketStatsIndex].ProtocolStats {
if _, ok := protocolToColor[protocolName]; !ok {
protocolToColor[protocolName] = data.Color
}
for methodName, dataOfMethod := range data.MethodsStats {
if _, ok := methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey]; !ok {
methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey] = map[string]map[string]*AccumulativeStatsCounter{}
}
if _, ok := methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey][protocolName]; !ok {
methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey][protocolName] = map[string]*AccumulativeStatsCounter{}
}
if _, ok := methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey][protocolName][methodName]; !ok {
methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey][protocolName][methodName] = &AccumulativeStatsCounter{
Name: methodName,
EntriesCount: 0,
VolumeSizeBytes: 0,
}
}
methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey][protocolName][methodName].EntriesCount += dataOfMethod.EntriesCount
methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey][protocolName][methodName].VolumeSizeBytes += dataOfMethod.VolumeInBytes
}
}
}
bucketStatsIndex--
}
return ConvertToTimelineData(methodsPerProtocolPerTimeAggregated, protocolToColor)
}
func ConvertToTimelineData(methodsPerProtocolPerTimeAggregated map[time.Time]map[string]map[string]*AccumulativeStatsCounter, protocolToColor map[string]string) []*AccumulativeStatsProtocolTime {
finalResult := make([]*AccumulativeStatsProtocolTime, 0)
for timeKey, item := range methodsPerProtocolPerTimeAggregated {
protocolsData := make([]*AccumulativeStatsProtocol, 0)
for protocolName := range item {
entriesCount := 0
volumeSizeBytes := 0
methods := make([]*AccumulativeStatsCounter, 0)
for _, methodAccData := range methodsPerProtocolPerTimeAggregated[timeKey][protocolName] {
entriesCount += methodAccData.EntriesCount
volumeSizeBytes += methodAccData.VolumeSizeBytes
methods = append(methods, methodAccData)
}
protocolsData = append(protocolsData, &AccumulativeStatsProtocol{
AccumulativeStatsCounter: AccumulativeStatsCounter{
Name: protocolName,
EntriesCount: entriesCount,
VolumeSizeBytes: volumeSizeBytes,
},
Color: protocolToColor[protocolName],
Methods: methods,
})
}
finalResult = append(finalResult, &AccumulativeStatsProtocolTime{
Time: timeKey.UnixMilli(),
ProtocolsData: protocolsData,
})
}
return finalResult
} }
func EntryAdded(size int, summery *api.BaseEntry) { func EntryAdded(size int, summery *api.BaseEntry) {
@@ -233,14 +110,67 @@ func EntryAdded(size int, summery *api.BaseEntry) {
generalStats.LastEntryTimestamp = currentTimestamp generalStats.LastEntryTimestamp = currentTimestamp
} }
//GetBucketOfTimeStamp Round the entry to the nearest threshold (one minute) floored (e.g: 15:31:45 -> 15:31:00) func calculateInterval(firstTimestamp int64, lastTimestamp int64) time.Duration {
func GetBucketOfTimeStamp(timestamp int64) time.Time { validDurations := []time.Duration{
entryTimeStampAsTime := time.UnixMilli(timestamp) time.Minute,
return entryTimeStampAsTime.Add(-1 * InternalBucketThreshold / 2).Round(InternalBucketThreshold) time.Minute * 2,
time.Minute * 3,
time.Minute * 5,
time.Minute * 10,
time.Minute * 15,
time.Minute * 20,
time.Minute * 30,
time.Minute * 45,
time.Minute * 60,
time.Minute * 75,
time.Minute * 90, // 1.5 minutes
time.Minute * 120, // 2 hours
time.Minute * 150, // 2.5 hours
time.Minute * 180, // 3 hours
time.Minute * 240, // 4 hours
time.Minute * 300, // 5 hours
time.Minute * 360, // 6 hours
time.Minute * 420, // 7 hours
time.Minute * 480, // 8 hours
time.Minute * 540, // 9 hours
time.Minute * 600, // 10 hours
time.Minute * 660, // 11 hours
time.Minute * 720, // 12 hours
time.Minute * 1440, // 24 hours
}
duration := time.Duration(lastTimestamp-firstTimestamp) * time.Second / time.Duration(MaxNumberOfBars)
for _, validDuration := range validDurations {
if validDuration-duration >= 0 {
return validDuration
}
}
return duration.Round(validDurations[len(validDurations)-1])
}
func getAccumulativeStats(stats BucketStats) []*AccumulativeStatsProtocol {
if len(stats) == 0 {
return make([]*AccumulativeStatsProtocol, 0)
}
methodsPerProtocolAggregated := getAggregatedStats(stats)
return convertAccumulativeStatsDictToArray(methodsPerProtocolAggregated)
}
func getAccumulativeStatsTiming(stats BucketStats) []*AccumulativeStatsProtocolTime {
if len(stats) == 0 {
return make([]*AccumulativeStatsProtocolTime, 0)
}
interval := calculateInterval(stats[0].BucketTime.Unix(), stats[len(stats)-1].BucketTime.Unix()) // in seconds
methodsPerProtocolPerTimeAggregated := getAggregatedResultTiming(stats, interval)
return convertAccumulativeStatsTimelineDictToArray(methodsPerProtocolPerTimeAggregated)
} }
func addToBucketStats(size int, summery *api.BaseEntry) { func addToBucketStats(size int, summery *api.BaseEntry) {
entryTimeBucketRounded := GetBucketOfTimeStamp(summery.Timestamp) entryTimeBucketRounded := getBucketFromTimeStamp(summery.Timestamp)
if len(bucketsStats) == 0 { if len(bucketsStats) == 0 {
bucketsStats = append(bucketsStats, &TimeFrameStatsValue{ bucketsStats = append(bucketsStats, &TimeFrameStatsValue{
@@ -259,7 +189,6 @@ func addToBucketStats(size int, summery *api.BaseEntry) {
if _, found := bucketOfEntry.ProtocolStats[summery.Protocol.Abbreviation]; !found { if _, found := bucketOfEntry.ProtocolStats[summery.Protocol.Abbreviation]; !found {
bucketOfEntry.ProtocolStats[summery.Protocol.Abbreviation] = ProtocolStats{ bucketOfEntry.ProtocolStats[summery.Protocol.Abbreviation] = ProtocolStats{
MethodsStats: map[string]*SizeAndEntriesCount{}, MethodsStats: map[string]*SizeAndEntriesCount{},
Color: summery.Protocol.BackgroundColor,
} }
} }
if _, found := bucketOfEntry.ProtocolStats[summery.Protocol.Abbreviation].MethodsStats[summery.Method]; !found { if _, found := bucketOfEntry.ProtocolStats[summery.Protocol.Abbreviation].MethodsStats[summery.Method]; !found {
@@ -272,3 +201,166 @@ func addToBucketStats(size int, summery *api.BaseEntry) {
bucketOfEntry.ProtocolStats[summery.Protocol.Abbreviation].MethodsStats[summery.Method].EntriesCount += 1 bucketOfEntry.ProtocolStats[summery.Protocol.Abbreviation].MethodsStats[summery.Method].EntriesCount += 1
bucketOfEntry.ProtocolStats[summery.Protocol.Abbreviation].MethodsStats[summery.Method].VolumeInBytes += size bucketOfEntry.ProtocolStats[summery.Protocol.Abbreviation].MethodsStats[summery.Method].VolumeInBytes += size
} }
func getBucketFromTimeStamp(timestamp int64) time.Time {
entryTimeStampAsTime := time.UnixMilli(timestamp)
return entryTimeStampAsTime.Add(-1 * InternalBucketThreshold / 2).Round(InternalBucketThreshold)
}
func convertAccumulativeStatsTimelineDictToArray(methodsPerProtocolPerTimeAggregated map[time.Time]map[string]map[string]*AccumulativeStatsCounter) []*AccumulativeStatsProtocolTime {
finalResult := make([]*AccumulativeStatsProtocolTime, 0)
for timeKey, item := range methodsPerProtocolPerTimeAggregated {
protocolsData := make([]*AccumulativeStatsProtocol, 0)
for protocolName, value := range item {
entriesCount := 0
volumeSizeBytes := 0
methods := make([]*AccumulativeStatsCounter, 0)
for _, methodAccData := range value {
entriesCount += methodAccData.EntriesCount
volumeSizeBytes += methodAccData.VolumeSizeBytes
methods = append(methods, methodAccData)
}
protocolsData = append(protocolsData, &AccumulativeStatsProtocol{
AccumulativeStatsCounter: AccumulativeStatsCounter{
Name: protocolName,
Color: protocolToColor[protocolName],
EntriesCount: entriesCount,
VolumeSizeBytes: volumeSizeBytes,
},
Methods: methods,
})
}
finalResult = append(finalResult, &AccumulativeStatsProtocolTime{
Time: timeKey.UnixMilli(),
ProtocolsData: protocolsData,
})
}
return finalResult
}
func convertAccumulativeStatsDictToArray(methodsPerProtocolAggregated map[string]map[string]*AccumulativeStatsCounter) []*AccumulativeStatsProtocol {
protocolsData := make([]*AccumulativeStatsProtocol, 0)
for protocolName, value := range methodsPerProtocolAggregated {
entriesCount := 0
volumeSizeBytes := 0
methods := make([]*AccumulativeStatsCounter, 0)
for _, methodAccData := range value {
entriesCount += methodAccData.EntriesCount
volumeSizeBytes += methodAccData.VolumeSizeBytes
methods = append(methods, methodAccData)
}
protocolsData = append(protocolsData, &AccumulativeStatsProtocol{
AccumulativeStatsCounter: AccumulativeStatsCounter{
Name: protocolName,
Color: protocolToColor[protocolName],
EntriesCount: entriesCount,
VolumeSizeBytes: volumeSizeBytes,
},
Methods: methods,
})
}
return protocolsData
}
func getFilteredBucketStatsCopy(startTime time.Time, endTime time.Time) BucketStats {
bucketStatsCopy := BucketStats{}
bucketStatsLocker.Lock()
if err := copier.Copy(&bucketStatsCopy, bucketsStats); err != nil {
logger.Log.Errorf("Error while copying src stats into temporary copied object")
return nil
}
bucketStatsLocker.Unlock()
filteredBucketStatsCopy := BucketStats{}
interval := InternalBucketThreshold
for _, bucket := range bucketStatsCopy {
if (bucket.BucketTime.After(startTime.Add(-1*interval/2).Round(interval)) && bucket.BucketTime.Before(endTime.Add(-1*interval/2).Round(interval))) ||
bucket.BucketTime.Equal(startTime.Add(-1*interval/2).Round(interval)) ||
bucket.BucketTime.Equal(endTime.Add(-1*interval/2).Round(interval)) {
filteredBucketStatsCopy = append(filteredBucketStatsCopy, bucket)
}
}
return filteredBucketStatsCopy
}
func getAggregatedResultTiming(stats BucketStats, interval time.Duration) map[time.Time]map[string]map[string]*AccumulativeStatsCounter {
methodsPerProtocolPerTimeAggregated := map[time.Time]map[string]map[string]*AccumulativeStatsCounter{}
bucketStatsIndex := len(stats) - 1
for bucketStatsIndex >= 0 {
currentBucketTime := stats[bucketStatsIndex].BucketTime
resultBucketRoundedKey := currentBucketTime.Add(-1 * interval / 2).Round(interval)
for protocolName, data := range stats[bucketStatsIndex].ProtocolStats {
for methodName, dataOfMethod := range data.MethodsStats {
if _, ok := methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey]; !ok {
methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey] = map[string]map[string]*AccumulativeStatsCounter{}
}
if _, ok := methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey][protocolName]; !ok {
methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey][protocolName] = map[string]*AccumulativeStatsCounter{}
}
if _, ok := methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey][protocolName][methodName]; !ok {
methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey][protocolName][methodName] = &AccumulativeStatsCounter{
Name: methodName,
Color: getColorForMethod(protocolName, methodName),
EntriesCount: 0,
VolumeSizeBytes: 0,
}
}
methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey][protocolName][methodName].EntriesCount += dataOfMethod.EntriesCount
methodsPerProtocolPerTimeAggregated[resultBucketRoundedKey][protocolName][methodName].VolumeSizeBytes += dataOfMethod.VolumeInBytes
}
}
bucketStatsIndex--
}
return methodsPerProtocolPerTimeAggregated
}
func getAggregatedStats(stats BucketStats) map[string]map[string]*AccumulativeStatsCounter {
methodsPerProtocolAggregated := make(map[string]map[string]*AccumulativeStatsCounter, 0)
for _, countersOfTimeFrame := range stats {
for protocolName, value := range countersOfTimeFrame.ProtocolStats {
for method, countersValue := range value.MethodsStats {
if _, found := methodsPerProtocolAggregated[protocolName]; !found {
methodsPerProtocolAggregated[protocolName] = map[string]*AccumulativeStatsCounter{}
}
if _, found := methodsPerProtocolAggregated[protocolName][method]; !found {
methodsPerProtocolAggregated[protocolName][method] = &AccumulativeStatsCounter{
Name: method,
Color: getColorForMethod(protocolName, method),
EntriesCount: 0,
VolumeSizeBytes: 0,
}
}
methodsPerProtocolAggregated[protocolName][method].EntriesCount += countersValue.EntriesCount
methodsPerProtocolAggregated[protocolName][method].VolumeSizeBytes += countersValue.VolumeInBytes
}
}
}
return methodsPerProtocolAggregated
}
func getColorForMethod(protocolName string, methodName string) string {
hash := md5.Sum([]byte(fmt.Sprintf("%v_%v", protocolName, methodName)))
input := hex.EncodeToString(hash[:])
return fmt.Sprintf("#%v", input[:6])
}
func getAvailableProtocols(stats BucketStats) []string {
protocols := map[string]bool{}
for _, countersOfTimeFrame := range stats {
for protocolName := range countersOfTimeFrame.ProtocolStats {
protocols[protocolName] = true
}
}
result := make([]string, 0)
for protocol := range protocols {
result = append(result, protocol)
}
result = append(result, "ALL")
return result
}

View File

@@ -0,0 +1,298 @@
package providers
import (
"fmt"
"testing"
"time"
)
func TestGetBucketOfTimeStamp(t *testing.T) {
tests := map[int64]time.Time{
time.Date(2022, time.Month(1), 1, 10, 34, 45, 0, time.Local).UnixMilli(): time.Date(2022, time.Month(1), 1, 10, 34, 00, 0, time.Local),
time.Date(2022, time.Month(1), 1, 10, 34, 00, 0, time.Local).UnixMilli(): time.Date(2022, time.Month(1), 1, 10, 34, 00, 0, time.Local),
time.Date(2022, time.Month(1), 1, 10, 59, 01, 0, time.Local).UnixMilli(): time.Date(2022, time.Month(1), 1, 10, 59, 00, 0, time.Local),
}
for key, value := range tests {
t.Run(fmt.Sprintf("%v", key), func(t *testing.T) {
actual := getBucketFromTimeStamp(key)
if actual != value {
t.Errorf("unexpected result - expected: %v, actual: %v", value, actual)
}
})
}
}
func TestGetAggregatedStatsAllTime(t *testing.T) {
bucketStatsForTest := BucketStats{
&TimeFrameStatsValue{
BucketTime: time.Date(2022, time.Month(1), 1, 10, 00, 00, 0, time.UTC),
ProtocolStats: map[string]ProtocolStats{
"http": {
MethodsStats: map[string]*SizeAndEntriesCount{
"get": {
EntriesCount: 1,
VolumeInBytes: 2,
},
"post": {
EntriesCount: 2,
VolumeInBytes: 3,
},
},
},
"kafka": {
MethodsStats: map[string]*SizeAndEntriesCount{
"listTopics": {
EntriesCount: 5,
VolumeInBytes: 6,
},
},
},
},
},
&TimeFrameStatsValue{
BucketTime: time.Date(2022, time.Month(1), 1, 10, 01, 00, 0, time.UTC),
ProtocolStats: map[string]ProtocolStats{
"http": {
MethodsStats: map[string]*SizeAndEntriesCount{
"get": {
EntriesCount: 1,
VolumeInBytes: 2,
},
"post": {
EntriesCount: 2,
VolumeInBytes: 3,
},
},
},
"redis": {
MethodsStats: map[string]*SizeAndEntriesCount{
"set": {
EntriesCount: 5,
VolumeInBytes: 6,
},
},
},
},
},
}
expected := map[string]map[string]*AccumulativeStatsCounter{
"http": {
"post": {
Name: "post",
EntriesCount: 4,
VolumeSizeBytes: 6,
},
"get": {
Name: "get",
EntriesCount: 2,
VolumeSizeBytes: 4,
},
},
"kafka": {
"listTopics": {
Name: "listTopics",
EntriesCount: 5,
VolumeSizeBytes: 6,
},
},
"redis": {
"set": {
Name: "set",
EntriesCount: 5,
VolumeSizeBytes: 6,
},
},
}
actual := getAggregatedStats(bucketStatsForTest)
if len(actual) != len(expected) {
t.Errorf("unexpected result - expected: %v, actual: %v", len(expected), len(actual))
}
}
func TestGetAggregatedStatsFromSpecificTime(t *testing.T) {
bucketStatsForTest := BucketStats{
&TimeFrameStatsValue{
BucketTime: time.Date(2022, time.Month(1), 1, 10, 00, 00, 0, time.UTC),
ProtocolStats: map[string]ProtocolStats{
"http": {
MethodsStats: map[string]*SizeAndEntriesCount{
"get": {
EntriesCount: 1,
VolumeInBytes: 2,
},
},
},
"kafka": {
MethodsStats: map[string]*SizeAndEntriesCount{
"listTopics": {
EntriesCount: 5,
VolumeInBytes: 6,
},
},
},
},
},
&TimeFrameStatsValue{
BucketTime: time.Date(2022, time.Month(1), 1, 10, 01, 00, 0, time.UTC),
ProtocolStats: map[string]ProtocolStats{
"http": {
MethodsStats: map[string]*SizeAndEntriesCount{
"get": {
EntriesCount: 1,
VolumeInBytes: 2,
},
"post": {
EntriesCount: 2,
VolumeInBytes: 3,
},
},
},
"redis": {
MethodsStats: map[string]*SizeAndEntriesCount{
"set": {
EntriesCount: 5,
VolumeInBytes: 6,
},
},
},
},
},
}
expected := map[time.Time]map[string]map[string]*AccumulativeStatsCounter{
time.Date(2022, time.Month(1), 1, 10, 00, 00, 0, time.UTC): {
"http": {
"post": {
Name: "post",
EntriesCount: 2,
VolumeSizeBytes: 3,
},
"get": {
Name: "get",
EntriesCount: 2,
VolumeSizeBytes: 4,
},
},
"kafka": {
"listTopics": {
Name: "listTopics",
EntriesCount: 5,
VolumeSizeBytes: 6,
},
},
"redis": {
"set": {
Name: "set",
EntriesCount: 5,
VolumeSizeBytes: 6,
},
},
},
}
actual := getAggregatedResultTiming(bucketStatsForTest, time.Minute*5)
if len(actual) != len(expected) {
t.Errorf("unexpected result - expected: %v, actual: %v", len(expected), len(actual))
}
}
func TestGetAggregatedStatsFromSpecificTimeMultipleBuckets(t *testing.T) {
bucketStatsForTest := BucketStats{
&TimeFrameStatsValue{
BucketTime: time.Date(2022, time.Month(1), 1, 10, 00, 00, 0, time.UTC),
ProtocolStats: map[string]ProtocolStats{
"http": {
MethodsStats: map[string]*SizeAndEntriesCount{
"get": {
EntriesCount: 1,
VolumeInBytes: 2,
},
},
},
"kafka": {
MethodsStats: map[string]*SizeAndEntriesCount{
"listTopics": {
EntriesCount: 5,
VolumeInBytes: 6,
},
},
},
},
},
&TimeFrameStatsValue{
BucketTime: time.Date(2022, time.Month(1), 1, 10, 01, 00, 0, time.UTC),
ProtocolStats: map[string]ProtocolStats{
"http": {
MethodsStats: map[string]*SizeAndEntriesCount{
"get": {
EntriesCount: 1,
VolumeInBytes: 2,
},
"post": {
EntriesCount: 2,
VolumeInBytes: 3,
},
},
},
"redis": {
MethodsStats: map[string]*SizeAndEntriesCount{
"set": {
EntriesCount: 5,
VolumeInBytes: 6,
},
},
},
},
},
}
expected := map[time.Time]map[string]map[string]*AccumulativeStatsCounter{
time.Date(2022, time.Month(1), 1, 10, 00, 00, 0, time.UTC): {
"http": {
"get": {
Name: "get",
EntriesCount: 1,
VolumeSizeBytes: 2,
},
},
"kafka": {
"listTopics": {
Name: "listTopics",
EntriesCount: 5,
VolumeSizeBytes: 6,
},
},
},
time.Date(2022, time.Month(1), 1, 10, 01, 00, 0, time.UTC): {
"http": {
"post": {
Name: "post",
EntriesCount: 2,
VolumeSizeBytes: 3,
},
"get": {
Name: "get",
EntriesCount: 1,
VolumeSizeBytes: 2,
},
},
"redis": {
"set": {
Name: "set",
EntriesCount: 5,
VolumeSizeBytes: 6,
},
},
},
}
actual := getAggregatedResultTiming(bucketStatsForTest, time.Minute)
if len(actual) != len(expected) {
t.Errorf("unexpected result - expected: %v, actual: %v", len(expected), len(actual))
}
}

View File

@@ -26,7 +26,7 @@ func TestEntryAddedCount(t *testing.T) {
entryBucketKey := time.Date(2021, 1, 1, 10, 0, 0, 0, time.UTC) entryBucketKey := time.Date(2021, 1, 1, 10, 0, 0, 0, time.UTC)
valueLessThanBucketThreshold := time.Second * 130 valueLessThanBucketThreshold := time.Second * 130
mockSummery := &api.BaseEntry{Protocol: api.Protocol{Name: "mock"}, Method: "mock-method", Timestamp: entryBucketKey.Add(valueLessThanBucketThreshold).UnixNano()} mockSummery := &api.BaseEntry{Protocol: api.Protocol{ProtocolSummary: api.ProtocolSummary{Name: "mock"}}, Method: "mock-method", Timestamp: entryBucketKey.Add(valueLessThanBucketThreshold).UnixNano()}
for _, entriesCount := range tests { for _, entriesCount := range tests {
t.Run(fmt.Sprintf("%d", entriesCount), func(t *testing.T) { t.Run(fmt.Sprintf("%d", entriesCount), func(t *testing.T) {
for i := 0; i < entriesCount; i++ { for i := 0; i < entriesCount; i++ {
@@ -61,7 +61,7 @@ func TestEntryAddedVolume(t *testing.T) {
var expectedEntriesCount int var expectedEntriesCount int
var expectedVolumeInGB float64 var expectedVolumeInGB float64
mockSummery := &api.BaseEntry{Protocol: api.Protocol{Name: "mock"}, Method: "mock-method", Timestamp: time.Date(2021, 1, 1, 10, 0, 0, 0, time.UTC).UnixNano()} mockSummery := &api.BaseEntry{Protocol: api.Protocol{ProtocolSummary: api.ProtocolSummary{Name: "mock"}}, Method: "mock-method", Timestamp: time.Date(2021, 1, 1, 10, 0, 0, 0, time.UTC).UnixNano()}
for _, data := range tests { for _, data := range tests {
t.Run(fmt.Sprintf("%d", len(data)), func(t *testing.T) { t.Run(fmt.Sprintf("%d", len(data)), func(t *testing.T) {
@@ -81,24 +81,4 @@ func TestEntryAddedVolume(t *testing.T) {
} }
}) })
} }
}
func TestGetBucketOfTimeStamp(t *testing.T) {
tests := map[int64]time.Time{
time.Date(2022, time.Month(1), 1, 10, 34, 45, 0, time.Local).UnixMilli(): time.Date(2022, time.Month(1), 1, 10, 34, 00, 0, time.Local),
time.Date(2022, time.Month(1), 1, 10, 34, 00, 0, time.Local).UnixMilli(): time.Date(2022, time.Month(1), 1, 10, 34, 00, 0, time.Local),
time.Date(2022, time.Month(1), 1, 10, 59, 01, 0, time.Local).UnixMilli(): time.Date(2022, time.Month(1), 1, 10, 59, 00, 0, time.Local),
}
for key, value := range tests {
t.Run(fmt.Sprintf("%v", key), func(t *testing.T) {
actual := providers.GetBucketOfTimeStamp(key)
if actual != value {
t.Errorf("unexpected result - expected: %v, actual: %v", value, actual)
}
})
}
} }

View File

@@ -44,9 +44,10 @@ func Set(tappedPodsToSet []*shared.PodInfo) {
func GetTappedPodsStatus() []shared.TappedPodStatus { func GetTappedPodsStatus() []shared.TappedPodStatus {
tappedPodsStatus := make([]shared.TappedPodStatus, 0) tappedPodsStatus := make([]shared.TappedPodStatus, 0)
tapperStatus := tappers.GetStatus()
for _, pod := range Get() { for _, pod := range Get() {
var status string var status string
if tapperStatus, ok := tappers.GetStatus()[pod.NodeName]; ok { if tapperStatus, ok := tapperStatus[pod.NodeName]; ok {
status = strings.ToLower(tapperStatus.Status) status = strings.ToLower(tapperStatus.Status)
} }
@@ -59,7 +60,7 @@ func GetTappedPodsStatus() []shared.TappedPodStatus {
func SetNodeToTappedPodMap(nodeToTappedPodsMap shared.NodeToPodsMap) { func SetNodeToTappedPodMap(nodeToTappedPodsMap shared.NodeToPodsMap) {
summary := nodeToTappedPodsMap.Summary() summary := nodeToTappedPodsMap.Summary()
logger.Log.Infof("Setting node to tapped pods map to %v", summary) logger.Log.Debugf("Setting node to tapped pods map to %v", summary)
nodeHostToTappedPodsMap = nodeToTappedPodsMap nodeHostToTappedPodsMap = nodeToTappedPodsMap
} }

184
agent/pkg/replay/replay.go Normal file
View File

@@ -0,0 +1,184 @@
package replay
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"strings"
"sync"
"time"
"github.com/google/uuid"
"github.com/up9inc/mizu/agent/pkg/app"
tapApi "github.com/up9inc/mizu/tap/api"
mizuhttp "github.com/up9inc/mizu/tap/extensions/http"
)
var (
inProcessRequestsLocker = sync.Mutex{}
inProcessRequests = 0
)
const maxParallelAction = 5
type Details struct {
Method string `json:"method"`
Url string `json:"url"`
Body string `json:"body"`
Headers map[string]string `json:"headers"`
}
type Response struct {
Success bool `json:"status"`
Data interface{} `json:"data"`
ErrorMessage string `json:"errorMessage"`
}
func incrementCounter() bool {
result := false
inProcessRequestsLocker.Lock()
if inProcessRequests < maxParallelAction {
inProcessRequests++
result = true
}
inProcessRequestsLocker.Unlock()
return result
}
func decrementCounter() {
inProcessRequestsLocker.Lock()
inProcessRequests--
inProcessRequestsLocker.Unlock()
}
func getEntryFromRequestResponse(extension *tapApi.Extension, request *http.Request, response *http.Response) *tapApi.Entry {
captureTime := time.Now()
itemTmp := tapApi.OutputChannelItem{
Protocol: *extension.Protocol,
ConnectionInfo: &tapApi.ConnectionInfo{
ClientIP: "",
ClientPort: "1",
ServerIP: "",
ServerPort: "1",
IsOutgoing: false,
},
Capture: "",
Timestamp: time.Now().UnixMilli(),
Pair: &tapApi.RequestResponsePair{
Request: tapApi.GenericMessage{
IsRequest: true,
CaptureTime: captureTime,
CaptureSize: 0,
Payload: &mizuhttp.HTTPPayload{
Type: mizuhttp.TypeHttpRequest,
Data: request,
},
},
Response: tapApi.GenericMessage{
IsRequest: false,
CaptureTime: captureTime,
CaptureSize: 0,
Payload: &mizuhttp.HTTPPayload{
Type: mizuhttp.TypeHttpResponse,
Data: response,
},
},
},
}
// Analyze is expecting an item that's marshalled and unmarshalled
itemMarshalled, err := json.Marshal(itemTmp)
if err != nil {
return nil
}
var finalItem *tapApi.OutputChannelItem
if err := json.Unmarshal(itemMarshalled, &finalItem); err != nil {
return nil
}
return extension.Dissector.Analyze(finalItem, "", "", "")
}
func ExecuteRequest(replayData *Details, timeout time.Duration) *Response {
if incrementCounter() {
defer decrementCounter()
client := &http.Client{
Timeout: timeout,
}
request, err := http.NewRequest(strings.ToUpper(replayData.Method), replayData.Url, bytes.NewBufferString(replayData.Body))
if err != nil {
return &Response{
Success: false,
Data: nil,
ErrorMessage: err.Error(),
}
}
for headerKey, headerValue := range replayData.Headers {
request.Header.Add(headerKey, headerValue)
}
request.Header.Add("x-mizu", uuid.New().String())
response, requestErr := client.Do(request)
if requestErr != nil {
return &Response{
Success: false,
Data: nil,
ErrorMessage: requestErr.Error(),
}
}
extension := app.ExtensionsMap["http"] // # TODO: maybe pass the extension to the function so it can be tested
entry := getEntryFromRequestResponse(extension, request, response)
base := extension.Dissector.Summarize(entry)
var representation []byte
// Represent is expecting an entry that's marshalled and unmarshalled
entryMarshalled, err := json.Marshal(entry)
if err != nil {
return &Response{
Success: false,
Data: nil,
ErrorMessage: err.Error(),
}
}
var entryUnmarshalled *tapApi.Entry
if err := json.Unmarshal(entryMarshalled, &entryUnmarshalled); err != nil {
return &Response{
Success: false,
Data: nil,
ErrorMessage: err.Error(),
}
}
representation, err = extension.Dissector.Represent(entryUnmarshalled.Request, entryUnmarshalled.Response)
if err != nil {
return &Response{
Success: false,
Data: nil,
ErrorMessage: err.Error(),
}
}
return &Response{
Success: true,
Data: &tapApi.EntryWrapper{
Protocol: *extension.Protocol,
Representation: string(representation),
Data: entryUnmarshalled,
Base: base,
},
ErrorMessage: "",
}
} else {
return &Response{
Success: false,
Data: nil,
ErrorMessage: fmt.Sprintf("reached threshold of %d requests", maxParallelAction),
}
}
}

View File

@@ -0,0 +1,106 @@
package replay
import (
"bytes"
"fmt"
"net/http"
"strings"
"testing"
"time"
"encoding/json"
"github.com/google/uuid"
tapApi "github.com/up9inc/mizu/tap/api"
mizuhttp "github.com/up9inc/mizu/tap/extensions/http"
)
func TestValid(t *testing.T) {
client := &http.Client{
Timeout: 10 * time.Second,
}
tests := map[string]*Details{
"40x": {
Method: "GET",
Url: "http://httpbin.org/status/404",
Body: "",
Headers: map[string]string{},
},
"20x": {
Method: "GET",
Url: "http://httpbin.org/status/200",
Body: "",
Headers: map[string]string{},
},
"50x": {
Method: "GET",
Url: "http://httpbin.org/status/500",
Body: "",
Headers: map[string]string{},
},
// TODO: this should be fixes, currently not working because of header name with ":"
//":path-header": {
// Method: "GET",
// Url: "http://httpbin.org/get",
// Body: "",
// Headers: map[string]string{
// ":path": "/get",
// },
// },
}
for testCaseName, replayData := range tests {
t.Run(fmt.Sprintf("%+v", testCaseName), func(t *testing.T) {
request, err := http.NewRequest(strings.ToUpper(replayData.Method), replayData.Url, bytes.NewBufferString(replayData.Body))
if err != nil {
t.Errorf("Error executing request")
}
for headerKey, headerValue := range replayData.Headers {
request.Header.Add(headerKey, headerValue)
}
request.Header.Add("x-mizu", uuid.New().String())
response, requestErr := client.Do(request)
if requestErr != nil {
t.Errorf("failed: %v, ", requestErr)
}
extensionHttp := &tapApi.Extension{}
dissectorHttp := mizuhttp.NewDissector()
dissectorHttp.Register(extensionHttp)
extensionHttp.Dissector = dissectorHttp
extension := extensionHttp
entry := getEntryFromRequestResponse(extension, request, response)
base := extension.Dissector.Summarize(entry)
// Represent is expecting an entry that's marshalled and unmarshalled
entryMarshalled, err := json.Marshal(entry)
if err != nil {
t.Errorf("failed marshaling entry: %v, ", err)
}
var entryUnmarshalled *tapApi.Entry
if err := json.Unmarshal(entryMarshalled, &entryUnmarshalled); err != nil {
t.Errorf("failed unmarshaling entry: %v, ", err)
}
var representation []byte
representation, err = extension.Dissector.Represent(entryUnmarshalled.Request, entryUnmarshalled.Response)
if err != nil {
t.Errorf("failed: %v, ", err)
}
result := &tapApi.EntryWrapper{
Protocol: *extension.Protocol,
Representation: string(representation),
Data: entry,
Base: base,
}
t.Logf("%+v", result)
//data, _ := json.MarshalIndent(result, "", " ")
//t.Logf("%+v", string(data))
})
}
}

View File

@@ -1,522 +0,0 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0 h1:3ithwDMr7/3vpAMXiH+ZQnYbuIsh+OPhUPMFC9enmn0=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0 h1:xE3CPsOgttP4ACBePh79zTKALtXwn/Edhcr16R5hMWU=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0 h1:/May9ojXjRkPBNVrq+oWLqmWCkr4OU5uRY29bu0mRyQ=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0 h1:Lpy6hKgdcl7a3WGSfJIFmxmcdjSpP6OmBEfcOv1Y680=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0 h1:UDpwYIwla4jHGzZJaEJYx1tOejbgSoNqsAfHAUYe2r8=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9 h1:VpgP7xuJadIUuKccphEpTJnWhS2jkQyMt6Y7pJCD7fY=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest v0.11.12 h1:gI8ytXbxMfI+IVbI9mP2JGCTXIuhHLgRlvQ9X4PsnHE=
github.com/Azure/go-autorest/autorest v0.11.12/go.mod h1:eipySxLmqSyC5s5k1CLupqet0PSENBEDP93LQ9a8QYw=
github.com/Azure/go-autorest/autorest/adal v0.9.5 h1:Y3bBUV4rTuxenJJs41HU3qmqsb+auo+a3Lz+PlJPpL0=
github.com/Azure/go-autorest/autorest/adal v0.9.5/go.mod h1:B7KF7jKIeC9Mct5spmyCB/A8CG/sEz1vwIRGv/bbw7A=
github.com/Azure/go-autorest/autorest/date v0.3.0 h1:7gUk1U5M/CQbp9WoqinNzJar+8KY+LPI6wiWrP/myHw=
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
github.com/Azure/go-autorest/autorest/mocks v0.4.1 h1:K0laFcLE6VLTOwNgSxaGbUcLPuGXlNkbVvq4cW4nIHk=
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
github.com/Azure/go-autorest/logger v0.2.0 h1:e4RVHVZKC5p6UANLJHkM4OfR1UKZPj8Wt8Pcx+3oqrE=
github.com/Azure/go-autorest/logger v0.2.0/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
github.com/Azure/go-autorest/tracing v0.6.0 h1:TYi4+3m5t6K48TGI9AUdb+IzbnSxvnvUMfuitfgcfuo=
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802 h1:1BDTz0u9nC3//pOCMdNH+CiXJVYJh5UQNCOBG7jbELc=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46 h1:lsxEuwrXEAokXB9qhlbKWPpo3KMLZQ5WB5WLQRW1uq0=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a h1:idn718Q4B6AGu/h5Sxe66HYVdqdGu2l9Iebqhi/AEoA=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/census-instrumentation/opencensus-proto v0.2.1 h1:glEXhBS5PSLLv4IXzLA5yPRVX4bilULVyxxbrfOtDAk=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1 h1:q763qf9huN11kDQavWsoZXJNW3xEE4JJyHa5Q25/sd8=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4 h1:ta993UF76GwbvJcIo3Y68y/M3WxlpEHPWIGDkJYwzJI=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/creack/pty v1.1.9 h1:uDmaGzcdjhF4i/plgjmEsriH11Y0o7RKapEf/LDaM3w=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815 h1:bWDMxwH3px2JBh6AyO7hdCn/PkvCZXii8TGj7sbtEbQ=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633 h1:H2pdYOb3KQ1/YsqVWoWNLQO+fusocsw354rqGTZtAgw=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473 h1:4cmBvAEBNJaGARUEs3/suWRyfyBfhf7I60WBZq+bv2w=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/protoc-gen-validate v0.1.0 h1:EQciDnbrYxy13PgWoY8AqoxGiPrpgBZ1R8UNe3ddc+A=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses=
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible h1:TcekIExNqud5crz4xD2pavyTgWiPvpYe4Xau31I0PRk=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1 h1:QbL/5oDUmRBzO9/Z7Seo6zf912W/a6Sr4Eu0G/3Jho0=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4 h1:WtGNWLvXpe6ZudgnXrq0barxBImvnnJoMEhXAzcbM0I=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-logr/logr v0.4.0 h1:K7/B1jt6fIBQVd4Owv2MqGQClcgf0R266+7C/QjRcLc=
github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
github.com/go-openapi/jsonpointer v0.19.2/go.mod h1:3akKfEdA7DF1sugOqz1dVQHBcuDBPKZGEoHC/NkiQRg=
github.com/go-openapi/jsonpointer v0.19.3 h1:gihV7YNZK1iK6Tgwwsxo2rJbD1GTbdm72325Bq8FI3w=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.19.2/go.mod h1:jMjeRr2HHw6nAVajTXJ4eiUwohSTlpa0o73RUL1owJc=
github.com/go-openapi/jsonreference v0.19.3 h1:5cxNfTy0UVC3X8JL5ymxzyoUZmo8iZb+jeTWn7tUa8o=
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
github.com/go-openapi/spec v0.19.3 h1:0XRyw8kguri6Yw4SxhsQA/atC88yqrk0+G4YhI2wabc=
github.com/go-openapi/spec v0.19.3/go.mod h1:FpwSN1ksY1eteniUU7X0N/BgJ7a4WvBFVA8Lj9mJglo=
github.com/go-openapi/swag v0.19.2/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/go-openapi/swag v0.19.5 h1:lTz6Ys4CmqqCQmZPBlbQENR1/GucA2bzYTE12Pw4tFY=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e h1:1r7pUrabqp18hOBcwBwiTsbnFeTZHV9eER/QT5JVZxY=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1 h1:ocYkMQY5RrXTYgXl7ICpV0IXwlEQGwKIsery4gyXa1U=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0 h1:0udJVsspx3VBr5FwtLhQQtuAsVc79tTq0ocGIPAU6qo=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.2 h1:X2ev0eStA3AbceY54o37/0PQ/UWqKEiiO2dKL5OPaFM=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0 h1:Hsa8mG0dQ46ij8Sl2AYJDUv1oA9/d6Vk+3LG99Oe02g=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3 h1:SRgJV+IoxM5MKyFdlSUeNy6/ycRUF2yBAKdAQswoHUk=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0 h1:GOZbcHa3HfsPKPlmyPyN2KEohoMXOhdMbHrvbpl2QaA=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2 h1:EVhdT+1Kseyi1/pUmXKaFxYsDNy9RQYkMWRH68J/W7Y=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5 h1:sjZBwGj9Jlw33ImPtvFviGYvseOtDM7hkSKB7+Tv3SM=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gnostic v0.4.1 h1:DLJCy1n/vrD4HPjOvYcT8aYQXpPIzoRZONaYwyycI+I=
github.com/googleapis/gnostic v0.4.1/go.mod h1:LRhVm6pbyptWbWbuZ38d1eyptfvIytN3ir6b65WBswg=
github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6 h1:UDMh68UUwekSh5iP2OMhRRZJiiBccgV7axzUG8vi56c=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.5 h1:JboBksRwiiAJWvIYJVo46AfV+IAIKZpfrSzVKj42R4Q=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.10 h1:Kz6Cvnvv2wGdaG/V8yMvfkmNiXq9Ya2KUv4rouJJr68=
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1 h1:6QPYqodiu3GuPL+7mfx+NwDdp2eTkp9IfEUpgAwUN0o=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kisielk/errcheck v1.5.0 h1:e8esj/e4R+SAOwFwN+n3zr0nYeCyeweozKfO23MvHzY=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0 h1:AV2c/EiW3KqPNT9ZKl07ehoAGi4C5/01Cfbblndcapg=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.5 h1:hyz3dwM5QLc1Rfoz4FuWJQG5BN7tc6K1MndAUnGpQr4=
github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e h1:hB2xlXdHp/pmPZq0y3QnmWAArdw9PqbmotexnWx/FU8=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d h1:7PxY7LVfSZm7PEeBTyK1rj1gABdCO2mbri6GKO1cMDs=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.11.0 h1:JAKSXpt1YjtLA7YpPiqO9ss6sNXEsPfSGdwN0UHqzrw=
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.7.0 h1:XPnZz8VVBHjVsy1vzJmRwIcSwiUO+JFfrv/xGiigmME=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4 h1:gQz4mCbXsO+nc9n1hCxHcGA3Zx3Eo+UHZoInFGUIXNM=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/spf13/afero v1.2.2 h1:5jhuqJyZCZf2JRofRvN/nIFgIWNzPa3/Vz8mYylgbWc=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0 h1:Hbg2NidpLE8veEBkEZTL3CvlkUIVzuU9jDplZO54c48=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1 h1:ruQGxdhGHe7FWOJPT0mKs5+pD2Xs1Bm/kdGlHO04FmM=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3 h1:8sGtKOrtQqkN1bp2AtX+misvLIlOmsEsNd+9NIcPEm8=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190611184440-5c40567a22f8/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83 h1:/ZScEX8SfEmUGRHs0gxpqteO5nfNW6axyZbBdw9A12g=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6 h1:QE6XYQK6naiK1EPAe1g/ILLxN5RBoH5xkJk3CqlMI/Y=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b h1:+qEpEAPhDZ1o0x3tHzZTQDArnOixOzGD9HUJfcg0mb4=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b h1:Wh+f8QHJXR411sJR8/vRBTZ7YapZaRvUcLFFJhusH0k=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028 h1:4+4C/Iv2U4fMZBiMCc98MG1In4gJY5YRhtpDNeDeHWs=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7 h1:OgUuv8lsRpBibGNbSizVwKWlysjaNzmC9gYMhPVfqFM=
golang.org/x/net v0.0.0-20210224082022-3d97a244fca7/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d h1:TzXSXBo42m9gQenoE3b9BGiEpg5IG2JkU5FkPIawgtw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9 h1:SQFwaSi55rU7vdNs9Yr0Z324VNlrF+0wMqRXT4St8ck=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190616124812-15dcb6c0061f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073 h1:8qxJSnu+7dRq6upnbntrmriWByIakBuct5OM/MdQC1M=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d h1:SZxvLBoTP5yHO3Frd4z4vrF+DBX9vMVanchswa69toE=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.4 h1:0YWbFKbhXG/wIiuHDSKpS0Iy7FSA+u45VtBMfQcFTTc=
golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190614205625-5aca471b1d59/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a h1:CB3a9Nez8M13wwlr/E2YtwoU+qYHKfC+JrDa45RXXoQ=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0 h1:jz2KixHX7EcCPiQrySzPdnYT7DbINAypCqKZ1Z7GM40=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5 h1:tycE03LOZYQNhDpS27tcQdAzLCVMaj7QT2SXxebnpCM=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1 h1:zvIju4sqAGvwKspUQOhwnpcqSbzi7/H6QomNNjTL4sk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.25.0 h1:Ejskq+SyPohKW+1uil0JJMtmHCgJPJ/qWTxr8qp+R4c=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0 h1:0vLT13EuvQ0hNvakwLuFZ/jYrLp5F3kcWHXdRggjCE8=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
k8s.io/api v0.21.0 h1:gu5iGF4V6tfVCQ/R+8Hc0h7H1JuEhzyEi9S4R5LM8+Y=
k8s.io/api v0.21.0/go.mod h1:+YbrhBBGgsxbF6o6Kj4KJPJnBmAKuXDeS3E18bgHNVU=
k8s.io/apimachinery v0.21.0 h1:3Fx+41if+IRavNcKOz09FwEXDBG6ORh6iMsTSelhkMA=
k8s.io/apimachinery v0.21.0/go.mod h1:jbreFvJo3ov9rj7eWT7+sYiRx+qZuCYXwWT1bcDswPY=
k8s.io/client-go v0.21.0 h1:n0zzzJsAQmJngpC0IhgFcApZyoGXPrDIAD601HD09ag=
k8s.io/client-go v0.21.0/go.mod h1:nNBytTF9qPFDEhoqgEPaarobC8QPae13bElIVHzIglA=
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac h1:sAvhNk5RRuc6FNYGqe7Ygz3PSo/2wGWbulskmzRX8Vs=
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
k8s.io/klog/v2 v2.8.0 h1:Q3gmuM9hKEjefWFFYF0Mat+YyFJvsUyYuwyNNJ5C9Ts=
k8s.io/klog/v2 v2.8.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec=
k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7 h1:vEx13qjvaZ4yfObSSXW7BrMc/KQBBT/Jyee8XtLf4x0=
k8s.io/kube-openapi v0.0.0-20210305001622-591a79e4bda7/go.mod h1:wXW5VT87nVfh/iLV8FpR2uDvrFyomxbtb1KivDbvPTE=
k8s.io/utils v0.0.0-20201110183641-67b214c5f920 h1:CbnUZsM497iRC5QMVkHwyl8s2tB3g7yaSHkYPkpgelw=
k8s.io/utils v0.0.0-20201110183641-67b214c5f920/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
rsc.io/binaryregexp v0.2.0 h1:HfqmD5MEmC0zvwBuF187nq9mdnXjXsSivRiXN7SmRkE=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0 h1:9JKUTTIUgS6kzR9mK1YuGKv6Nl+DijDNIc0ghT58FaY=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0 h1:7uVkIFmeBqHfdjD+gZwtXXI+RODJ2Wc4O7MPEh/QiW4=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
sigs.k8s.io/structured-merge-diff/v4 v4.1.0 h1:C4r9BgJ98vrKnnVCjwCSXcWjWe0NKcUQkmzDXZXGwH8=
sigs.k8s.io/structured-merge-diff/v4 v4.1.0/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=

View File

@@ -15,9 +15,9 @@ func NewFromInCluster(errOut chan error, namespace string) (*Resolver, error) {
if err != nil { if err != nil {
return nil, err return nil, err
} }
clientset, err := kubernetes.NewForConfig(config) clientSet, err := kubernetes.NewForConfig(config)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &Resolver{clientConfig: config, clientSet: clientset, nameMap: cmap.New(), serviceMap: cmap.New(), errOut: errOut, namespace: namespace}, nil return &Resolver{clientConfig: config, clientSet: clientSet, nameMap: cmap.New(), serviceMap: cmap.New(), errOut: errOut, namespace: namespace}, nil
} }

View File

@@ -0,0 +1,13 @@
package routes
import (
"github.com/gin-gonic/gin"
"github.com/up9inc/mizu/agent/pkg/controllers"
)
// ReplayRoutes defines the group of replay routes.
func ReplayRoutes(app *gin.Engine) {
routeGroup := app.Group("/replay")
routeGroup.POST("/", controllers.ReplayRequest)
}

View File

@@ -15,9 +15,8 @@ func StatusRoutes(ginApp *gin.Engine) {
routeGroup.GET("/connectedTappersCount", controllers.GetConnectedTappersCount) routeGroup.GET("/connectedTappersCount", controllers.GetConnectedTappersCount)
routeGroup.GET("/tap", controllers.GetTappingStatus) routeGroup.GET("/tap", controllers.GetTappingStatus)
routeGroup.GET("/general", controllers.GetGeneralStats) // get general stats about entries in DB routeGroup.GET("/general", controllers.GetGeneralStats)
routeGroup.GET("/accumulative", controllers.GetAccumulativeStats) routeGroup.GET("/trafficStats", controllers.GetTrafficStats)
routeGroup.GET("/accumulativeTiming", controllers.GetAccumulativeStatsTiming)
routeGroup.GET("/resolving", controllers.GetCurrentResolvingInformation) routeGroup.GET("/resolving", controllers.GetCurrentResolvingInformation)
} }

View File

@@ -1,124 +0,0 @@
package rules
import (
"encoding/base64"
"encoding/json"
"fmt"
"reflect"
"regexp"
"strings"
"github.com/up9inc/mizu/agent/pkg/har"
"github.com/up9inc/mizu/logger"
"github.com/up9inc/mizu/shared"
"github.com/yalp/jsonpath"
)
type RulesMatched struct {
Matched bool `json:"matched"`
Rule shared.RulePolicy `json:"rule"`
}
func appendRulesMatched(rulesMatched []RulesMatched, matched bool, rule shared.RulePolicy) []RulesMatched {
return append(rulesMatched, RulesMatched{Matched: matched, Rule: rule})
}
func ValidatePath(URLFromRule string, URL string) bool {
if URLFromRule != "" {
matchPath, err := regexp.MatchString(URLFromRule, URL)
if err != nil || !matchPath {
return false
}
}
return true
}
func ValidateService(serviceFromRule string, service string) bool {
if serviceFromRule != "" {
matchService, err := regexp.MatchString(serviceFromRule, service)
if err != nil || !matchService {
return false
}
}
return true
}
func MatchRequestPolicy(harEntry har.Entry, service string) (resultPolicyToSend []RulesMatched, isEnabled bool) {
enforcePolicy, err := shared.DecodeEnforcePolicy(fmt.Sprintf("%s%s", shared.ConfigDirPath, shared.ValidationRulesFileName))
if err == nil && len(enforcePolicy.Rules) > 0 {
isEnabled = true
}
for _, rule := range enforcePolicy.Rules {
if !ValidatePath(rule.Path, harEntry.Request.URL) || !ValidateService(rule.Service, service) {
continue
}
if rule.Type == "json" {
var bodyJsonMap interface{}
contentTextDecoded, _ := base64.StdEncoding.DecodeString(string(harEntry.Response.Content.Text))
if err := json.Unmarshal(contentTextDecoded, &bodyJsonMap); err != nil {
continue
}
out, err := jsonpath.Read(bodyJsonMap, rule.Key)
if err != nil || out == nil {
continue
}
var matchValue bool
if reflect.TypeOf(out).Kind() == reflect.String {
matchValue, err = regexp.MatchString(rule.Value, out.(string))
if err != nil {
continue
}
logger.Log.Info(matchValue, rule.Value)
} else {
val := fmt.Sprint(out)
matchValue, err = regexp.MatchString(rule.Value, val)
if err != nil {
continue
}
}
resultPolicyToSend = appendRulesMatched(resultPolicyToSend, matchValue, rule)
} else if rule.Type == "header" {
for j := range harEntry.Response.Headers {
matchKey, err := regexp.MatchString(rule.Key, harEntry.Response.Headers[j].Name)
if err != nil {
continue
}
if matchKey {
matchValue, err := regexp.MatchString(rule.Value, harEntry.Response.Headers[j].Value)
if err != nil {
continue
}
resultPolicyToSend = appendRulesMatched(resultPolicyToSend, matchValue, rule)
}
}
} else {
resultPolicyToSend = appendRulesMatched(resultPolicyToSend, true, rule)
}
}
return
}
func PassedValidationRules(rulesMatched []RulesMatched) (bool, int64, int) {
var numberOfRulesMatched = len(rulesMatched)
var responseTime int64 = -1
if numberOfRulesMatched == 0 {
return false, 0, numberOfRulesMatched
}
for _, rule := range rulesMatched {
if !rule.Matched {
return false, responseTime, numberOfRulesMatched
} else {
if strings.ToLower(rule.Rule.Type) == "slo" {
if rule.Rule.ResponseTime < responseTime || responseTime == -1 {
responseTime = rule.Rule.ResponseTime
}
}
}
}
return true, responseTime, numberOfRulesMatched
}

View File

@@ -50,11 +50,13 @@ var (
IP: fmt.Sprintf("%s.%s", Ip, UnresolvedNodeName), IP: fmt.Sprintf("%s.%s", Ip, UnresolvedNodeName),
} }
ProtocolHttp = &tapApi.Protocol{ ProtocolHttp = &tapApi.Protocol{
Name: "http", ProtocolSummary: tapApi.ProtocolSummary{
Name: "http",
Version: "1.1",
Abbreviation: "HTTP",
},
LongName: "Hypertext Transfer Protocol -- HTTP/1.1", LongName: "Hypertext Transfer Protocol -- HTTP/1.1",
Abbreviation: "HTTP",
Macro: "http", Macro: "http",
Version: "1.1",
BackgroundColor: "#205cf5", BackgroundColor: "#205cf5",
ForegroundColor: "#ffffff", ForegroundColor: "#ffffff",
FontSize: 12, FontSize: 12,
@@ -63,11 +65,13 @@ var (
Priority: 0, Priority: 0,
} }
ProtocolRedis = &tapApi.Protocol{ ProtocolRedis = &tapApi.Protocol{
Name: "redis", ProtocolSummary: tapApi.ProtocolSummary{
Name: "redis",
Version: "3.x",
Abbreviation: "REDIS",
},
LongName: "Redis Serialization Protocol", LongName: "Redis Serialization Protocol",
Abbreviation: "REDIS",
Macro: "redis", Macro: "redis",
Version: "3.x",
BackgroundColor: "#a41e11", BackgroundColor: "#a41e11",
ForegroundColor: "#ffffff", ForegroundColor: "#ffffff",
FontSize: 11, FontSize: 11,

View File

@@ -1,8 +1,9 @@
package utils package utils
import ( import (
"github.com/djherbis/atime"
"os" "os"
"github.com/djherbis/atime"
) )
type ByModTime []os.FileInfo type ByModTime []os.FileInfo
@@ -19,7 +20,6 @@ func (fis ByModTime) Less(i, j int) bool {
return fis[i].ModTime().Before(fis[j].ModTime()) return fis[i].ModTime().Before(fis[j].ModTime())
} }
type ByName []os.FileInfo type ByName []os.FileInfo
func (fis ByName) Len() int { func (fis ByName) Len() int {
@@ -34,7 +34,6 @@ func (fis ByName) Less(i, j int) bool {
return fis[i].Name() < fis[j].Name() return fis[i].Name() < fis[j].Name()
} }
type ByCreationTime []os.FileInfo type ByCreationTime []os.FileInfo
func (fis ByCreationTime) Len() int { func (fis ByCreationTime) Len() int {
@@ -47,4 +46,4 @@ func (fis ByCreationTime) Swap(i, j int) {
func (fis ByCreationTime) Less(i, j int) bool { func (fis ByCreationTime) Less(i, j int) bool {
return atime.Get(fis[i]).Unix() < atime.Get(fis[j]).Unix() return atime.Get(fis[i]).Unix() < atime.Get(fis[j]).Unix()
} }

View File

@@ -6,7 +6,6 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"net/url"
"os" "os"
"os/signal" "os/signal"
"syscall" "syscall"
@@ -59,17 +58,6 @@ func CheckErr(e error) {
} }
} }
func SetHostname(address, newHostname string) string {
replacedUrl, err := url.Parse(address)
if err != nil {
logger.Log.Errorf("error replacing hostname to %s in address %s, returning original %v", newHostname, address, err)
return address
}
replacedUrl.Host = newHostname
return replacedUrl.String()
}
func ReadJsonFile(filePath string, value interface{}) error { func ReadJsonFile(filePath string, value interface{}) error {
if content, err := ioutil.ReadFile(filePath); err != nil { if content, err := ioutil.ReadFile(filePath); err != nil {
return err return err

View File

@@ -4,9 +4,7 @@ import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt" "fmt"
"io/ioutil"
"net/http" "net/http"
"net/url"
"time" "time"
"github.com/up9inc/mizu/cli/utils" "github.com/up9inc/mizu/cli/utils"
@@ -93,45 +91,3 @@ func (provider *Provider) ReportTappedPods(pods []core.Pod) error {
} }
} }
} }
func (provider *Provider) GetGeneralStats() (map[string]interface{}, error) {
generalStatsUrl := fmt.Sprintf("%s/status/general", provider.url)
response, requestErr := utils.Get(generalStatsUrl, provider.client)
if requestErr != nil {
return nil, fmt.Errorf("failed to get general stats for telemetry, err: %w", requestErr)
}
defer response.Body.Close()
data, readErr := ioutil.ReadAll(response.Body)
if readErr != nil {
return nil, fmt.Errorf("failed to read general stats for telemetry, err: %v", readErr)
}
var generalStats map[string]interface{}
if parseErr := json.Unmarshal(data, &generalStats); parseErr != nil {
return nil, fmt.Errorf("failed to parse general stats for telemetry, err: %v", parseErr)
}
return generalStats, nil
}
func (provider *Provider) GetVersion() (string, error) {
versionUrl, _ := url.Parse(fmt.Sprintf("%s/metadata/version", provider.url))
req := &http.Request{
Method: http.MethodGet,
URL: versionUrl,
}
statusResp, err := utils.Do(req, provider.client)
if err != nil {
return "", err
}
defer statusResp.Body.Close()
versionResponse := &shared.VersionResponse{}
if err := json.NewDecoder(statusResp.Body).Decode(&versionResponse); err != nil {
return "", err
}
return versionResponse.Ver, nil
}

View File

@@ -4,7 +4,6 @@ import (
"github.com/creasty/defaults" "github.com/creasty/defaults"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/up9inc/mizu/cli/config/configStructs" "github.com/up9inc/mizu/cli/config/configStructs"
"github.com/up9inc/mizu/cli/telemetry"
"github.com/up9inc/mizu/logger" "github.com/up9inc/mizu/logger"
) )
@@ -12,7 +11,6 @@ var checkCmd = &cobra.Command{
Use: "check", Use: "check",
Short: "Check the Mizu installation for potential problems", Short: "Check the Mizu installation for potential problems",
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
go telemetry.ReportRun("check", nil)
runMizuCheck() runMizuCheck()
return nil return nil
}, },

View File

@@ -2,14 +2,12 @@ package cmd
import ( import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/up9inc/mizu/cli/telemetry"
) )
var cleanCmd = &cobra.Command{ var cleanCmd = &cobra.Command{
Use: "clean", Use: "clean",
Short: "Removes all mizu resources", Short: "Removes all mizu resources",
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
go telemetry.ReportRun("clean", nil)
performCleanCommand() performCleanCommand()
return nil return nil
}, },

View File

@@ -7,7 +7,6 @@ import (
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/up9inc/mizu/cli/config" "github.com/up9inc/mizu/cli/config"
"github.com/up9inc/mizu/cli/config/configStructs" "github.com/up9inc/mizu/cli/config/configStructs"
"github.com/up9inc/mizu/cli/telemetry"
"github.com/up9inc/mizu/cli/uiUtils" "github.com/up9inc/mizu/cli/uiUtils"
"github.com/up9inc/mizu/logger" "github.com/up9inc/mizu/logger"
) )
@@ -16,8 +15,6 @@ var configCmd = &cobra.Command{
Use: "config", Use: "config",
Short: "Generate config with default values", Short: "Generate config with default values",
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
go telemetry.ReportRun("config", config.Config.Config)
configWithDefaults, err := config.GetConfigWithDefaults() configWithDefaults, err := config.GetConfigWithDefaults()
if err != nil { if err != nil {
logger.Log.Errorf("Failed generating config with defaults, err: %v", err) logger.Log.Errorf("Failed generating config with defaults, err: %v", err)

View File

@@ -4,7 +4,6 @@ import (
"github.com/creasty/defaults" "github.com/creasty/defaults"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/up9inc/mizu/cli/config/configStructs" "github.com/up9inc/mizu/cli/config/configStructs"
"github.com/up9inc/mizu/cli/telemetry"
"github.com/up9inc/mizu/logger" "github.com/up9inc/mizu/logger"
) )
@@ -12,7 +11,6 @@ var installCmd = &cobra.Command{
Use: "install", Use: "install",
Short: "Installs mizu components", Short: "Installs mizu components",
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
go telemetry.ReportRun("install", nil)
runMizuInstall() runMizuInstall()
return nil return nil
}, },

View File

@@ -9,7 +9,6 @@ import (
"github.com/up9inc/mizu/cli/config/configStructs" "github.com/up9inc/mizu/cli/config/configStructs"
"github.com/up9inc/mizu/cli/errormessage" "github.com/up9inc/mizu/cli/errormessage"
"github.com/up9inc/mizu/cli/mizu/fsUtils" "github.com/up9inc/mizu/cli/mizu/fsUtils"
"github.com/up9inc/mizu/cli/telemetry"
"github.com/up9inc/mizu/logger" "github.com/up9inc/mizu/logger"
) )
@@ -17,8 +16,6 @@ var logsCmd = &cobra.Command{
Use: "logs", Use: "logs",
Short: "Create a zip file with logs for Github issue or troubleshoot", Short: "Create a zip file with logs for Github issue or troubleshoot",
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
go telemetry.ReportRun("logs", config.Config.Logs)
kubernetesProvider, err := getKubernetesProviderForCli() kubernetesProvider, err := getKubernetesProviderForCli()
if err != nil { if err != nil {
return nil return nil

View File

@@ -48,14 +48,12 @@ func init() {
tapCmd.Flags().Uint16P(configStructs.GuiPortTapName, "p", defaultTapConfig.GuiPort, "Provide a custom port for the web interface webserver") tapCmd.Flags().Uint16P(configStructs.GuiPortTapName, "p", defaultTapConfig.GuiPort, "Provide a custom port for the web interface webserver")
tapCmd.Flags().StringSliceP(configStructs.NamespacesTapName, "n", defaultTapConfig.Namespaces, "Namespaces selector") tapCmd.Flags().StringSliceP(configStructs.NamespacesTapName, "n", defaultTapConfig.Namespaces, "Namespaces selector")
tapCmd.Flags().BoolP(configStructs.AllNamespacesTapName, "A", defaultTapConfig.AllNamespaces, "Tap all namespaces") tapCmd.Flags().BoolP(configStructs.AllNamespacesTapName, "A", defaultTapConfig.AllNamespaces, "Tap all namespaces")
tapCmd.Flags().StringSliceP(configStructs.PlainTextFilterRegexesTapName, "r", defaultTapConfig.PlainTextFilterRegexes, "List of regex expressions that are used to filter matching values from text/plain http bodies")
tapCmd.Flags().Bool(configStructs.EnableRedactionTapName, defaultTapConfig.EnableRedaction, "Enables redaction of potentially sensitive request/response headers and body values") tapCmd.Flags().Bool(configStructs.EnableRedactionTapName, defaultTapConfig.EnableRedaction, "Enables redaction of potentially sensitive request/response headers and body values")
tapCmd.Flags().String(configStructs.HumanMaxEntriesDBSizeTapName, defaultTapConfig.HumanMaxEntriesDBSize, "Override the default max entries db size") tapCmd.Flags().String(configStructs.HumanMaxEntriesDBSizeTapName, defaultTapConfig.HumanMaxEntriesDBSize, "Override the default max entries db size")
tapCmd.Flags().String(configStructs.InsertionFilterName, defaultTapConfig.InsertionFilter, "Set the insertion filter. Accepts string or a file path.") tapCmd.Flags().String(configStructs.InsertionFilterName, defaultTapConfig.InsertionFilter, "Set the insertion filter. Accepts string or a file path.")
tapCmd.Flags().Bool(configStructs.DryRunTapName, defaultTapConfig.DryRun, "Preview of all pods matching the regex, without tapping them") tapCmd.Flags().Bool(configStructs.DryRunTapName, defaultTapConfig.DryRun, "Preview of all pods matching the regex, without tapping them")
tapCmd.Flags().String(configStructs.EnforcePolicyFile, defaultTapConfig.EnforcePolicyFile, "Yaml file path with policy rules")
tapCmd.Flags().String(configStructs.ContractFile, defaultTapConfig.ContractFile, "OAS/Swagger file to validate to monitor the contracts")
tapCmd.Flags().Bool(configStructs.ServiceMeshName, defaultTapConfig.ServiceMesh, "Record decrypted traffic if the cluster is configured with a service mesh and with mtls") tapCmd.Flags().Bool(configStructs.ServiceMeshName, defaultTapConfig.ServiceMesh, "Record decrypted traffic if the cluster is configured with a service mesh and with mtls")
tapCmd.Flags().Bool(configStructs.TlsName, defaultTapConfig.Tls, "Record tls traffic") tapCmd.Flags().Bool(configStructs.TlsName, defaultTapConfig.Tls, "Record tls traffic")
tapCmd.Flags().Bool(configStructs.ProfilerName, defaultTapConfig.Profiler, "Run pprof server") tapCmd.Flags().Bool(configStructs.ProfilerName, defaultTapConfig.Profiler, "Run pprof server")
tapCmd.Flags().Int(configStructs.MaxLiveStreamsName, defaultTapConfig.MaxLiveStreams, "Maximum live tcp streams to handle concurrently")
} }

View File

@@ -4,17 +4,13 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"regexp" "regexp"
"strings" "strings"
"time" "time"
"github.com/up9inc/mizu/cli/resources" "github.com/up9inc/mizu/cli/resources"
"github.com/up9inc/mizu/cli/telemetry"
"github.com/up9inc/mizu/cli/utils" "github.com/up9inc/mizu/cli/utils"
"github.com/getkin/kin-openapi/openapi3"
"gopkg.in/yaml.v3"
core "k8s.io/api/core/v1" core "k8s.io/api/core/v1"
k8serrors "k8s.io/apimachinery/pkg/api/errors" k8serrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -47,40 +43,6 @@ func RunMizuTap() {
apiProvider = apiserver.NewProvider(GetApiServerUrl(config.Config.Tap.GuiPort), apiserver.DefaultRetries, apiserver.DefaultTimeout) apiProvider = apiserver.NewProvider(GetApiServerUrl(config.Config.Tap.GuiPort), apiserver.DefaultRetries, apiserver.DefaultTimeout)
var err error
var serializedValidationRules string
if config.Config.Tap.EnforcePolicyFile != "" {
serializedValidationRules, err = readValidationRules(config.Config.Tap.EnforcePolicyFile)
if err != nil {
logger.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error reading policy file: %v", errormessage.FormatError(err)))
return
}
}
// Read and validate the OAS file
var serializedContract string
if config.Config.Tap.ContractFile != "" {
bytes, err := ioutil.ReadFile(config.Config.Tap.ContractFile)
if err != nil {
logger.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error reading contract file: %v", errormessage.FormatError(err)))
return
}
serializedContract = string(bytes)
ctx := context.Background()
loader := &openapi3.Loader{Context: ctx}
doc, err := loader.LoadFromData(bytes)
if err != nil {
logger.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error loading contract file: %v", errormessage.FormatError(err)))
return
}
err = doc.Validate(ctx)
if err != nil {
logger.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error validating contract file: %v", errormessage.FormatError(err)))
return
}
}
kubernetesProvider, err := getKubernetesProviderForCli() kubernetesProvider, err := getKubernetesProviderForCli()
if err != nil { if err != nil {
return return
@@ -124,7 +86,7 @@ func RunMizuTap() {
} }
logger.Log.Infof("Waiting for Mizu Agent to start...") logger.Log.Infof("Waiting for Mizu Agent to start...")
if state.mizuServiceAccountExists, err = resources.CreateTapMizuResources(ctx, kubernetesProvider, serializedValidationRules, serializedContract, serializedMizuConfig, config.Config.IsNsRestrictedMode(), config.Config.MizuResourcesNamespace, config.Config.AgentImage, config.Config.Tap.MaxEntriesDBSizeBytes(), config.Config.Tap.ApiServerResources, config.Config.ImagePullPolicy(), config.Config.LogLevel(), config.Config.Tap.Profiler); err != nil { if state.mizuServiceAccountExists, err = resources.CreateTapMizuResources(ctx, kubernetesProvider, serializedMizuConfig, config.Config.IsNsRestrictedMode(), config.Config.MizuResourcesNamespace, config.Config.AgentImage, config.Config.Tap.MaxEntriesDBSizeBytes(), config.Config.Tap.ApiServerResources, config.Config.ImagePullPolicy(), config.Config.LogLevel(), config.Config.Tap.Profiler); err != nil {
var statusError *k8serrors.StatusError var statusError *k8serrors.StatusError
if errors.As(err, &statusError) && (statusError.ErrStatus.Reason == metav1.StatusReasonAlreadyExists) { if errors.As(err, &statusError) && (statusError.ErrStatus.Reason == metav1.StatusReasonAlreadyExists) {
logger.Log.Info("Mizu is already running in this namespace, change the `mizu-resources-namespace` configuration or run `mizu clean` to remove the currently running Mizu instance") logger.Log.Info("Mizu is already running in this namespace, change the `mizu-resources-namespace` configuration or run `mizu clean` to remove the currently running Mizu instance")
@@ -146,8 +108,6 @@ func RunMizuTap() {
} }
func finishTapExecution(kubernetesProvider *kubernetes.Provider) { func finishTapExecution(kubernetesProvider *kubernetes.Provider) {
telemetry.ReportTapTelemetry(apiProvider, config.Config.Tap, state.startTime)
finishMizuExecution(kubernetesProvider, config.Config.IsNsRestrictedMode(), config.Config.MizuResourcesNamespace) finishMizuExecution(kubernetesProvider, config.Config.IsNsRestrictedMode(), config.Config.MizuResourcesNamespace)
} }
@@ -163,7 +123,6 @@ func getTapMizuAgentConfig() *shared.MizuAgentConfig {
AgentDatabasePath: shared.DataDirPath, AgentDatabasePath: shared.DataDirPath,
ServiceMap: config.Config.ServiceMap, ServiceMap: config.Config.ServiceMap,
OAS: config.Config.OAS, OAS: config.Config.OAS,
Telemetry: config.Config.Telemetry,
} }
return &mizuAgentConfig return &mizuAgentConfig
@@ -188,20 +147,22 @@ func printTappedPodsPreview(ctx context.Context, kubernetesProvider *kubernetes.
} }
} }
func startTapperSyncer(ctx context.Context, cancel context.CancelFunc, provider *kubernetes.Provider, targetNamespaces []string, mizuApiFilteringOptions api.TrafficFilteringOptions, startTime time.Time) error { func startTapperSyncer(ctx context.Context, cancel context.CancelFunc, provider *kubernetes.Provider, targetNamespaces []string, startTime time.Time) error {
tapperSyncer, err := kubernetes.CreateAndStartMizuTapperSyncer(ctx, provider, kubernetes.TapperSyncerConfig{ tapperSyncer, err := kubernetes.CreateAndStartMizuTapperSyncer(ctx, provider, kubernetes.TapperSyncerConfig{
TargetNamespaces: targetNamespaces, TargetNamespaces: targetNamespaces,
PodFilterRegex: *config.Config.Tap.PodRegex(), PodFilterRegex: *config.Config.Tap.PodRegex(),
MizuResourcesNamespace: config.Config.MizuResourcesNamespace, MizuResourcesNamespace: config.Config.MizuResourcesNamespace,
AgentImage: config.Config.AgentImage, AgentImage: config.Config.AgentImage,
TapperResources: config.Config.Tap.TapperResources, TapperResources: config.Config.Tap.TapperResources,
ImagePullPolicy: config.Config.ImagePullPolicy(), ImagePullPolicy: config.Config.ImagePullPolicy(),
LogLevel: config.Config.LogLevel(), LogLevel: config.Config.LogLevel(),
IgnoredUserAgents: config.Config.Tap.IgnoredUserAgents, MizuApiFilteringOptions: api.TrafficFilteringOptions{
MizuApiFilteringOptions: mizuApiFilteringOptions, IgnoredUserAgents: config.Config.Tap.IgnoredUserAgents,
},
MizuServiceAccountExists: state.mizuServiceAccountExists, MizuServiceAccountExists: state.mizuServiceAccountExists,
ServiceMesh: config.Config.Tap.ServiceMesh, ServiceMesh: config.Config.Tap.ServiceMesh,
Tls: config.Config.Tap.Tls, Tls: config.Config.Tap.Tls,
MaxLiveStreams: config.Config.Tap.MaxLiveStreams,
}, startTime) }, startTime)
if err != nil { if err != nil {
@@ -265,36 +226,6 @@ func getErrorDisplayTextForK8sTapManagerError(err kubernetes.K8sTapManagerError)
} }
} }
func readValidationRules(file string) (string, error) {
rules, err := shared.DecodeEnforcePolicy(file)
if err != nil {
return "", err
}
newContent, _ := yaml.Marshal(&rules)
return string(newContent), nil
}
func getMizuApiFilteringOptions() (*api.TrafficFilteringOptions, error) {
var compiledRegexSlice []*api.SerializableRegexp
if config.Config.Tap.PlainTextFilterRegexes != nil && len(config.Config.Tap.PlainTextFilterRegexes) > 0 {
compiledRegexSlice = make([]*api.SerializableRegexp, 0)
for _, regexStr := range config.Config.Tap.PlainTextFilterRegexes {
compiledRegex, err := api.CompileRegexToSerializableRegexp(regexStr)
if err != nil {
return nil, err
}
compiledRegexSlice = append(compiledRegexSlice, compiledRegex)
}
}
return &api.TrafficFilteringOptions{
PlainTextMaskingRegexes: compiledRegexSlice,
IgnoredUserAgents: config.Config.Tap.IgnoredUserAgents,
EnableRedaction: config.Config.Tap.EnableRedaction,
}, nil
}
func watchApiServerPod(ctx context.Context, kubernetesProvider *kubernetes.Provider, cancel context.CancelFunc) { func watchApiServerPod(ctx context.Context, kubernetesProvider *kubernetes.Provider, cancel context.CancelFunc) {
podExactRegex := regexp.MustCompile(fmt.Sprintf("^%s$", kubernetes.ApiServerPodName)) podExactRegex := regexp.MustCompile(fmt.Sprintf("^%s$", kubernetes.ApiServerPodName))
podWatchHelper := kubernetes.NewPodWatchHelper(kubernetesProvider, podExactRegex) podWatchHelper := kubernetes.NewPodWatchHelper(kubernetesProvider, podExactRegex)
@@ -412,8 +343,7 @@ func watchApiServerEvents(ctx context.Context, kubernetesProvider *kubernetes.Pr
func postApiServerStarted(ctx context.Context, kubernetesProvider *kubernetes.Provider, cancel context.CancelFunc) { func postApiServerStarted(ctx context.Context, kubernetesProvider *kubernetes.Provider, cancel context.CancelFunc) {
startProxyReportErrorIfAny(kubernetesProvider, ctx, cancel, config.Config.Tap.GuiPort) startProxyReportErrorIfAny(kubernetesProvider, ctx, cancel, config.Config.Tap.GuiPort)
options, _ := getMizuApiFilteringOptions() if err := startTapperSyncer(ctx, cancel, kubernetesProvider, state.targetNamespaces, state.startTime); err != nil {
if err := startTapperSyncer(ctx, cancel, kubernetesProvider, state.targetNamespaces, *options, state.startTime); err != nil {
logger.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error starting mizu tapper syncer: %v", errormessage.FormatError(err))) logger.Log.Errorf(uiUtils.Error, fmt.Sprintf("Error starting mizu tapper syncer: %v", errormessage.FormatError(err)))
cancel() cancel()
} }

View File

@@ -6,7 +6,6 @@ import (
"github.com/up9inc/mizu/cli/config" "github.com/up9inc/mizu/cli/config"
"github.com/up9inc/mizu/cli/config/configStructs" "github.com/up9inc/mizu/cli/config/configStructs"
"github.com/up9inc/mizu/cli/telemetry"
"github.com/up9inc/mizu/logger" "github.com/up9inc/mizu/logger"
"github.com/creasty/defaults" "github.com/creasty/defaults"
@@ -18,8 +17,6 @@ var versionCmd = &cobra.Command{
Use: "version", Use: "version",
Short: "Print version info", Short: "Print version info",
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
go telemetry.ReportRun("version", config.Config.Version)
if config.Config.Version.DebugInfo { if config.Config.Version.DebugInfo {
timeStampInt, _ := strconv.ParseInt(mizu.BuildTimestamp, 10, 0) timeStampInt, _ := strconv.ParseInt(mizu.BuildTimestamp, 10, 0)
logger.Log.Infof("Version: %s \nBranch: %s (%s)", mizu.Ver, mizu.Branch, mizu.GitCommitHash) logger.Log.Infof("Version: %s \nBranch: %s (%s)", mizu.Ver, mizu.Branch, mizu.GitCommitHash)

View File

@@ -3,9 +3,7 @@ package cmd
import ( import (
"github.com/creasty/defaults" "github.com/creasty/defaults"
"github.com/spf13/cobra" "github.com/spf13/cobra"
"github.com/up9inc/mizu/cli/config"
"github.com/up9inc/mizu/cli/config/configStructs" "github.com/up9inc/mizu/cli/config/configStructs"
"github.com/up9inc/mizu/cli/telemetry"
"github.com/up9inc/mizu/logger" "github.com/up9inc/mizu/logger"
) )
@@ -13,7 +11,6 @@ var viewCmd = &cobra.Command{
Use: "view", Use: "view",
Short: "Open GUI in browser", Short: "Open GUI in browser",
RunE: func(cmd *cobra.Command, args []string) error { RunE: func(cmd *cobra.Command, args []string) error {
go telemetry.ReportRun("view", config.Config.View)
runMizuView() runMizuView()
return nil return nil
}, },

View File

@@ -31,7 +31,6 @@ type ConfigStruct struct {
AgentImage string `yaml:"agent-image,omitempty" readonly:""` AgentImage string `yaml:"agent-image,omitempty" readonly:""`
ImagePullPolicyStr string `yaml:"image-pull-policy" default:"Always"` ImagePullPolicyStr string `yaml:"image-pull-policy" default:"Always"`
MizuResourcesNamespace string `yaml:"mizu-resources-namespace" default:"mizu"` MizuResourcesNamespace string `yaml:"mizu-resources-namespace" default:"mizu"`
Telemetry bool `yaml:"telemetry" default:"true"`
DumpLogs bool `yaml:"dump-logs" default:"false"` DumpLogs bool `yaml:"dump-logs" default:"false"`
KubeConfigPathStr string `yaml:"kube-config-path"` KubeConfigPathStr string `yaml:"kube-config-path"`
KubeContext string `yaml:"kube-context"` KubeContext string `yaml:"kube-context"`

View File

@@ -6,6 +6,7 @@ import (
"io/ioutil" "io/ioutil"
"os" "os"
"regexp" "regexp"
"strings"
"github.com/up9inc/mizu/cli/uiUtils" "github.com/up9inc/mizu/cli/uiUtils"
"github.com/up9inc/mizu/shared" "github.com/up9inc/mizu/shared"
@@ -15,40 +16,43 @@ import (
) )
const ( const (
GuiPortTapName = "gui-port" GuiPortTapName = "gui-port"
NamespacesTapName = "namespaces" NamespacesTapName = "namespaces"
AllNamespacesTapName = "all-namespaces" AllNamespacesTapName = "all-namespaces"
PlainTextFilterRegexesTapName = "regex-masking" EnableRedactionTapName = "redact"
EnableRedactionTapName = "redact" HumanMaxEntriesDBSizeTapName = "max-entries-db-size"
HumanMaxEntriesDBSizeTapName = "max-entries-db-size" InsertionFilterName = "insertion-filter"
InsertionFilterName = "insertion-filter" DryRunTapName = "dry-run"
DryRunTapName = "dry-run" ServiceMeshName = "service-mesh"
EnforcePolicyFile = "traffic-validation-file" TlsName = "tls"
ContractFile = "contract" ProfilerName = "profiler"
ServiceMeshName = "service-mesh" MaxLiveStreamsName = "max-live-streams"
TlsName = "tls"
ProfilerName = "profiler"
) )
type TapConfig struct { type TapConfig struct {
PodRegexStr string `yaml:"regex" default:".*"` PodRegexStr string `yaml:"regex" default:".*"`
GuiPort uint16 `yaml:"gui-port" default:"8899"` GuiPort uint16 `yaml:"gui-port" default:"8899"`
ProxyHost string `yaml:"proxy-host" default:"127.0.0.1"` ProxyHost string `yaml:"proxy-host" default:"127.0.0.1"`
Namespaces []string `yaml:"namespaces"` Namespaces []string `yaml:"namespaces"`
AllNamespaces bool `yaml:"all-namespaces" default:"false"` AllNamespaces bool `yaml:"all-namespaces" default:"false"`
PlainTextFilterRegexes []string `yaml:"regex-masking"` IgnoredUserAgents []string `yaml:"ignored-user-agents"`
IgnoredUserAgents []string `yaml:"ignored-user-agents"` EnableRedaction bool `yaml:"redact" default:"false"`
EnableRedaction bool `yaml:"redact" default:"false"` RedactPatterns struct {
HumanMaxEntriesDBSize string `yaml:"max-entries-db-size" default:"200MB"` RequestHeaders []string `yaml:"request-headers"`
InsertionFilter string `yaml:"insertion-filter" default:""` ResponseHeaders []string `yaml:"response-headers"`
DryRun bool `yaml:"dry-run" default:"false"` RequestBody []string `yaml:"request-body"`
EnforcePolicyFile string `yaml:"traffic-validation-file"` ResponseBody []string `yaml:"response-body"`
ContractFile string `yaml:"contract"` RequestQueryParams []string `yaml:"request-query-params"`
ApiServerResources shared.Resources `yaml:"api-server-resources"` } `yaml:"redact-patterns"`
TapperResources shared.Resources `yaml:"tapper-resources"` HumanMaxEntriesDBSize string `yaml:"max-entries-db-size" default:"200MB"`
ServiceMesh bool `yaml:"service-mesh" default:"false"` InsertionFilter string `yaml:"insertion-filter" default:""`
Tls bool `yaml:"tls" default:"false"` DryRun bool `yaml:"dry-run" default:"false"`
Profiler bool `yaml:"profiler" default:"false"` ApiServerResources shared.Resources `yaml:"api-server-resources"`
TapperResources shared.Resources `yaml:"tapper-resources"`
ServiceMesh bool `yaml:"service-mesh" default:"false"`
Tls bool `yaml:"tls" default:"false"`
Profiler bool `yaml:"profiler" default:"false"`
MaxLiveStreams int `yaml:"max-live-streams" default:"500"`
} }
func (config *TapConfig) PodRegex() *regexp.Regexp { func (config *TapConfig) PodRegex() *regexp.Regexp {
@@ -73,9 +77,48 @@ func (config *TapConfig) GetInsertionFilter() string {
} }
} }
} }
redactFilter := getRedactFilter(config)
if insertionFilter != "" && redactFilter != "" {
return fmt.Sprintf("(%s) and (%s)", insertionFilter, redactFilter)
} else if insertionFilter == "" && redactFilter != "" {
return redactFilter
}
return insertionFilter return insertionFilter
} }
func getRedactFilter(config *TapConfig) string {
if !config.EnableRedaction {
return ""
}
var redactValues []string
for _, requestHeader := range config.RedactPatterns.RequestHeaders {
redactValues = append(redactValues, fmt.Sprintf("request.headers['%s']", requestHeader))
}
for _, responseHeader := range config.RedactPatterns.ResponseHeaders {
redactValues = append(redactValues, fmt.Sprintf("response.headers['%s']", responseHeader))
}
for _, requestBody := range config.RedactPatterns.RequestBody {
redactValues = append(redactValues, fmt.Sprintf("request.postData.text.json()...%s", requestBody))
}
for _, responseBody := range config.RedactPatterns.ResponseBody {
redactValues = append(redactValues, fmt.Sprintf("response.content.text.json()...%s", responseBody))
}
for _, requestQueryParams := range config.RedactPatterns.RequestQueryParams {
redactValues = append(redactValues, fmt.Sprintf("request.queryString['%s']", requestQueryParams))
}
if len(redactValues) == 0 {
return ""
}
return fmt.Sprintf("redact(\"%s\")", strings.Join(redactValues, "\",\""))
}
func (config *TapConfig) Validate() error { func (config *TapConfig) Validate() error {
_, compileErr := regexp.Compile(config.PodRegexStr) _, compileErr := regexp.Compile(config.PodRegexStr)
if compileErr != nil { if compileErr != nil {

View File

@@ -4,17 +4,13 @@ go 1.17
require ( require (
github.com/creasty/defaults v1.5.2 github.com/creasty/defaults v1.5.2
github.com/denisbrodbeck/machineid v1.0.1
github.com/getkin/kin-openapi v0.89.0
github.com/google/go-github/v37 v37.0.0 github.com/google/go-github/v37 v37.0.0
github.com/google/uuid v1.3.0
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
github.com/spf13/cobra v1.3.0 github.com/spf13/cobra v1.3.0
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
github.com/up9inc/mizu/logger v0.0.0 github.com/up9inc/mizu/logger v0.0.0
github.com/up9inc/mizu/shared v0.0.0 github.com/up9inc/mizu/shared v0.0.0
github.com/up9inc/mizu/tap/api v0.0.0 github.com/up9inc/mizu/tap/api v0.0.0
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
k8s.io/api v0.23.3 k8s.io/api v0.23.3
k8s.io/apimachinery v0.23.3 k8s.io/apimachinery v0.23.3
@@ -39,7 +35,6 @@ require (
github.com/evanphx/json-patch v5.6.0+incompatible // indirect github.com/evanphx/json-patch v5.6.0+incompatible // indirect
github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect github.com/exponent-io/jsonpath v0.0.0-20210407135951-1de76d718b3f // indirect
github.com/fvbommel/sortorder v1.0.2 // indirect github.com/fvbommel/sortorder v1.0.2 // indirect
github.com/ghodss/yaml v1.0.0 // indirect
github.com/go-errors/errors v1.4.2 // indirect github.com/go-errors/errors v1.4.2 // indirect
github.com/go-logr/logr v1.2.2 // indirect github.com/go-logr/logr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect github.com/go-openapi/jsonpointer v0.19.5 // indirect
@@ -52,8 +47,8 @@ require (
github.com/google/go-cmp v0.5.7 // indirect github.com/google/go-cmp v0.5.7 // indirect
github.com/google/go-querystring v1.1.0 // indirect github.com/google/go-querystring v1.1.0 // indirect
github.com/google/gofuzz v1.2.0 // indirect github.com/google/gofuzz v1.2.0 // indirect
github.com/google/martian v2.1.0+incompatible // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/googleapis/gnostic v0.5.5 // indirect github.com/googleapis/gnostic v0.5.5 // indirect
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
github.com/imdario/mergo v0.3.12 // indirect github.com/imdario/mergo v0.3.12 // indirect
@@ -79,6 +74,7 @@ require (
go.starlark.net v0.0.0-20220203230714-bb14e151c28f // indirect go.starlark.net v0.0.0-20220203230714-bb14e151c28f // indirect
golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab // indirect golang.org/x/crypto v0.0.0-20220208050332-20e1d8d225ab // indirect
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
golang.org/x/sys v0.0.0-20220207234003-57398862261d // indirect golang.org/x/sys v0.0.0-20220207234003-57398862261d // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect golang.org/x/text v0.3.7 // indirect

View File

@@ -145,8 +145,6 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE=
github.com/denisbrodbeck/machineid v1.0.1 h1:geKr9qtkB876mXguW2X6TU4ZynleN6ezuMSRhl4D7AQ=
github.com/denisbrodbeck/machineid v1.0.1/go.mod h1:dJUwb7PTidGDeYyUBmXZ2GphQBbjJCrnectwCyxcUSI=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no= github.com/dgryski/go-sip13 v0.0.0-20181026042036-e10d5fee7954/go.mod h1:vAd38F8PWV+bWy6jNmig1y/TA+kYO4g3RSRF0IAv0no=
github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
@@ -190,9 +188,6 @@ github.com/fvbommel/sortorder v1.0.1/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui72
github.com/fvbommel/sortorder v1.0.2 h1:mV4o8B2hKboCdkJm+a7uX/SIpZob4JzUpc5GGnM45eo= github.com/fvbommel/sortorder v1.0.2 h1:mV4o8B2hKboCdkJm+a7uX/SIpZob4JzUpc5GGnM45eo=
github.com/fvbommel/sortorder v1.0.2/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0= github.com/fvbommel/sortorder v1.0.2/go.mod h1:uk88iVf1ovNn1iLfgUVU2F9o5eO30ui720w+kxuqRs0=
github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg= github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
github.com/getkin/kin-openapi v0.89.0 h1:p4nagHchUKGn85z/f+pse4aSh50nIBOYjOhMIku2hiA=
github.com/getkin/kin-openapi v0.89.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA= github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
@@ -294,7 +289,6 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=

View File

@@ -14,8 +14,6 @@ var (
Platform = "" Platform = ""
) )
const DEVENVVAR = "MIZU_DISABLE_TELEMTRY"
func GetMizuFolderPath() string { func GetMizuFolderPath() string {
home, homeDirErr := os.UserHomeDir() home, homeDirErr := os.UserHomeDir()
if homeDirErr != nil { if homeDirErr != nil {

View File

@@ -5,42 +5,18 @@ import (
"fmt" "fmt"
"io/ioutil" "io/ioutil"
"net/http" "net/http"
"os"
"runtime" "runtime"
"strings" "strings"
"time" "time"
"github.com/up9inc/mizu/cli/apiserver"
"github.com/up9inc/mizu/cli/mizu" "github.com/up9inc/mizu/cli/mizu"
"github.com/up9inc/mizu/cli/pkg/version" "github.com/up9inc/mizu/cli/pkg/version"
"github.com/up9inc/mizu/logger" "github.com/up9inc/mizu/logger"
"github.com/google/go-github/v37/github" "github.com/google/go-github/v37/github"
"github.com/up9inc/mizu/cli/uiUtils"
) )
func CheckVersionCompatibility(apiServerProvider *apiserver.Provider) (bool, error) {
apiVer, err := apiServerProvider.GetVersion()
if err != nil {
return false, err
}
if equals, err := version.AreEquals(apiVer, mizu.Ver); err != nil {
return false, fmt.Errorf("Failed to check version equality between mizuVer: %s and apiVer: %s, error: %w", mizu.Ver, apiVer, err)
} else if !equals {
logger.Log.Errorf(uiUtils.Red, fmt.Sprintf("cli version (%s) is not compatible with api version (%s)", mizu.Ver, apiVer))
return false, nil
}
logger.Log.Debug("cli version %s is compatible with api version %s", mizu.Ver, apiVer)
return true, nil
}
func CheckNewerVersion(versionChan chan string) { func CheckNewerVersion(versionChan chan string) {
if _, present := os.LookupEnv(mizu.DEVENVVAR); present {
versionChan <- ""
return
}
logger.Log.Debugf("Checking for newer version...") logger.Log.Debugf("Checking for newer version...")
start := time.Now() start := time.Now()
client := github.NewClient(nil) client := github.NewClient(nil)

View File

@@ -14,14 +14,14 @@ import (
core "k8s.io/api/core/v1" core "k8s.io/api/core/v1"
) )
func CreateTapMizuResources(ctx context.Context, kubernetesProvider *kubernetes.Provider, serializedValidationRules string, serializedContract string, serializedMizuConfig string, isNsRestrictedMode bool, mizuResourcesNamespace string, agentImage string, maxEntriesDBSizeBytes int64, apiServerResources shared.Resources, imagePullPolicy core.PullPolicy, logLevel logging.Level, profiler bool) (bool, error) { func CreateTapMizuResources(ctx context.Context, kubernetesProvider *kubernetes.Provider, serializedMizuConfig string, isNsRestrictedMode bool, mizuResourcesNamespace string, agentImage string, maxEntriesDBSizeBytes int64, apiServerResources shared.Resources, imagePullPolicy core.PullPolicy, logLevel logging.Level, profiler bool) (bool, error) {
if !isNsRestrictedMode { if !isNsRestrictedMode {
if err := createMizuNamespace(ctx, kubernetesProvider, mizuResourcesNamespace); err != nil { if err := createMizuNamespace(ctx, kubernetesProvider, mizuResourcesNamespace); err != nil {
return false, err return false, err
} }
} }
if err := createMizuConfigmap(ctx, kubernetesProvider, serializedValidationRules, serializedContract, serializedMizuConfig, mizuResourcesNamespace); err != nil { if err := createMizuConfigmap(ctx, kubernetesProvider, serializedMizuConfig, mizuResourcesNamespace); err != nil {
return false, err return false, err
} }
@@ -71,8 +71,8 @@ func createMizuNamespace(ctx context.Context, kubernetesProvider *kubernetes.Pro
return err return err
} }
func createMizuConfigmap(ctx context.Context, kubernetesProvider *kubernetes.Provider, serializedValidationRules string, serializedContract string, serializedMizuConfig string, mizuResourcesNamespace string) error { func createMizuConfigmap(ctx context.Context, kubernetesProvider *kubernetes.Provider, serializedMizuConfig string, mizuResourcesNamespace string) error {
err := kubernetesProvider.CreateConfigMap(ctx, mizuResourcesNamespace, kubernetes.ConfigMapName, serializedValidationRules, serializedContract, serializedMizuConfig) err := kubernetesProvider.CreateConfigMap(ctx, mizuResourcesNamespace, kubernetes.ConfigMapName, serializedMizuConfig)
return err return err
} }

View File

@@ -1,101 +0,0 @@
package telemetry
import (
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
"time"
"github.com/denisbrodbeck/machineid"
"github.com/up9inc/mizu/cli/apiserver"
"github.com/up9inc/mizu/cli/config"
"github.com/up9inc/mizu/cli/mizu"
"github.com/up9inc/mizu/logger"
)
const telemetryUrl = "https://us-east4-up9-prod.cloudfunctions.net/mizu-telemetry"
func ReportRun(cmd string, args interface{}) {
if !shouldRunTelemetry() {
logger.Log.Debug("not reporting telemetry")
return
}
argsBytes, _ := json.Marshal(args)
argsMap := map[string]interface{}{
"cmd": cmd,
"args": string(argsBytes),
}
if err := sendTelemetry(argsMap); err != nil {
logger.Log.Debug(err)
return
}
logger.Log.Debugf("successfully reported telemetry for cmd %v", cmd)
}
func ReportTapTelemetry(apiProvider *apiserver.Provider, args interface{}, startTime time.Time) {
if !shouldRunTelemetry() {
logger.Log.Debug("not reporting telemetry")
return
}
generalStats, err := apiProvider.GetGeneralStats()
if err != nil {
logger.Log.Debugf("[ERROR] failed to get general stats from api server %v", err)
return
}
argsBytes, _ := json.Marshal(args)
argsMap := map[string]interface{}{
"cmd": "tap",
"args": string(argsBytes),
"executionTimeInSeconds": int(time.Since(startTime).Seconds()),
"apiCallsCount": generalStats["EntriesCount"],
"trafficVolumeInGB": generalStats["EntriesVolumeInGB"],
}
if err := sendTelemetry(argsMap); err != nil {
logger.Log.Debug(err)
return
}
logger.Log.Debug("successfully reported telemetry of tap command")
}
func shouldRunTelemetry() bool {
if _, present := os.LookupEnv(mizu.DEVENVVAR); present {
return false
}
if !config.Config.Telemetry {
return false
}
if mizu.Branch != "main" && mizu.Branch != "develop" {
return false
}
return true
}
func sendTelemetry(argsMap map[string]interface{}) error {
argsMap["component"] = "mizu_cli"
argsMap["buildTimestamp"] = mizu.BuildTimestamp
argsMap["branch"] = mizu.Branch
argsMap["version"] = mizu.Ver
argsMap["platform"] = mizu.Platform
if machineId, err := machineid.ProtectedID("mizu"); err == nil {
argsMap["machineId"] = machineId
}
jsonValue, _ := json.Marshal(argsMap)
if resp, err := http.Post(telemetryUrl, "application/json", bytes.NewBuffer(jsonValue)); err != nil {
return fmt.Errorf("ERROR: failed sending telemetry, err: %v, response %v", err, resp)
}
return nil
}

View File

@@ -5,8 +5,8 @@ if (( $EUID != 0 )); then
SUDO='sudo' SUDO='sudo'
fi fi
curl https://github.com/capstone-engine/capstone/archive/4.0.2.tar.gz -Lo ./capstone.tar.gz \ curl https://github.com/capstone-engine/capstone/releases/download/5.0-rc2/capstone-5.0-rc2.tar.xz -Lo ./capstone.tar.xz \
&& tar -xzf capstone.tar.gz && mv ./capstone-* ./capstone \ && tar -xf capstone.tar.xz && mv ./capstone-* ./capstone \
&& cd capstone \ && cd capstone \
&& CAPSTONE_ARCHS="aarch64 x86" ./make.sh \ && CAPSTONE_ARCHS="aarch64 x86" ./make.sh \
&& $SUDO ./make.sh install && $SUDO ./make.sh install

View File

@@ -20,8 +20,8 @@ RUN ./configure --host=arm && make \
WORKDIR /work WORKDIR /work
# Build and install Capstone from source # Build and install Capstone from source
RUN curl https://github.com/capstone-engine/capstone/archive/4.0.2.tar.gz -Lo ./capstone.tar.gz \ RUN curl https://github.com/capstone-engine/capstone/releases/download/5.0-rc2/capstone-5.0-rc2.tar.xz -Lo ./capstone.tar.xz \
&& tar -xzf capstone.tar.gz && mv ./capstone-* ./capstone && tar -xf capstone.tar.xz && mv ./capstone-* ./capstone
WORKDIR /work/capstone WORKDIR /work/capstone
RUN CAPSTONE_ARCHS="aarch64" CAPSTONE_STATIC=yes ./make.sh \ RUN CAPSTONE_ARCHS="aarch64" CAPSTONE_STATIC=yes ./make.sh \
&& cp /work/capstone/libcapstone.a /usr/xcc/aarch64-linux-musl-cross/lib/gcc/aarch64-linux-musl/*/ && cp /work/capstone/libcapstone.a /usr/xcc/aarch64-linux-musl-cross/lib/gcc/aarch64-linux-musl/*/

View File

@@ -1,4 +1,5 @@
#!/bin/bash #!/bin/bash
set -e set -e
docker build . -t up9inc/linux-arm64-musl-go-libpcap-capstone-bpf && docker push up9inc/linux-arm64-musl-go-libpcap-capstone-bpf # Build it on x86_64
docker build . -t up9inc/linux-arm64-musl-go-libpcap-capstone-bpf:capstone-5.0-rc2 && docker push up9inc/linux-arm64-musl-go-libpcap-capstone-bpf:capstone-5.0-rc2

View File

@@ -44,8 +44,8 @@ RUN ./configure --host=x86_64 && make \
WORKDIR / WORKDIR /
# Build and install Capstone from source # Build and install Capstone from source
RUN curl https://github.com/capstone-engine/capstone/archive/4.0.2.tar.gz -Lo ./capstone.tar.gz \ RUN curl https://github.com/capstone-engine/capstone/releases/download/5.0-rc2/capstone-5.0-rc2.tar.xz -Lo ./capstone.tar.xz \
&& tar -xzf capstone.tar.gz && mv ./capstone-* ./capstone && tar -xf capstone.tar.xz && mv ./capstone-* ./capstone
WORKDIR /capstone WORKDIR /capstone
RUN CAPSTONE_ARCHS="x86" CAPSTONE_STATIC=yes ./make.sh \ RUN CAPSTONE_ARCHS="x86" CAPSTONE_STATIC=yes ./make.sh \
&& cp /capstone/libcapstone.a /usr/local/musl/lib/gcc/x86_64-unknown-linux-musl/*/ && cp /capstone/libcapstone.a /usr/local/musl/lib/gcc/x86_64-unknown-linux-musl/*/

View File

@@ -1,4 +1,5 @@
#!/bin/bash #!/bin/bash
set -e set -e
docker build . -t up9inc/linux-x86_64-musl-go-libpcap-capstone-bpf && docker push up9inc/linux-x86_64-musl-go-libpcap-capstone-bpf # Build it on arm64
docker build . -t up9inc/linux-x86_64-musl-go-libpcap-capstone-bpf:capstone-5.0-rc2 && docker push up9inc/linux-x86_64-musl-go-libpcap-capstone-bpf:capstone-5.0-rc2

View File

@@ -57,7 +57,7 @@ log "Writing output to $MIZU_BENCHMARK_OUTPUT_DIR"
cd $MIZU_HOME || exit 1 cd $MIZU_HOME || exit 1
export HOST_MODE=0 export HOST_MODE=0
export SENSITIVE_DATA_FILTERING_OPTIONS='{"EnableRedaction": false}' export SENSITIVE_DATA_FILTERING_OPTIONS='{}'
export MIZU_DEBUG_DISABLE_PCAP=false export MIZU_DEBUG_DISABLE_PCAP=false
export MIZU_DEBUG_DISABLE_TCP_REASSEMBLY=false export MIZU_DEBUG_DISABLE_TCP_REASSEMBLY=false
export MIZU_DEBUG_DISABLE_TCP_STREAM=false export MIZU_DEBUG_DISABLE_TCP_STREAM=false

View File

@@ -6,8 +6,6 @@ const (
NodeNameEnvVar = "NODE_NAME" NodeNameEnvVar = "NODE_NAME"
ConfigDirPath = "/app/config/" ConfigDirPath = "/app/config/"
DataDirPath = "/app/data/" DataDirPath = "/app/data/"
ValidationRulesFileName = "validation-rules.yaml"
ContractFileName = "contract-oas.yaml"
ConfigFileName = "mizu-config.json" ConfigFileName = "mizu-config.json"
DefaultApiServerPort = 8899 DefaultApiServerPort = 8899
LogLevelEnvVar = "LOG_LEVEL" LogLevelEnvVar = "LOG_LEVEL"

View File

@@ -4,11 +4,9 @@ go 1.17
require ( require (
github.com/docker/go-units v0.4.0 github.com/docker/go-units v0.4.0
github.com/golang-jwt/jwt/v4 v4.2.0
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
github.com/up9inc/mizu/logger v0.0.0 github.com/up9inc/mizu/logger v0.0.0
github.com/up9inc/mizu/tap/api v0.0.0 github.com/up9inc/mizu/tap/api v0.0.0
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
k8s.io/api v0.23.3 k8s.io/api v0.23.3
k8s.io/apimachinery v0.23.3 k8s.io/apimachinery v0.23.3
k8s.io/client-go v0.23.3 k8s.io/client-go v0.23.3
@@ -38,11 +36,11 @@ require (
github.com/go-openapi/jsonreference v0.19.6 // indirect github.com/go-openapi/jsonreference v0.19.6 // indirect
github.com/go-openapi/swag v0.21.1 // indirect github.com/go-openapi/swag v0.21.1 // indirect
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/protobuf v1.5.2 // indirect github.com/golang/protobuf v1.5.2 // indirect
github.com/google/btree v1.0.1 // 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/martian v2.1.0+incompatible // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/google/uuid v1.3.0 // indirect github.com/google/uuid v1.3.0 // indirect
github.com/googleapis/gnostic v0.5.5 // indirect github.com/googleapis/gnostic v0.5.5 // indirect
@@ -81,6 +79,7 @@ require (
google.golang.org/protobuf v1.27.1 // indirect google.golang.org/protobuf v1.27.1 // indirect
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
k8s.io/cli-runtime v0.23.3 // indirect k8s.io/cli-runtime v0.23.3 // indirect
k8s.io/component-base 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

View File

@@ -282,7 +282,6 @@ github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=

View File

@@ -43,11 +43,11 @@ type TapperSyncerConfig struct {
TapperResources shared.Resources TapperResources shared.Resources
ImagePullPolicy core.PullPolicy ImagePullPolicy core.PullPolicy
LogLevel logging.Level LogLevel logging.Level
IgnoredUserAgents []string
MizuApiFilteringOptions api.TrafficFilteringOptions MizuApiFilteringOptions api.TrafficFilteringOptions
MizuServiceAccountExists bool MizuServiceAccountExists bool
ServiceMesh bool ServiceMesh bool
Tls bool Tls bool
MaxLiveStreams int
} }
func CreateAndStartMizuTapperSyncer(ctx context.Context, kubernetesProvider *Provider, config TapperSyncerConfig, startTime time.Time) (*MizuTapperSyncer, error) { func CreateAndStartMizuTapperSyncer(ctx context.Context, kubernetesProvider *Provider, config TapperSyncerConfig, startTime time.Time) (*MizuTapperSyncer, error) {
@@ -337,7 +337,8 @@ func (tapperSyncer *MizuTapperSyncer) updateMizuTappers() error {
tapperSyncer.config.MizuApiFilteringOptions, tapperSyncer.config.MizuApiFilteringOptions,
tapperSyncer.config.LogLevel, tapperSyncer.config.LogLevel,
tapperSyncer.config.ServiceMesh, tapperSyncer.config.ServiceMesh,
tapperSyncer.config.Tls); err != nil { tapperSyncer.config.Tls,
tapperSyncer.config.MaxLiveStreams); err != nil {
return err return err
} }

View File

@@ -10,6 +10,7 @@ import (
"net/url" "net/url"
"path/filepath" "path/filepath"
"regexp" "regexp"
"strconv"
"github.com/op/go-logging" "github.com/op/go-logging"
"github.com/up9inc/mizu/logger" "github.com/up9inc/mizu/logger"
@@ -382,11 +383,11 @@ func (provider *Provider) GetMizuApiServerPodObject(opts *ApiServerOptions, moun
Tolerations: []core.Toleration{ Tolerations: []core.Toleration{
{ {
Operator: core.TolerationOpExists, Operator: core.TolerationOpExists,
Effect: core.TaintEffectNoExecute, Effect: core.TaintEffectNoExecute,
}, },
{ {
Operator: core.TolerationOpExists, Operator: core.TolerationOpExists,
Effect: core.TaintEffectNoSchedule, Effect: core.TaintEffectNoSchedule,
}, },
}, },
}, },
@@ -684,14 +685,8 @@ func (provider *Provider) handleRemovalError(err error) error {
return err return err
} }
func (provider *Provider) CreateConfigMap(ctx context.Context, namespace string, configMapName string, serializedValidationRules string, serializedContract string, serializedMizuConfig string) error { func (provider *Provider) CreateConfigMap(ctx context.Context, namespace string, configMapName string, serializedMizuConfig string) error {
configMapData := make(map[string]string) configMapData := make(map[string]string)
if serializedValidationRules != "" {
configMapData[shared.ValidationRulesFileName] = serializedValidationRules
}
if serializedContract != "" {
configMapData[shared.ContractFileName] = serializedContract
}
configMapData[shared.ConfigFileName] = serializedMizuConfig configMapData[shared.ConfigFileName] = serializedMizuConfig
configMap := &core.ConfigMap{ configMap := &core.ConfigMap{
@@ -714,7 +709,7 @@ 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, nodeNames []string, 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, maxLiveStreams int) error {
logger.Log.Debugf("Applying %d tapper daemon sets, ns: %s, daemonSetName: %s, podImage: %s, tapperPodName: %s", len(nodeNames), 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(nodeNames) == 0 { if len(nodeNames) == 0 {
@@ -732,6 +727,7 @@ func (provider *Provider) ApplyMizuTapperDaemonSet(ctx context.Context, namespac
"--tap", "--tap",
"--api-server-address", fmt.Sprintf("ws://%s/wsTapper", apiServerPodIp), "--api-server-address", fmt.Sprintf("ws://%s/wsTapper", apiServerPodIp),
"--nodefrag", "--nodefrag",
"--max-live-streams", strconv.Itoa(maxLiveStreams),
} }
if serviceMesh { if serviceMesh {

View File

@@ -11,11 +11,11 @@ import (
) )
const ( const (
EventAdded watch.EventType = watch.Added EventAdded = watch.Added
EventModified watch.EventType = watch.Modified EventModified = watch.Modified
EventDeleted watch.EventType = watch.Deleted EventDeleted = watch.Deleted
EventBookmark watch.EventType = watch.Bookmark EventBookmark = watch.Bookmark
EventError watch.EventType = watch.Error EventError = watch.Error
) )
type InvalidObjectType struct { type InvalidObjectType struct {

View File

@@ -1,13 +1,8 @@
package shared package shared
import ( import (
"io/ioutil"
"strings"
"github.com/op/go-logging" "github.com/op/go-logging"
"github.com/up9inc/mizu/logger"
"gopkg.in/yaml.v3"
v1 "k8s.io/api/core/v1" v1 "k8s.io/api/core/v1"
) )
@@ -48,14 +43,12 @@ type MizuAgentConfig struct {
AgentDatabasePath string `json:"agentDatabasePath"` AgentDatabasePath string `json:"agentDatabasePath"`
ServiceMap bool `json:"serviceMap"` ServiceMap bool `json:"serviceMap"`
OAS OASConfig `json:"oas"` OAS OASConfig `json:"oas"`
Telemetry bool `json:"telemetry"`
} }
type WebSocketMessageMetadata struct { type WebSocketMessageMetadata struct {
MessageType WebSocketMessageType `json:"messageType,omitempty"` MessageType WebSocketMessageType `json:"messageType,omitempty"`
} }
type WebSocketStatusMessage struct { type WebSocketStatusMessage struct {
*WebSocketMessageMetadata *WebSocketMessageMetadata
TappingStatus []TappedPodStatus `json:"tappingStatus"` TappingStatus []TappedPodStatus `json:"tappingStatus"`
@@ -136,83 +129,3 @@ type HealthResponse struct {
type VersionResponse struct { type VersionResponse struct {
Ver string `json:"ver"` Ver string `json:"ver"`
} }
type RulesPolicy struct {
Rules []RulePolicy `yaml:"rules"`
}
type RulePolicy struct {
Type string `yaml:"type"`
Service string `yaml:"service"`
Path string `yaml:"path"`
Method string `yaml:"method"`
Key string `yaml:"key"`
Value string `yaml:"value"`
ResponseTime int64 `yaml:"response-time"`
Name string `yaml:"name"`
}
type RulesMatched struct {
Matched bool `json:"matched"`
Rule RulePolicy `json:"rule"`
}
func (r *RulePolicy) validateType() bool {
permitedTypes := []string{"json", "header", "slo"}
_, found := Find(permitedTypes, r.Type)
if !found {
logger.Log.Errorf("Only json, header and slo types are supported on rule definition. This rule will be ignored. rule name: %s", r.Name)
found = false
}
if strings.ToLower(r.Type) == "slo" {
if r.ResponseTime <= 0 {
logger.Log.Errorf("When rule type is slo, the field response-time should be specified and have a value >= 1. rule name: %s", r.Name)
found = false
}
}
return found
}
func (rules *RulesPolicy) ValidateRulesPolicy() []int {
invalidIndex := make([]int, 0)
for i := range rules.Rules {
validated := rules.Rules[i].validateType()
if !validated {
invalidIndex = append(invalidIndex, i)
}
}
return invalidIndex
}
func Find(slice []string, val string) (int, bool) {
for i, item := range slice {
if item == val {
return i, true
}
}
return -1, false
}
func DecodeEnforcePolicy(path string) (RulesPolicy, error) {
content, err := ioutil.ReadFile(path)
enforcePolicy := RulesPolicy{}
if err != nil {
return enforcePolicy, err
}
err = yaml.Unmarshal([]byte(content), &enforcePolicy)
if err != nil {
return enforcePolicy, err
}
invalidIndex := enforcePolicy.ValidateRulesPolicy()
var k = 0
if len(invalidIndex) != 0 {
for i, rule := range enforcePolicy.Rules {
if !ContainsInt(invalidIndex, i) {
enforcePolicy.Rules[k] = rule
k++
}
}
enforcePolicy.Rules = enforcePolicy.Rules[:k]
}
return enforcePolicy, nil
}

View File

@@ -10,15 +10,6 @@ func Contains(slice []string, containsValue string) bool {
return false return false
} }
func ContainsInt(slice []int, containsValue int) bool {
for _, sliceValue := range slice {
if sliceValue == containsValue {
return true
}
}
return false
}
func Unique(slice []string) []string { func Unique(slice []string) []string {
keys := make(map[string]bool) keys := make(map[string]bool)
var list []string var list []string

View File

@@ -2,35 +2,43 @@ package api
import ( import (
"bufio" "bufio"
"bytes"
"encoding/json"
"errors"
"fmt" "fmt"
"io/ioutil"
"net" "net"
"net/http" "strings"
"os"
"sort"
"sync" "sync"
"time" "time"
"github.com/google/martian/har"
"github.com/up9inc/mizu/tap/dbgctl" "github.com/up9inc/mizu/tap/dbgctl"
) )
const mizuTestEnvVar = "MIZU_TEST" const UnknownNamespace = ""
const UNKNOWN_NAMESPACE = ""
var UnknownIp net.IP = net.IP{0, 0, 0, 0} var UnknownIp = net.IP{0, 0, 0, 0}
var UnknownPort uint16 = 0 var UnknownPort uint16 = 0
type ProtocolSummary struct {
Name string `json:"name"`
Version string `json:"version"`
Abbreviation string `json:"abbr"`
}
func (protocol *ProtocolSummary) ToString() string {
return fmt.Sprintf("%s?%s?%s", protocol.Name, protocol.Version, protocol.Abbreviation)
}
func GetProtocolSummary(inputString string) *ProtocolSummary {
splitted := strings.SplitN(inputString, "?", 3)
return &ProtocolSummary{
Name: splitted[0],
Version: splitted[1],
Abbreviation: splitted[2],
}
}
type Protocol struct { type Protocol struct {
Name string `json:"name"` ProtocolSummary
LongName string `json:"longName"` LongName string `json:"longName"`
Abbreviation string `json:"abbr"`
Macro string `json:"macro"` Macro string `json:"macro"`
Version string `json:"version"`
BackgroundColor string `json:"backgroundColor"` BackgroundColor string `json:"backgroundColor"`
ForegroundColor string `json:"foregroundColor"` ForegroundColor string `json:"foregroundColor"`
FontSize int8 `json:"fontSize"` FontSize int8 `json:"fontSize"`
@@ -102,7 +110,6 @@ type OutputChannelItem struct {
Timestamp int64 Timestamp int64
ConnectionInfo *ConnectionInfo ConnectionInfo *ConnectionInfo
Pair *RequestResponsePair Pair *RequestResponsePair
Summary *BaseEntry
Namespace string Namespace string
} }
@@ -127,6 +134,7 @@ func (p *ReadProgress) Reset() {
type Dissector interface { type Dissector interface {
Register(*Extension) Register(*Extension)
GetProtocols() map[string]*Protocol
Ping() Ping()
Dissect(b *bufio.Reader, reader TcpReader, options *TrafficFilteringOptions) error Dissect(b *bufio.Reader, reader TcpReader, options *TrafficFilteringOptions) error
Analyze(item *OutputChannelItem, resolvedSource string, resolvedDestination string, namespace string) *Entry Analyze(item *OutputChannelItem, resolvedSource string, resolvedDestination string, namespace string) *Entry
@@ -161,69 +169,44 @@ func (e *Emitting) Emit(item *OutputChannelItem) {
} }
type Entry struct { type Entry struct {
Id string `json:"id"` Id string `json:"id"`
Protocol Protocol `json:"proto"` Protocol ProtocolSummary `json:"protocol"`
Capture Capture `json:"capture"` Capture Capture `json:"capture"`
Source *TCP `json:"src"` Source *TCP `json:"src"`
Destination *TCP `json:"dst"` Destination *TCP `json:"dst"`
Namespace string `json:"namespace"` Namespace string `json:"namespace"`
Outgoing bool `json:"outgoing"` Outgoing bool `json:"outgoing"`
Timestamp int64 `json:"timestamp"` Timestamp int64 `json:"timestamp"`
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"` RequestSize int `json:"requestSize"`
ResponseSize int `json:"responseSize"` ResponseSize int `json:"responseSize"`
ElapsedTime int64 `json:"elapsedTime"` ElapsedTime int64 `json:"elapsedTime"`
Rules ApplicableRules `json:"rules,omitempty"`
ContractStatus ContractStatus `json:"contractStatus,omitempty"`
ContractRequestReason string `json:"contractRequestReason,omitempty"`
ContractResponseReason string `json:"contractResponseReason,omitempty"`
ContractContent string `json:"contractContent,omitempty"`
HTTPPair string `json:"httpPair,omitempty"`
} }
type EntryWrapper struct { type EntryWrapper struct {
Protocol Protocol `json:"protocol"` Protocol Protocol `json:"protocol"`
Representation string `json:"representation"` Representation string `json:"representation"`
Data *Entry `json:"data"` Data *Entry `json:"data"`
Base *BaseEntry `json:"base"` Base *BaseEntry `json:"base"`
Rules []map[string]interface{} `json:"rulesMatched,omitempty"`
IsRulesEnabled bool `json:"isRulesEnabled"`
} }
type BaseEntry struct { type BaseEntry struct {
Id string `json:"id"` Id string `json:"id"`
Protocol Protocol `json:"proto,omitempty"` Protocol Protocol `json:"proto,omitempty"`
Capture Capture `json:"capture"` 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"`
StatusQuery string `json:"statusQuery"` StatusQuery string `json:"statusQuery"`
Method string `json:"method,omitempty"` Method string `json:"method,omitempty"`
MethodQuery string `json:"methodQuery,omitempty"` MethodQuery string `json:"methodQuery,omitempty"`
Timestamp int64 `json:"timestamp,omitempty"` Timestamp int64 `json:"timestamp,omitempty"`
Source *TCP `json:"src"` Source *TCP `json:"src"`
Destination *TCP `json:"dst"` Destination *TCP `json:"dst"`
IsOutgoing bool `json:"isOutgoing,omitempty"` IsOutgoing bool `json:"isOutgoing,omitempty"`
Latency int64 `json:"latency"` Latency int64 `json:"latency"`
Rules ApplicableRules `json:"rules,omitempty"`
ContractStatus ContractStatus `json:"contractStatus"`
}
type ApplicableRules struct {
Latency int64 `json:"latency,omitempty"`
Status bool `json:"status,omitempty"`
NumberOfRules int `json:"numberOfRules,omitempty"`
}
type ContractStatus int
type Contract struct {
Status ContractStatus `json:"status"`
RequestReason string `json:"requestReason"`
ResponseReason string `json:"responseReason"`
Content string `json:"content"`
} }
const ( const (
@@ -246,170 +229,6 @@ type TableData struct {
Selector string `json:"selector"` Selector string `json:"selector"`
} }
const (
TypeHttpRequest = iota
TypeHttpResponse
)
type HTTPPayload struct {
Type uint8
Data interface{}
}
type HTTPPayloader interface {
MarshalJSON() ([]byte, error)
}
type HTTPWrapper struct {
Method string `json:"method"`
Url string `json:"url"`
Details interface{} `json:"details"`
RawRequest *HTTPRequestWrapper `json:"rawRequest"`
RawResponse *HTTPResponseWrapper `json:"rawResponse"`
}
func (h HTTPPayload) MarshalJSON() ([]byte, error) {
_, testEnvEnabled := os.LookupEnv(mizuTestEnvVar)
switch h.Type {
case TypeHttpRequest:
harRequest, err := har.NewRequest(h.Data.(*http.Request), true)
if err != nil {
return nil, errors.New("Failed converting request to HAR")
}
sort.Slice(harRequest.Headers, func(i, j int) bool {
if harRequest.Headers[i].Name < harRequest.Headers[j].Name {
return true
}
if harRequest.Headers[i].Name > harRequest.Headers[j].Name {
return false
}
return harRequest.Headers[i].Value < harRequest.Headers[j].Value
})
sort.Slice(harRequest.QueryString, func(i, j int) bool {
if harRequest.QueryString[i].Name < harRequest.QueryString[j].Name {
return true
}
if harRequest.QueryString[i].Name > harRequest.QueryString[j].Name {
return false
}
return harRequest.QueryString[i].Value < harRequest.QueryString[j].Value
})
if harRequest.PostData != nil {
sort.Slice(harRequest.PostData.Params, func(i, j int) bool {
if harRequest.PostData.Params[i].Name < harRequest.PostData.Params[j].Name {
return true
}
if harRequest.PostData.Params[i].Name > harRequest.PostData.Params[j].Name {
return false
}
return harRequest.PostData.Params[i].Value < harRequest.PostData.Params[j].Value
})
}
if testEnvEnabled {
harRequest.URL = ""
}
var reqWrapper *HTTPRequestWrapper
if !testEnvEnabled {
reqWrapper = &HTTPRequestWrapper{Request: h.Data.(*http.Request)}
}
return json.Marshal(&HTTPWrapper{
Method: harRequest.Method,
Details: harRequest,
RawRequest: reqWrapper,
})
case TypeHttpResponse:
harResponse, err := har.NewResponse(h.Data.(*http.Response), true)
if err != nil {
return nil, errors.New("Failed converting response to HAR")
}
sort.Slice(harResponse.Headers, func(i, j int) bool {
if harResponse.Headers[i].Name < harResponse.Headers[j].Name {
return true
}
if harResponse.Headers[i].Name > harResponse.Headers[j].Name {
return false
}
return harResponse.Headers[i].Value < harResponse.Headers[j].Value
})
sort.Slice(harResponse.Cookies, func(i, j int) bool {
if harResponse.Cookies[i].Name < harResponse.Cookies[j].Name {
return true
}
if harResponse.Cookies[i].Name > harResponse.Cookies[j].Name {
return false
}
return harResponse.Cookies[i].Value < harResponse.Cookies[j].Value
})
var resWrapper *HTTPResponseWrapper
if !testEnvEnabled {
resWrapper = &HTTPResponseWrapper{Response: h.Data.(*http.Response)}
}
return json.Marshal(&HTTPWrapper{
Method: "",
Url: "",
Details: harResponse,
RawResponse: resWrapper,
})
default:
panic(fmt.Sprintf("HTTP payload cannot be marshaled: %v", h.Type))
}
}
type HTTPWrapperTricky struct {
Method string `json:"method"`
Url string `json:"url"`
Details interface{} `json:"details"`
RawRequest *http.Request `json:"rawRequest"`
RawResponse *http.Response `json:"rawResponse"`
}
type HTTPMessage struct {
IsRequest bool `json:"isRequest"`
CaptureTime time.Time `json:"captureTime"`
Payload HTTPWrapperTricky `json:"payload"`
}
type HTTPRequestResponsePair struct {
Request HTTPMessage `json:"request"`
Response HTTPMessage `json:"response"`
}
type HTTPRequestWrapper struct {
*http.Request
}
func (r *HTTPRequestWrapper) MarshalJSON() ([]byte, error) {
body, _ := ioutil.ReadAll(r.Request.Body)
r.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body))
return json.Marshal(&struct { //nolint
Body string `json:"Body,omitempty"`
GetBody string `json:"GetBody,omitempty"`
Cancel string `json:"Cancel,omitempty"`
*http.Request
}{
Body: string(body),
Request: r.Request,
})
}
type HTTPResponseWrapper struct {
*http.Response
}
func (r *HTTPResponseWrapper) MarshalJSON() ([]byte, error) {
body, _ := ioutil.ReadAll(r.Response.Body)
r.Response.Body = ioutil.NopCloser(bytes.NewBuffer(body))
return json.Marshal(&struct { //nolint
Body string `json:"Body,omitempty"`
GetBody string `json:"GetBody,omitempty"`
Cancel string `json:"Cancel,omitempty"`
*http.Response
}{
Body: string(body),
Response: r.Response,
})
}
type TcpReaderDataMsg interface { type TcpReaderDataMsg interface {
GetBytes() []byte GetBytes() []byte
GetTimestamp() time.Time GetTimestamp() time.Time

View File

@@ -2,9 +2,6 @@ module github.com/up9inc/mizu/tap/api
go 1.17 go 1.17
require ( require github.com/up9inc/mizu/tap/dbgctl v0.0.0
github.com/google/martian v2.1.0+incompatible
github.com/up9inc/mizu/tap/dbgctl v0.0.0
)
replace github.com/up9inc/mizu/tap/dbgctl v0.0.0 => ../dbgctl replace github.com/up9inc/mizu/tap/dbgctl v0.0.0 => ../dbgctl

View File

@@ -1,2 +0,0 @@
github.com/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=

View File

@@ -1,7 +1,5 @@
package api package api
type TrafficFilteringOptions struct { type TrafficFilteringOptions struct {
IgnoredUserAgents []string IgnoredUserAgents []string
PlainTextMaskingRegexes []*SerializableRegexp
EnableRedaction bool
} }

View File

@@ -5,11 +5,11 @@ import (
) )
var ( var (
MizuTapperDisablePcap bool = os.Getenv("MIZU_DEBUG_DISABLE_PCAP") == "true" MizuTapperDisablePcap = os.Getenv("MIZU_DEBUG_DISABLE_PCAP") == "true"
MizuTapperDisableTcpReassembly bool = os.Getenv("MIZU_DEBUG_DISABLE_TCP_REASSEMBLY") == "true" MizuTapperDisableTcpReassembly = os.Getenv("MIZU_DEBUG_DISABLE_TCP_REASSEMBLY") == "true"
MizuTapperDisableTcpStream bool = os.Getenv("MIZU_DEBUG_DISABLE_TCP_STREAM") == "true" MizuTapperDisableTcpStream = os.Getenv("MIZU_DEBUG_DISABLE_TCP_STREAM") == "true"
MizuTapperDisableDissectors bool = os.Getenv("MIZU_DEBUG_DISABLE_DISSECTORS") == "true" MizuTapperDisableDissectors = os.Getenv("MIZU_DEBUG_DISABLE_DISSECTORS") == "true"
MizuTapperDisableEmitting bool = os.Getenv("MIZU_DEBUG_DISABLE_EMITTING") == "true" MizuTapperDisableEmitting = os.Getenv("MIZU_DEBUG_DISABLE_EMITTING") == "true"
MizuTapperDisableSending bool = os.Getenv("MIZU_DEBUG_DISABLE_SENDING") == "true" MizuTapperDisableSending = os.Getenv("MIZU_DEBUG_DISABLE_SENDING") == "true"
MizuTapperDisableNonHttpExtensions bool = os.Getenv("MIZU_DEBUG_DISABLE_NON_HTTP_EXTENSSION") == "true" MizuTapperDisableNonHttpExtensions = os.Getenv("MIZU_DEBUG_DISABLE_NON_HTTP_EXTENSSION") == "true"
) )

View File

@@ -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/expect8/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/expect16/amqp/\* expect

View File

@@ -4,17 +4,20 @@ go 1.17
require ( require (
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0
github.com/up9inc/mizu/logger v0.0.0
github.com/up9inc/mizu/tap/api v0.0.0 github.com/up9inc/mizu/tap/api v0.0.0
) )
require ( require (
github.com/davecgh/go-spew v1.1.0 // indirect github.com/davecgh/go-spew v1.1.0 // indirect
github.com/google/martian v2.1.0+incompatible // indirect github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/up9inc/mizu/tap/dbgctl v0.0.0 // indirect github.com/up9inc/mizu/tap/dbgctl v0.0.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect
) )
replace github.com/up9inc/mizu/logger v0.0.0 => ../../../logger
replace github.com/up9inc/mizu/tap/api v0.0.0 => ../../api replace github.com/up9inc/mizu/tap/api v0.0.0 => ../../api
replace github.com/up9inc/mizu/tap/dbgctl v0.0.0 => ../../dbgctl replace github.com/up9inc/mizu/tap/dbgctl v0.0.0 => ../../dbgctl

View File

@@ -1,7 +1,7 @@
github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8=
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/google/martian v2.1.0+incompatible h1:/CP5g8u/VJHijgedC/Legn3BAbAaWPgecwXBIDzw5no= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
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=

View File

@@ -5,8 +5,8 @@ import (
"fmt" "fmt"
"sort" "sort"
"strconv" "strconv"
"time"
"github.com/up9inc/mizu/logger"
"github.com/up9inc/mizu/tap/api" "github.com/up9inc/mizu/tap/api"
) )
@@ -25,14 +25,14 @@ var connectionMethodMap = map[int]string{
61: "connection unblocked", 61: "connection unblocked",
} }
// var channelMethodMap = map[int]string{ var channelMethodMap = map[int]string{
// 10: "channel open", 10: "channel open",
// 11: "channel open-ok", 11: "channel open-ok",
// 20: "channel flow", 20: "channel flow",
// 21: "channel flow-ok", 21: "channel flow-ok",
// 40: "channel close", 40: "channel close",
// 41: "channel close-ok", 41: "channel close-ok",
// } }
var exchangeMethodMap = map[int]string{ var exchangeMethodMap = map[int]string{
10: "exchange declare", 10: "exchange declare",
@@ -94,29 +94,41 @@ 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, captureSize int, emitter api.Emitter, capture api.Capture) { type emptyResponse struct {
request := &api.GenericMessage{ }
IsRequest: true,
CaptureTime: captureTime, const emptyMethod = "empty"
Payload: AMQPPayload{
Data: &AMQPWrapper{ func getIdent(reader api.TcpReader, methodFrame *MethodFrame) (ident string) {
Method: method, tcpID := reader.GetTcpID()
Url: "", // To match methods to their Ok(s)
Details: event, methodId := methodFrame.MethodId - methodFrame.MethodId%10
},
}, if reader.GetIsClient() {
ident = fmt.Sprintf(
"%s_%s_%s_%s_%d_%d_%d",
tcpID.SrcIP,
tcpID.DstIP,
tcpID.SrcPort,
tcpID.DstPort,
methodFrame.ChannelId,
methodFrame.ClassId,
methodId,
)
} else {
ident = fmt.Sprintf(
"%s_%s_%s_%s_%d_%d_%d",
tcpID.DstIP,
tcpID.SrcIP,
tcpID.DstPort,
tcpID.SrcPort,
methodFrame.ChannelId,
methodFrame.ClassId,
methodId,
)
} }
item := &api.OutputChannelItem{
Protocol: protocol, return
Capture: capture,
Timestamp: captureTime.UnixNano() / int64(time.Millisecond),
ConnectionInfo: connectionInfo,
Pair: &api.RequestResponsePair{
Request: *request,
Response: api.GenericMessage{},
},
}
emitter.Emit(item)
} }
func representProperties(properties map[string]interface{}, rep []interface{}) ([]interface{}, string, string) { func representProperties(properties map[string]interface{}, rep []interface{}) ([]interface{}, string, string) {
@@ -460,6 +472,36 @@ func representQueueDeclare(event map[string]interface{}) []interface{} {
return rep return rep
} }
func representQueueDeclareOk(event map[string]interface{}) []interface{} {
rep := make([]interface{}, 0)
details, _ := json.Marshal([]api.TableData{
{
Name: "Queue",
Value: event["queue"].(string),
Selector: `response.queue`,
},
{
Name: "Message Count",
Value: fmt.Sprintf("%g", event["messageCount"].(float64)),
Selector: `response.messageCount`,
},
{
Name: "Consumer Count",
Value: fmt.Sprintf("%g", event["consumerCount"].(float64)),
Selector: `response.consumerCount`,
},
})
rep = append(rep, api.SectionData{
Type: api.TABLE,
Title: "Details",
Data: string(details),
})
return rep
}
func representExchangeDeclare(event map[string]interface{}) []interface{} { func representExchangeDeclare(event map[string]interface{}) []interface{} {
rep := make([]interface{}, 0) rep := make([]interface{}, 0)
@@ -571,7 +613,7 @@ func representConnectionStart(event map[string]interface{}) []interface{} {
x, _ := json.Marshal(value) x, _ := json.Marshal(value)
outcome = string(x) outcome = string(x)
default: default:
panic("Unknown data type for the server property!") logger.Log.Info("Unknown data type for the server property!")
} }
headers = append(headers, api.TableData{ headers = append(headers, api.TableData{
Name: name, Name: name,
@@ -593,6 +635,65 @@ func representConnectionStart(event map[string]interface{}) []interface{} {
return rep return rep
} }
func representConnectionStartOk(event map[string]interface{}) []interface{} {
rep := make([]interface{}, 0)
details, _ := json.Marshal([]api.TableData{
{
Name: "Mechanism",
Value: event["mechanism"].(string),
Selector: `response.mechanism`,
},
{
Name: "Mechanism",
Value: event["mechanism"].(string),
Selector: `response.response`,
},
{
Name: "Locale",
Value: event["locale"].(string),
Selector: `response.locale`,
},
})
rep = append(rep, api.SectionData{
Type: api.TABLE,
Title: "Details",
Data: string(details),
})
if event["clientProperties"] != nil {
headers := make([]api.TableData, 0)
for name, value := range event["clientProperties"].(map[string]interface{}) {
var outcome string
switch v := value.(type) {
case string:
outcome = v
case map[string]interface{}:
x, _ := json.Marshal(value)
outcome = string(x)
default:
logger.Log.Info("Unknown data type for the client property!")
}
headers = append(headers, api.TableData{
Name: name,
Value: outcome,
Selector: fmt.Sprintf(`response.clientProperties["%s"]`, name),
})
}
sort.Slice(headers, func(i, j int) bool {
return headers[i].Name < headers[j].Name
})
headersMarshaled, _ := json.Marshal(headers)
rep = append(rep, api.SectionData{
Type: api.TABLE,
Title: "Client Properties",
Data: string(headersMarshaled),
})
}
return rep
}
func representConnectionClose(event map[string]interface{}) []interface{} { func representConnectionClose(event map[string]interface{}) []interface{} {
replyCode := "" replyCode := ""
@@ -750,3 +851,122 @@ func representBasicConsume(event map[string]interface{}) []interface{} {
return rep return rep
} }
func representBasicConsumeOk(event map[string]interface{}) []interface{} {
rep := make([]interface{}, 0)
details, _ := json.Marshal([]api.TableData{
{
Name: "Consumer Tag",
Value: event["consumerTag"].(string),
Selector: `response.consumerTag`,
},
})
rep = append(rep, api.SectionData{
Type: api.TABLE,
Title: "Details",
Data: string(details),
})
return rep
}
func representConnectionOpen(event map[string]interface{}) []interface{} {
rep := make([]interface{}, 0)
details, _ := json.Marshal([]api.TableData{
{
Name: "Virtual Host",
Value: event["virtualHost"].(string),
Selector: `request.virtualHost`,
},
})
rep = append(rep, api.SectionData{
Type: api.TABLE,
Title: "Details",
Data: string(details),
})
return rep
}
func representConnectionTune(event map[string]interface{}) []interface{} {
rep := make([]interface{}, 0)
details, _ := json.Marshal([]api.TableData{
{
Name: "Channel Max",
Value: fmt.Sprintf("%g", event["channelMax"].(float64)),
Selector: `request.channelMax`,
},
{
Name: "Frame Max",
Value: fmt.Sprintf("%g", event["frameMax"].(float64)),
Selector: `request.frameMax`,
},
{
Name: "Heartbeat",
Value: fmt.Sprintf("%g", event["heartbeat"].(float64)),
Selector: `request.heartbeat`,
},
})
rep = append(rep, api.SectionData{
Type: api.TABLE,
Title: "Details",
Data: string(details),
})
return rep
}
func representBasicCancel(event map[string]interface{}) []interface{} {
rep := make([]interface{}, 0)
details, _ := json.Marshal([]api.TableData{
{
Name: "Consumer Tag",
Value: event["consumerTag"].(string),
Selector: `response.consumerTag`,
},
{
Name: "NoWait",
Value: strconv.FormatBool(event["noWait"].(bool)),
Selector: `request.noWait`,
},
})
rep = append(rep, api.SectionData{
Type: api.TABLE,
Title: "Details",
Data: string(details),
})
return rep
}
func representBasicCancelOk(event map[string]interface{}) []interface{} {
rep := make([]interface{}, 0)
details, _ := json.Marshal([]api.TableData{
{
Name: "Consumer Tag",
Value: event["consumerTag"].(string),
Selector: `response.consumerTag`,
},
})
rep = append(rep, api.SectionData{
Type: api.TABLE,
Title: "Details",
Data: string(details),
})
return rep
}
func representEmpty(event map[string]interface{}) []interface{} {
rep := make([]interface{}, 0)
return rep
}

View File

@@ -12,12 +12,14 @@ import (
"github.com/up9inc/mizu/tap/api" "github.com/up9inc/mizu/tap/api"
) )
var protocol api.Protocol = api.Protocol{ var protocol = api.Protocol{
Name: "amqp", ProtocolSummary: api.ProtocolSummary{
Name: "amqp",
Version: "0-9-1",
Abbreviation: "AMQP",
},
LongName: "Advanced Message Queuing Protocol 0-9-1", LongName: "Advanced Message Queuing Protocol 0-9-1",
Abbreviation: "AMQP",
Macro: "amqp", Macro: "amqp",
Version: "0-9-1",
BackgroundColor: "#ff6600", BackgroundColor: "#ff6600",
ForegroundColor: "#ffffff", ForegroundColor: "#ffffff",
FontSize: 12, FontSize: 12,
@@ -26,32 +28,30 @@ var protocol api.Protocol = api.Protocol{
Priority: 1, Priority: 1,
} }
var protocolsMap = map[string]*api.Protocol{
protocol.ToString(): &protocol,
}
type dissecting string type dissecting string
func (d dissecting) Register(extension *api.Extension) { func (d dissecting) Register(extension *api.Extension) {
extension.Protocol = &protocol extension.Protocol = &protocol
} }
func (d dissecting) GetProtocols() map[string]*api.Protocol {
return protocolsMap
}
func (d dissecting) Ping() { func (d dissecting) Ping() {
log.Printf("pong %s", protocol.Name) log.Printf("pong %s", protocol.Name)
} }
const amqpRequest string = "amqp_request"
func (d dissecting) Dissect(b *bufio.Reader, reader api.TcpReader, options *api.TrafficFilteringOptions) error { func (d dissecting) Dissect(b *bufio.Reader, reader api.TcpReader, options *api.TrafficFilteringOptions) error {
r := AmqpReader{b} r := AmqpReader{b}
var remaining int var remaining int
var header *HeaderFrame var header *HeaderFrame
connectionInfo := &api.ConnectionInfo{
ClientIP: reader.GetTcpID().SrcIP,
ClientPort: reader.GetTcpID().SrcPort,
ServerIP: reader.GetTcpID().DstIP,
ServerPort: reader.GetTcpID().DstPort,
IsOutgoing: true,
}
eventBasicPublish := &BasicPublish{ eventBasicPublish := &BasicPublish{
Exchange: "", Exchange: "",
RoutingKey: "", RoutingKey: "",
@@ -73,14 +73,18 @@ func (d dissecting) Dissect(b *bufio.Reader, reader api.TcpReader, options *api.
var lastMethodFrameMessage Message var lastMethodFrameMessage Message
var ident string
isClient := reader.GetIsClient()
reqResMatcher := reader.GetReqResMatcher().(*requestResponseMatcher)
for { for {
frame, err := r.ReadFrame() frameVal, err := r.readFrame()
if err == io.EOF { if err == io.EOF {
// We must read until we see an EOF... very important! // We must read until we see an EOF... very important!
return err return err
} }
switch f := frame.(type) { switch f := frameVal.(type) {
case *HeartbeatFrame: case *HeartbeatFrame:
// drop // drop
@@ -111,16 +115,22 @@ func (d dissecting) Dissect(b *bufio.Reader, reader api.TcpReader, options *api.
switch lastMethodFrameMessage.(type) { switch lastMethodFrameMessage.(type) {
case *BasicPublish: case *BasicPublish:
eventBasicPublish.Body = f.Body eventBasicPublish.Body = f.Body
emitAMQP(*eventBasicPublish, amqpRequest, basicMethodMap[40], connectionInfo, reader.GetCaptureTime(), reader.GetReadProgress().Current(), reader.GetEmitter(), reader.GetParent().GetOrigin()) reqResMatcher.emitEvent(isClient, ident, basicMethodMap[40], *eventBasicPublish, reader)
reqResMatcher.emitEvent(!isClient, ident, emptyMethod, &emptyResponse{}, reader)
case *BasicDeliver: case *BasicDeliver:
eventBasicDeliver.Body = f.Body eventBasicDeliver.Body = f.Body
emitAMQP(*eventBasicDeliver, amqpRequest, basicMethodMap[60], connectionInfo, reader.GetCaptureTime(), reader.GetReadProgress().Current(), reader.GetEmitter(), reader.GetParent().GetOrigin()) reqResMatcher.emitEvent(!isClient, ident, basicMethodMap[60], *eventBasicDeliver, reader)
reqResMatcher.emitEvent(isClient, ident, emptyMethod, &emptyResponse{}, reader)
} }
case *MethodFrame: case *MethodFrame:
reader.GetParent().SetProtocol(&protocol) reader.GetParent().SetProtocol(&protocol)
lastMethodFrameMessage = f.Method lastMethodFrameMessage = f.Method
ident = getIdent(reader, f)
switch m := f.Method.(type) { switch m := f.Method.(type) {
case *BasicPublish: case *BasicPublish:
eventBasicPublish.Exchange = m.Exchange eventBasicPublish.Exchange = m.Exchange
@@ -136,7 +146,10 @@ func (d dissecting) Dissect(b *bufio.Reader, reader api.TcpReader, options *api.
NoWait: m.NoWait, NoWait: m.NoWait,
Arguments: m.Arguments, Arguments: m.Arguments,
} }
emitAMQP(*eventQueueBind, amqpRequest, queueMethodMap[20], connectionInfo, reader.GetCaptureTime(), reader.GetReadProgress().Current(), reader.GetEmitter(), reader.GetParent().GetOrigin()) reqResMatcher.emitEvent(isClient, ident, queueMethodMap[20], *eventQueueBind, reader)
case *QueueBindOk:
reqResMatcher.emitEvent(isClient, ident, queueMethodMap[21], m, reader)
case *BasicConsume: case *BasicConsume:
eventBasicConsume := &BasicConsume{ eventBasicConsume := &BasicConsume{
@@ -148,7 +161,10 @@ func (d dissecting) Dissect(b *bufio.Reader, reader api.TcpReader, options *api.
NoWait: m.NoWait, NoWait: m.NoWait,
Arguments: m.Arguments, Arguments: m.Arguments,
} }
emitAMQP(*eventBasicConsume, amqpRequest, basicMethodMap[20], connectionInfo, reader.GetCaptureTime(), reader.GetReadProgress().Current(), reader.GetEmitter(), reader.GetParent().GetOrigin()) reqResMatcher.emitEvent(isClient, ident, basicMethodMap[20], *eventBasicConsume, reader)
case *BasicConsumeOk:
reqResMatcher.emitEvent(isClient, ident, basicMethodMap[21], m, reader)
case *BasicDeliver: case *BasicDeliver:
eventBasicDeliver.ConsumerTag = m.ConsumerTag eventBasicDeliver.ConsumerTag = m.ConsumerTag
@@ -167,7 +183,10 @@ func (d dissecting) Dissect(b *bufio.Reader, reader api.TcpReader, options *api.
NoWait: m.NoWait, NoWait: m.NoWait,
Arguments: m.Arguments, Arguments: m.Arguments,
} }
emitAMQP(*eventQueueDeclare, amqpRequest, queueMethodMap[10], connectionInfo, reader.GetCaptureTime(), reader.GetReadProgress().Current(), reader.GetEmitter(), reader.GetParent().GetOrigin()) reqResMatcher.emitEvent(isClient, ident, queueMethodMap[10], *eventQueueDeclare, reader)
case *QueueDeclareOk:
reqResMatcher.emitEvent(isClient, ident, queueMethodMap[11], m, reader)
case *ExchangeDeclare: case *ExchangeDeclare:
eventExchangeDeclare := &ExchangeDeclare{ eventExchangeDeclare := &ExchangeDeclare{
@@ -180,17 +199,19 @@ func (d dissecting) Dissect(b *bufio.Reader, reader api.TcpReader, options *api.
NoWait: m.NoWait, NoWait: m.NoWait,
Arguments: m.Arguments, Arguments: m.Arguments,
} }
emitAMQP(*eventExchangeDeclare, amqpRequest, exchangeMethodMap[10], connectionInfo, reader.GetCaptureTime(), reader.GetReadProgress().Current(), reader.GetEmitter(), reader.GetParent().GetOrigin()) reqResMatcher.emitEvent(isClient, ident, exchangeMethodMap[10], *eventExchangeDeclare, reader)
case *ExchangeDeclareOk:
reqResMatcher.emitEvent(isClient, ident, exchangeMethodMap[11], m, reader)
case *ConnectionStart: case *ConnectionStart:
eventConnectionStart := &ConnectionStart{ // In our tests, *ConnectionStart does not result in *ConnectionStartOk
VersionMajor: m.VersionMajor, reqResMatcher.emitEvent(!isClient, ident, connectionMethodMap[10], m, reader)
VersionMinor: m.VersionMinor, reqResMatcher.emitEvent(isClient, ident, emptyMethod, &emptyResponse{}, reader)
ServerProperties: m.ServerProperties,
Mechanisms: m.Mechanisms, case *ConnectionStartOk:
Locales: m.Locales, // In our tests, *ConnectionStart does not result in *ConnectionStartOk
} reqResMatcher.emitEvent(isClient, ident, connectionMethodMap[11], m, reader)
emitAMQP(*eventConnectionStart, amqpRequest, connectionMethodMap[10], connectionInfo, reader.GetCaptureTime(), reader.GetReadProgress().Current(), reader.GetEmitter(), reader.GetParent().GetOrigin())
case *ConnectionClose: case *ConnectionClose:
eventConnectionClose := &ConnectionClose{ eventConnectionClose := &ConnectionClose{
@@ -199,22 +220,63 @@ func (d dissecting) Dissect(b *bufio.Reader, reader api.TcpReader, options *api.
ClassId: m.ClassId, ClassId: m.ClassId,
MethodId: m.MethodId, MethodId: m.MethodId,
} }
emitAMQP(*eventConnectionClose, amqpRequest, connectionMethodMap[50], connectionInfo, reader.GetCaptureTime(), reader.GetReadProgress().Current(), reader.GetEmitter(), reader.GetParent().GetOrigin()) reqResMatcher.emitEvent(isClient, ident, connectionMethodMap[50], *eventConnectionClose, reader)
case *ConnectionCloseOk:
reqResMatcher.emitEvent(isClient, ident, connectionMethodMap[51], m, reader)
case *connectionOpen:
eventConnectionOpen := &connectionOpen{
VirtualHost: m.VirtualHost,
}
reqResMatcher.emitEvent(isClient, ident, connectionMethodMap[40], *eventConnectionOpen, reader)
case *connectionOpenOk:
reqResMatcher.emitEvent(isClient, ident, connectionMethodMap[41], m, reader)
case *channelOpen:
reqResMatcher.emitEvent(isClient, ident, channelMethodMap[10], m, reader)
case *channelOpenOk:
reqResMatcher.emitEvent(isClient, ident, channelMethodMap[11], m, reader)
case *connectionTune:
// In our tests, *connectionTune does not result in *connectionTuneOk
reqResMatcher.emitEvent(!isClient, ident, connectionMethodMap[30], m, reader)
reqResMatcher.emitEvent(isClient, ident, emptyMethod, &emptyResponse{}, reader)
case *connectionTuneOk:
// In our tests, *connectionTune does not result in *connectionTuneOk
reqResMatcher.emitEvent(isClient, ident, connectionMethodMap[31], m, reader)
case *basicCancel:
reqResMatcher.emitEvent(isClient, ident, basicMethodMap[30], m, reader)
case *basicCancelOk:
reqResMatcher.emitEvent(isClient, ident, basicMethodMap[31], m, reader)
} }
default: default:
// log.Printf("unexpected frame: %+v", f) // log.Printf("unexpected frameVal: %+v", f)
} }
} }
} }
func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string, resolvedDestination string, namespace string) *api.Entry { func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string, resolvedDestination string, namespace string) *api.Entry {
request := item.Pair.Request.Payload.(map[string]interface{}) request := item.Pair.Request.Payload.(map[string]interface{})
response := item.Pair.Response.Payload.(map[string]interface{})
reqDetails := request["details"].(map[string]interface{}) reqDetails := request["details"].(map[string]interface{})
resDetails := response["details"].(map[string]interface{})
elapsedTime := item.Pair.Response.CaptureTime.Sub(item.Pair.Request.CaptureTime).Round(time.Millisecond).Milliseconds()
if elapsedTime < 0 {
elapsedTime = 0
}
reqDetails["method"] = request["method"] reqDetails["method"] = request["method"]
resDetails["method"] = response["method"]
return &api.Entry{ return &api.Entry{
Protocol: protocol, Protocol: protocol.ProtocolSummary,
Capture: item.Capture, Capture: item.Capture,
Source: &api.TCP{ Source: &api.TCP{
Name: resolvedSource, Name: resolvedSource,
@@ -226,13 +288,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,
RequestSize: item.Pair.Request.CaptureSize, Response: resDetails,
Timestamp: item.Timestamp, RequestSize: item.Pair.Request.CaptureSize,
StartTime: item.Pair.Request.CaptureTime, ResponseSize: item.Pair.Response.CaptureSize,
ElapsedTime: 0, Timestamp: item.Timestamp,
StartTime: item.Pair.Request.CaptureTime,
ElapsedTime: elapsedTime,
} }
} }
@@ -273,31 +337,46 @@ func (d dissecting) Summarize(entry *api.Entry) *api.BaseEntry {
case basicMethodMap[20]: case basicMethodMap[20]:
summary = entry.Request["queue"].(string) summary = entry.Request["queue"].(string)
summaryQuery = fmt.Sprintf(`request.queue == "%s"`, summary) summaryQuery = fmt.Sprintf(`request.queue == "%s"`, summary)
case connectionMethodMap[40]:
summary = entry.Request["virtualHost"].(string)
summaryQuery = fmt.Sprintf(`request.virtualHost == "%s"`, summary)
case connectionMethodMap[30]:
summary = fmt.Sprintf("%g", entry.Request["channelMax"].(float64))
summaryQuery = fmt.Sprintf(`request.channelMax == "%s"`, summary)
case connectionMethodMap[31]:
summary = fmt.Sprintf("%g", entry.Request["channelMax"].(float64))
summaryQuery = fmt.Sprintf(`request.channelMax == "%s"`, summary)
case basicMethodMap[30]:
summary = entry.Request["consumerTag"].(string)
summaryQuery = fmt.Sprintf(`request.consumerTag == "%s"`, summary)
case basicMethodMap[31]:
summary = entry.Request["consumerTag"].(string)
summaryQuery = fmt.Sprintf(`request.consumerTag == "%s"`, summary)
} }
return &api.BaseEntry{ return &api.BaseEntry{
Id: entry.Id, Id: entry.Id,
Protocol: entry.Protocol, Protocol: *protocolsMap[entry.Protocol.ToString()],
Capture: entry.Capture, Capture: entry.Capture,
Summary: summary, Summary: summary,
SummaryQuery: summaryQuery, SummaryQuery: summaryQuery,
Status: 0, Status: 0,
StatusQuery: "", StatusQuery: "",
Method: method, Method: method,
MethodQuery: methodQuery, MethodQuery: methodQuery,
Timestamp: entry.Timestamp, Timestamp: entry.Timestamp,
Source: entry.Source, Source: entry.Source,
Destination: entry.Destination, Destination: entry.Destination,
IsOutgoing: entry.Outgoing, IsOutgoing: entry.Outgoing,
Latency: entry.ElapsedTime, Latency: entry.ElapsedTime,
Rules: entry.Rules,
ContractStatus: entry.ContractStatus,
} }
} }
func (d dissecting) Represent(request map[string]interface{}, response map[string]interface{}) (object []byte, 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{})
var repRequest []interface{} var repRequest []interface{}
var repResponse []interface{}
switch request["method"].(string) { switch request["method"].(string) {
case basicMethodMap[40]: case basicMethodMap[40]:
repRequest = representBasicPublish(request) repRequest = representBasicPublish(request)
@@ -315,20 +394,56 @@ func (d dissecting) Represent(request map[string]interface{}, response map[strin
repRequest = representQueueBind(request) repRequest = representQueueBind(request)
case basicMethodMap[20]: case basicMethodMap[20]:
repRequest = representBasicConsume(request) repRequest = representBasicConsume(request)
case connectionMethodMap[40]:
repRequest = representConnectionOpen(request)
case channelMethodMap[10]:
repRequest = representEmpty(request)
case connectionMethodMap[30]:
repRequest = representConnectionTune(request)
case basicMethodMap[30]:
repRequest = representBasicCancel(request)
} }
switch response["method"].(string) {
case queueMethodMap[11]:
repResponse = representQueueDeclareOk(response)
case exchangeMethodMap[11]:
repResponse = representEmpty(response)
case connectionMethodMap[11]:
repResponse = representConnectionStartOk(response)
case connectionMethodMap[51]:
repResponse = representEmpty(response)
case basicMethodMap[21]:
repResponse = representBasicConsumeOk(response)
case queueMethodMap[21]:
repResponse = representEmpty(response)
case connectionMethodMap[41]:
repResponse = representEmpty(response)
case channelMethodMap[11]:
repResponse = representEmpty(request)
case connectionMethodMap[31]:
repResponse = representConnectionTune(request)
case basicMethodMap[31]:
repResponse = representBasicCancelOk(request)
case emptyMethod:
repResponse = representEmpty(response)
}
representation["request"] = repRequest representation["request"] = repRequest
representation["response"] = repResponse
object, err = json.Marshal(representation) object, err = json.Marshal(representation)
return return
} }
func (d dissecting) Macros() map[string]string { func (d dissecting) Macros() map[string]string {
return map[string]string{ return map[string]string{
`amqp`: fmt.Sprintf(`proto.name == "%s"`, protocol.Name), `amqp`: fmt.Sprintf(`protocol.name == "%s"`, protocol.Name),
} }
} }
func (d dissecting) NewResponseRequestMatcher() api.RequestResponseMatcher { func (d dissecting) NewResponseRequestMatcher() api.RequestResponseMatcher {
return nil return createResponseRequestMatcher()
} }
var Dissector dissecting var Dissector dissecting

View File

@@ -44,7 +44,7 @@ func TestRegister(t *testing.T) {
func TestMacros(t *testing.T) { func TestMacros(t *testing.T) {
expectedMacros := map[string]string{ expectedMacros := map[string]string{
"amqp": `proto.name == "amqp"`, "amqp": `protocol.name == "amqp"`,
} }
dissector := NewDissector() dissector := NewDissector()
macros := dissector.Macros() macros := dissector.Macros()

View File

@@ -0,0 +1,113 @@
package amqp
import (
"sync"
"time"
"github.com/up9inc/mizu/tap/api"
)
// Key is {client_addr}_{client_port}_{dest_addr}_{dest_port}_{channel_id}_{class_id}_{method_id}
type requestResponseMatcher struct {
openMessagesMap *sync.Map
}
func createResponseRequestMatcher() api.RequestResponseMatcher {
return &requestResponseMatcher{openMessagesMap: &sync.Map{}}
}
func (matcher *requestResponseMatcher) GetMap() *sync.Map {
return matcher.openMessagesMap
}
func (matcher *requestResponseMatcher) SetMaxTry(value int) {
}
func (matcher *requestResponseMatcher) emitEvent(isRequest bool, ident string, method string, event interface{}, reader api.TcpReader) {
reader.GetParent().SetProtocol(&protocol)
var item *api.OutputChannelItem
if isRequest {
item = matcher.registerRequest(ident, method, event, reader.GetCaptureTime(), reader.GetReadProgress().Current())
} else {
item = matcher.registerResponse(ident, method, event, reader.GetCaptureTime(), reader.GetReadProgress().Current())
}
if item != nil {
item.ConnectionInfo = &api.ConnectionInfo{
ClientIP: reader.GetTcpID().SrcIP,
ClientPort: reader.GetTcpID().SrcPort,
ServerIP: reader.GetTcpID().DstIP,
ServerPort: reader.GetTcpID().DstPort,
IsOutgoing: true,
}
item.Capture = reader.GetParent().GetOrigin()
reader.GetEmitter().Emit(item)
}
}
func (matcher *requestResponseMatcher) registerRequest(ident string, method string, request interface{}, captureTime time.Time, captureSize int) *api.OutputChannelItem {
requestAMQPMessage := api.GenericMessage{
IsRequest: true,
CaptureTime: captureTime,
CaptureSize: captureSize,
Payload: AMQPPayload{
Data: &AMQPWrapper{
Method: method,
Url: "",
Details: request,
},
},
}
if response, found := matcher.openMessagesMap.LoadAndDelete(ident); found {
// Type assertion always succeeds because all of the map's values are of api.GenericMessage type
responseAMQPMessage := response.(*api.GenericMessage)
if responseAMQPMessage.IsRequest {
return nil
}
return matcher.preparePair(&requestAMQPMessage, responseAMQPMessage)
}
matcher.openMessagesMap.Store(ident, &requestAMQPMessage)
return nil
}
func (matcher *requestResponseMatcher) registerResponse(ident string, method string, response interface{}, captureTime time.Time, captureSize int) *api.OutputChannelItem {
responseAMQPMessage := api.GenericMessage{
IsRequest: false,
CaptureTime: captureTime,
CaptureSize: captureSize,
Payload: AMQPPayload{
Data: &AMQPWrapper{
Method: method,
Url: "",
Details: response,
},
},
}
if request, found := matcher.openMessagesMap.LoadAndDelete(ident); found {
// Type assertion always succeeds because all of the map's values are of api.GenericMessage type
requestAMQPMessage := request.(*api.GenericMessage)
if !requestAMQPMessage.IsRequest {
return nil
}
return matcher.preparePair(requestAMQPMessage, &responseAMQPMessage)
}
matcher.openMessagesMap.Store(ident, &responseAMQPMessage)
return nil
}
func (matcher *requestResponseMatcher) preparePair(requestAMQPMessage *api.GenericMessage, responseAMQPMessage *api.GenericMessage) *api.OutputChannelItem {
return &api.OutputChannelItem{
Protocol: protocol,
Timestamp: requestAMQPMessage.CaptureTime.UnixNano() / int64(time.Millisecond),
ConnectionInfo: nil,
Pair: &api.RequestResponsePair{
Request: *requestAMQPMessage,
Response: *responseAMQPMessage,
},
}
}

View File

@@ -43,14 +43,14 @@ In realistic implementations where performance is a concern, we would use
“gathering reads” to avoid doing three separate system calls to read a frame. “gathering reads” to avoid doing three separate system calls to read a frame.
*/ */
func (r *AmqpReader) ReadFrame() (frame frame, err error) { func (r *AmqpReader) readFrame() (frame frame, err error) {
var scratch [7]byte var scratch [7]byte
if _, err = io.ReadFull(r.R, scratch[:7]); err != nil { if _, err = io.ReadFull(r.R, scratch[:7]); err != nil {
return return
} }
typ := uint8(scratch[0]) typ := scratch[0]
channel := binary.BigEndian.Uint16(scratch[1:3]) channel := binary.BigEndian.Uint16(scratch[1:3])
size := binary.BigEndian.Uint32(scratch[3:7]) size := binary.BigEndian.Uint32(scratch[3:7])
@@ -94,20 +94,20 @@ func (r *AmqpReader) ReadFrame() (frame frame, err error) {
return return
} }
func readShortstr(r io.Reader) (v string, err error) { func readShortStr(r io.Reader) (v string, err error) {
var length uint8 var length uint8
if err = binary.Read(r, binary.BigEndian, &length); err != nil { if err = binary.Read(r, binary.BigEndian, &length); err != nil {
return return
} }
bytes := make([]byte, length) bytesValue := make([]byte, length)
if _, err = io.ReadFull(r, bytes); err != nil { if _, err = io.ReadFull(r, bytesValue); err != nil {
return return
} }
return string(bytes), nil return string(bytesValue), nil
} }
func readLongstr(r io.Reader) (v string, err error) { func readLongStr(r io.Reader) (v string, err error) {
var length uint32 var length uint32
if err = binary.Read(r, binary.BigEndian, &length); err != nil { if err = binary.Read(r, binary.BigEndian, &length); err != nil {
return return
@@ -118,11 +118,11 @@ func readLongstr(r io.Reader) (v string, err error) {
return return
} }
bytes := make([]byte, length) bytesValue := make([]byte, length)
if _, err = io.ReadFull(r, bytes); err != nil { if _, err = io.ReadFull(r, bytesValue); err != nil {
return return
} }
return string(bytes), nil return string(bytesValue), nil
} }
func readDecimal(r io.Reader) (v Decimal, err error) { func readDecimal(r io.Reader) (v Decimal, err error) {
@@ -171,7 +171,7 @@ func readField(r io.Reader) (v interface{}, err error) {
if err = binary.Read(r, binary.BigEndian, &value); err != nil { if err = binary.Read(r, binary.BigEndian, &value); err != nil {
return return
} }
return (value != 0), nil return value != 0, nil
case 'b': case 'b':
var value [1]byte var value [1]byte
@@ -219,7 +219,7 @@ func readField(r io.Reader) (v interface{}, err error) {
return readDecimal(r) return readDecimal(r)
case 'S': case 'S':
return readLongstr(r) return readLongStr(r)
case 'A': case 'A':
return readArray(r) return readArray(r)
@@ -231,12 +231,12 @@ func readField(r io.Reader) (v interface{}, err error) {
return readTable(r) return readTable(r)
case 'x': case 'x':
var len int32 var lenVal int32
if err = binary.Read(r, binary.BigEndian, &len); err != nil { if err = binary.Read(r, binary.BigEndian, &lenVal); err != nil {
return nil, err return nil, err
} }
value := make([]byte, len) value := make([]byte, lenVal)
if _, err = io.ReadFull(r, value); err != nil { if _, err = io.ReadFull(r, value); err != nil {
return nil, err return nil, err
} }
@@ -261,7 +261,7 @@ func readTable(r io.Reader) (table Table, err error) {
var nested bytes.Buffer var nested bytes.Buffer
var str string var str string
if str, err = readLongstr(r); err != nil { if str, err = readLongStr(r); err != nil {
return return
} }
@@ -273,7 +273,7 @@ func readTable(r io.Reader) (table Table, err error) {
var key string var key string
var value interface{} var value interface{}
if key, err = readShortstr(&nested); err != nil { if key, err = readShortStr(&nested); err != nil {
return return
} }
@@ -349,12 +349,12 @@ func (r *AmqpReader) parseHeaderFrame(channel uint16, size uint32) (frame frame,
} }
if hasProperty(flags, flagContentType) { if hasProperty(flags, flagContentType) {
if hf.Properties.ContentType, err = readShortstr(r.R); err != nil { if hf.Properties.ContentType, err = readShortStr(r.R); err != nil {
return return
} }
} }
if hasProperty(flags, flagContentEncoding) { if hasProperty(flags, flagContentEncoding) {
if hf.Properties.ContentEncoding, err = readShortstr(r.R); err != nil { if hf.Properties.ContentEncoding, err = readShortStr(r.R); err != nil {
return return
} }
} }
@@ -374,22 +374,22 @@ func (r *AmqpReader) parseHeaderFrame(channel uint16, size uint32) (frame frame,
} }
} }
if hasProperty(flags, flagCorrelationId) { if hasProperty(flags, flagCorrelationId) {
if hf.Properties.CorrelationId, err = readShortstr(r.R); err != nil { if hf.Properties.CorrelationId, err = readShortStr(r.R); err != nil {
return return
} }
} }
if hasProperty(flags, flagReplyTo) { if hasProperty(flags, flagReplyTo) {
if hf.Properties.ReplyTo, err = readShortstr(r.R); err != nil { if hf.Properties.ReplyTo, err = readShortStr(r.R); err != nil {
return return
} }
} }
if hasProperty(flags, flagExpiration) { if hasProperty(flags, flagExpiration) {
if hf.Properties.Expiration, err = readShortstr(r.R); err != nil { if hf.Properties.Expiration, err = readShortStr(r.R); err != nil {
return return
} }
} }
if hasProperty(flags, flagMessageId) { if hasProperty(flags, flagMessageId) {
if hf.Properties.MessageId, err = readShortstr(r.R); err != nil { if hf.Properties.MessageId, err = readShortStr(r.R); err != nil {
return return
} }
} }
@@ -399,22 +399,22 @@ func (r *AmqpReader) parseHeaderFrame(channel uint16, size uint32) (frame frame,
} }
} }
if hasProperty(flags, flagType) { if hasProperty(flags, flagType) {
if hf.Properties.Type, err = readShortstr(r.R); err != nil { if hf.Properties.Type, err = readShortStr(r.R); err != nil {
return return
} }
} }
if hasProperty(flags, flagUserId) { if hasProperty(flags, flagUserId) {
if hf.Properties.UserId, err = readShortstr(r.R); err != nil { if hf.Properties.UserId, err = readShortStr(r.R); err != nil {
return return
} }
} }
if hasProperty(flags, flagAppId) { if hasProperty(flags, flagAppId) {
if hf.Properties.AppId, err = readShortstr(r.R); err != nil { if hf.Properties.AppId, err = readShortStr(r.R); err != nil {
return return
} }
} }
if hasProperty(flags, flagReserved1) { if hasProperty(flags, flagReserved1) {
if hf.Properties.reserved1, err = readShortstr(r.R); err != nil { if hf.Properties.reserved1, err = readShortStr(r.R); err != nil {
return return
} }
} }
@@ -436,7 +436,7 @@ func (r *AmqpReader) parseBodyFrame(channel uint16, size uint32) (frame frame, e
return bf, nil return bf, nil
} }
var errHeartbeatPayload = errors.New("Heartbeats should not have a payload") var errHeartbeatPayload = errors.New("heartbeats should not have a payload")
func (r *AmqpReader) parseHeartbeatFrame(channel uint16, size uint32) (frame frame, err error) { func (r *AmqpReader) parseHeartbeatFrame(channel uint16, size uint32) (frame frame, err error) {
hf := &HeartbeatFrame{ hf := &HeartbeatFrame{

View File

@@ -70,10 +70,10 @@ func (msg *ConnectionStart) read(r io.Reader) (err error) {
return return
} }
if msg.Mechanisms, err = readLongstr(r); err != nil { if msg.Mechanisms, err = readLongStr(r); err != nil {
return return
} }
if msg.Locales, err = readLongstr(r); err != nil { if msg.Locales, err = readLongStr(r); err != nil {
return return
} }
@@ -81,10 +81,10 @@ func (msg *ConnectionStart) read(r io.Reader) (err error) {
} }
type ConnectionStartOk struct { type ConnectionStartOk struct {
ClientProperties Table ClientProperties Table `json:"clientProperties"`
Mechanism string Mechanism string `json:"mechanism"`
Response string Response string `json:"response"`
Locale string Locale string `json:"locale"`
} }
func (msg *ConnectionStartOk) read(r io.Reader) (err error) { func (msg *ConnectionStartOk) read(r io.Reader) (err error) {
@@ -93,15 +93,15 @@ func (msg *ConnectionStartOk) read(r io.Reader) (err error) {
return return
} }
if msg.Mechanism, err = readShortstr(r); err != nil { if msg.Mechanism, err = readShortStr(r); err != nil {
return return
} }
if msg.Response, err = readLongstr(r); err != nil { if msg.Response, err = readLongStr(r); err != nil {
return return
} }
if msg.Locale, err = readShortstr(r); err != nil { if msg.Locale, err = readShortStr(r); err != nil {
return return
} }
@@ -114,7 +114,7 @@ type connectionSecure struct {
func (msg *connectionSecure) read(r io.Reader) (err error) { func (msg *connectionSecure) read(r io.Reader) (err error) {
if msg.Challenge, err = readLongstr(r); err != nil { if msg.Challenge, err = readLongStr(r); err != nil {
return return
} }
@@ -127,7 +127,7 @@ type connectionSecureOk struct {
func (msg *connectionSecureOk) read(r io.Reader) (err error) { func (msg *connectionSecureOk) read(r io.Reader) (err error) {
if msg.Response, err = readLongstr(r); err != nil { if msg.Response, err = readLongStr(r); err != nil {
return return
} }
@@ -135,9 +135,9 @@ func (msg *connectionSecureOk) read(r io.Reader) (err error) {
} }
type connectionTune struct { type connectionTune struct {
ChannelMax uint16 ChannelMax uint16 `json:"channelMax"`
FrameMax uint32 FrameMax uint32 `json:"frameMax"`
Heartbeat uint16 Heartbeat uint16 `json:"heartbeat"`
} }
func (msg *connectionTune) read(r io.Reader) (err error) { func (msg *connectionTune) read(r io.Reader) (err error) {
@@ -181,7 +181,7 @@ func (msg *connectionTuneOk) read(r io.Reader) (err error) {
} }
type connectionOpen struct { type connectionOpen struct {
VirtualHost string VirtualHost string `json:"virtualHost"`
reserved1 string reserved1 string
reserved2 bool reserved2 bool
} }
@@ -189,17 +189,17 @@ type connectionOpen struct {
func (msg *connectionOpen) read(r io.Reader) (err error) { func (msg *connectionOpen) read(r io.Reader) (err error) {
var bits byte var bits byte
if msg.VirtualHost, err = readShortstr(r); err != nil { if msg.VirtualHost, err = readShortStr(r); err != nil {
return return
} }
if msg.reserved1, err = readShortstr(r); err != nil { if msg.reserved1, err = readShortStr(r); err != nil {
return return
} }
if err = binary.Read(r, binary.BigEndian, &bits); err != nil { if err = binary.Read(r, binary.BigEndian, &bits); err != nil {
return return
} }
msg.reserved2 = (bits&(1<<0) > 0) msg.reserved2 = bits&(1<<0) > 0
return return
} }
@@ -210,7 +210,7 @@ type connectionOpenOk struct {
func (msg *connectionOpenOk) read(r io.Reader) (err error) { func (msg *connectionOpenOk) read(r io.Reader) (err error) {
if msg.reserved1, err = readShortstr(r); err != nil { if msg.reserved1, err = readShortStr(r); err != nil {
return return
} }
@@ -230,7 +230,7 @@ func (msg *ConnectionClose) read(r io.Reader) (err error) {
return return
} }
if msg.ReplyText, err = readShortstr(r); err != nil { if msg.ReplyText, err = readShortStr(r); err != nil {
return return
} }
@@ -258,7 +258,7 @@ type connectionBlocked struct {
func (msg *connectionBlocked) read(r io.Reader) (err error) { func (msg *connectionBlocked) read(r io.Reader) (err error) {
if msg.Reason, err = readShortstr(r); err != nil { if msg.Reason, err = readShortStr(r); err != nil {
return return
} }
@@ -279,7 +279,7 @@ type channelOpen struct {
func (msg *channelOpen) read(r io.Reader) (err error) { func (msg *channelOpen) read(r io.Reader) (err error) {
if msg.reserved1, err = readShortstr(r); err != nil { if msg.reserved1, err = readShortStr(r); err != nil {
return return
} }
@@ -292,7 +292,7 @@ type channelOpenOk struct {
func (msg *channelOpenOk) read(r io.Reader) (err error) { func (msg *channelOpenOk) read(r io.Reader) (err error) {
if msg.reserved1, err = readLongstr(r); err != nil { if msg.reserved1, err = readLongStr(r); err != nil {
return return
} }
@@ -309,7 +309,7 @@ func (msg *channelFlow) read(r io.Reader) (err error) {
if err = binary.Read(r, binary.BigEndian, &bits); err != nil { if err = binary.Read(r, binary.BigEndian, &bits); err != nil {
return return
} }
msg.Active = (bits&(1<<0) > 0) msg.Active = bits&(1<<0) > 0
return return
} }
@@ -324,7 +324,7 @@ func (msg *channelFlowOk) read(r io.Reader) (err error) {
if err = binary.Read(r, binary.BigEndian, &bits); err != nil { if err = binary.Read(r, binary.BigEndian, &bits); err != nil {
return return
} }
msg.Active = (bits&(1<<0) > 0) msg.Active = bits&(1<<0) > 0
return return
} }
@@ -342,7 +342,7 @@ func (msg *channelClose) read(r io.Reader) (err error) {
return return
} }
if msg.ReplyText, err = readShortstr(r); err != nil { if msg.ReplyText, err = readShortStr(r); err != nil {
return return
} }
@@ -383,21 +383,21 @@ func (msg *ExchangeDeclare) read(r io.Reader) (err error) {
return return
} }
if msg.Exchange, err = readShortstr(r); err != nil { if msg.Exchange, err = readShortStr(r); err != nil {
return return
} }
if msg.Type, err = readShortstr(r); err != nil { if msg.Type, err = readShortStr(r); err != nil {
return return
} }
if err = binary.Read(r, binary.BigEndian, &bits); err != nil { if err = binary.Read(r, binary.BigEndian, &bits); err != nil {
return return
} }
msg.Passive = (bits&(1<<0) > 0) msg.Passive = bits&(1<<0) > 0
msg.Durable = (bits&(1<<1) > 0) msg.Durable = bits&(1<<1) > 0
msg.AutoDelete = (bits&(1<<2) > 0) msg.AutoDelete = bits&(1<<2) > 0
msg.Internal = (bits&(1<<3) > 0) msg.Internal = bits&(1<<3) > 0
msg.NoWait = (bits&(1<<4) > 0) msg.NoWait = bits&(1<<4) > 0
if msg.Arguments, err = readTable(r); err != nil { if msg.Arguments, err = readTable(r); err != nil {
return return
@@ -428,15 +428,15 @@ func (msg *exchangeDelete) read(r io.Reader) (err error) {
return return
} }
if msg.Exchange, err = readShortstr(r); err != nil { if msg.Exchange, err = readShortStr(r); err != nil {
return return
} }
if err = binary.Read(r, binary.BigEndian, &bits); err != nil { if err = binary.Read(r, binary.BigEndian, &bits); err != nil {
return return
} }
msg.IfUnused = (bits&(1<<0) > 0) msg.IfUnused = bits&(1<<0) > 0
msg.NoWait = (bits&(1<<1) > 0) msg.NoWait = bits&(1<<1) > 0
return return
} }
@@ -465,20 +465,20 @@ func (msg *exchangeBind) read(r io.Reader) (err error) {
return return
} }
if msg.Destination, err = readShortstr(r); err != nil { if msg.Destination, err = readShortStr(r); err != nil {
return return
} }
if msg.Source, err = readShortstr(r); err != nil { if msg.Source, err = readShortStr(r); err != nil {
return return
} }
if msg.RoutingKey, err = readShortstr(r); err != nil { if msg.RoutingKey, err = readShortStr(r); err != nil {
return return
} }
if err = binary.Read(r, binary.BigEndian, &bits); err != nil { if err = binary.Read(r, binary.BigEndian, &bits); err != nil {
return return
} }
msg.NoWait = (bits&(1<<0) > 0) msg.NoWait = bits&(1<<0) > 0
if msg.Arguments, err = readTable(r); err != nil { if msg.Arguments, err = readTable(r); err != nil {
return return
@@ -511,20 +511,20 @@ func (msg *exchangeUnbind) read(r io.Reader) (err error) {
return return
} }
if msg.Destination, err = readShortstr(r); err != nil { if msg.Destination, err = readShortStr(r); err != nil {
return return
} }
if msg.Source, err = readShortstr(r); err != nil { if msg.Source, err = readShortStr(r); err != nil {
return return
} }
if msg.RoutingKey, err = readShortstr(r); err != nil { if msg.RoutingKey, err = readShortStr(r); err != nil {
return return
} }
if err = binary.Read(r, binary.BigEndian, &bits); err != nil { if err = binary.Read(r, binary.BigEndian, &bits); err != nil {
return return
} }
msg.NoWait = (bits&(1<<0) > 0) msg.NoWait = bits&(1<<0) > 0
if msg.Arguments, err = readTable(r); err != nil { if msg.Arguments, err = readTable(r); err != nil {
return return
@@ -559,18 +559,18 @@ func (msg *QueueDeclare) read(r io.Reader) (err error) {
return return
} }
if msg.Queue, err = readShortstr(r); err != nil { if msg.Queue, err = readShortStr(r); err != nil {
return return
} }
if err = binary.Read(r, binary.BigEndian, &bits); err != nil { if err = binary.Read(r, binary.BigEndian, &bits); err != nil {
return return
} }
msg.Passive = (bits&(1<<0) > 0) msg.Passive = bits&(1<<0) > 0
msg.Durable = (bits&(1<<1) > 0) msg.Durable = bits&(1<<1) > 0
msg.Exclusive = (bits&(1<<2) > 0) msg.Exclusive = bits&(1<<2) > 0
msg.AutoDelete = (bits&(1<<3) > 0) msg.AutoDelete = bits&(1<<3) > 0
msg.NoWait = (bits&(1<<4) > 0) msg.NoWait = bits&(1<<4) > 0
if msg.Arguments, err = readTable(r); err != nil { if msg.Arguments, err = readTable(r); err != nil {
return return
@@ -580,14 +580,14 @@ func (msg *QueueDeclare) read(r io.Reader) (err error) {
} }
type QueueDeclareOk struct { type QueueDeclareOk struct {
Queue string Queue string `json:"queue"`
MessageCount uint32 MessageCount uint32 `json:"messageCount"`
ConsumerCount uint32 ConsumerCount uint32 `json:"consumerCount"`
} }
func (msg *QueueDeclareOk) read(r io.Reader) (err error) { func (msg *QueueDeclareOk) read(r io.Reader) (err error) {
if msg.Queue, err = readShortstr(r); err != nil { if msg.Queue, err = readShortStr(r); err != nil {
return return
} }
@@ -617,20 +617,20 @@ func (msg *QueueBind) read(r io.Reader) (err error) {
return return
} }
if msg.Queue, err = readShortstr(r); err != nil { if msg.Queue, err = readShortStr(r); err != nil {
return return
} }
if msg.Exchange, err = readShortstr(r); err != nil { if msg.Exchange, err = readShortStr(r); err != nil {
return return
} }
if msg.RoutingKey, err = readShortstr(r); err != nil { if msg.RoutingKey, err = readShortStr(r); err != nil {
return return
} }
if err = binary.Read(r, binary.BigEndian, &bits); err != nil { if err = binary.Read(r, binary.BigEndian, &bits); err != nil {
return return
} }
msg.NoWait = (bits&(1<<0) > 0) msg.NoWait = bits&(1<<0) > 0
if msg.Arguments, err = readTable(r); err != nil { if msg.Arguments, err = readTable(r); err != nil {
return return
@@ -661,13 +661,13 @@ func (msg *queueUnbind) read(r io.Reader) (err error) {
return return
} }
if msg.Queue, err = readShortstr(r); err != nil { if msg.Queue, err = readShortStr(r); err != nil {
return return
} }
if msg.Exchange, err = readShortstr(r); err != nil { if msg.Exchange, err = readShortStr(r); err != nil {
return return
} }
if msg.RoutingKey, err = readShortstr(r); err != nil { if msg.RoutingKey, err = readShortStr(r); err != nil {
return return
} }
@@ -699,14 +699,14 @@ func (msg *queuePurge) read(r io.Reader) (err error) {
return return
} }
if msg.Queue, err = readShortstr(r); err != nil { if msg.Queue, err = readShortStr(r); err != nil {
return return
} }
if err = binary.Read(r, binary.BigEndian, &bits); err != nil { if err = binary.Read(r, binary.BigEndian, &bits); err != nil {
return return
} }
msg.NoWait = (bits&(1<<0) > 0) msg.NoWait = bits&(1<<0) > 0
return return
} }
@@ -739,16 +739,16 @@ func (msg *queueDelete) read(r io.Reader) (err error) {
return return
} }
if msg.Queue, err = readShortstr(r); err != nil { if msg.Queue, err = readShortStr(r); err != nil {
return return
} }
if err = binary.Read(r, binary.BigEndian, &bits); err != nil { if err = binary.Read(r, binary.BigEndian, &bits); err != nil {
return return
} }
msg.IfUnused = (bits&(1<<0) > 0) msg.IfUnused = bits&(1<<0) > 0
msg.IfEmpty = (bits&(1<<1) > 0) msg.IfEmpty = bits&(1<<1) > 0
msg.NoWait = (bits&(1<<2) > 0) msg.NoWait = bits&(1<<2) > 0
return return
} }
@@ -786,7 +786,7 @@ func (msg *basicQos) read(r io.Reader) (err error) {
if err = binary.Read(r, binary.BigEndian, &bits); err != nil { if err = binary.Read(r, binary.BigEndian, &bits); err != nil {
return return
} }
msg.Global = (bits&(1<<0) > 0) msg.Global = bits&(1<<0) > 0
return return
} }
@@ -817,20 +817,20 @@ func (msg *BasicConsume) read(r io.Reader) (err error) {
return return
} }
if msg.Queue, err = readShortstr(r); err != nil { if msg.Queue, err = readShortStr(r); err != nil {
return return
} }
if msg.ConsumerTag, err = readShortstr(r); err != nil { if msg.ConsumerTag, err = readShortStr(r); err != nil {
return return
} }
if err = binary.Read(r, binary.BigEndian, &bits); err != nil { if err = binary.Read(r, binary.BigEndian, &bits); err != nil {
return return
} }
msg.NoLocal = (bits&(1<<0) > 0) msg.NoLocal = bits&(1<<0) > 0
msg.NoAck = (bits&(1<<1) > 0) msg.NoAck = bits&(1<<1) > 0
msg.Exclusive = (bits&(1<<2) > 0) msg.Exclusive = bits&(1<<2) > 0
msg.NoWait = (bits&(1<<3) > 0) msg.NoWait = bits&(1<<3) > 0
if msg.Arguments, err = readTable(r); err != nil { if msg.Arguments, err = readTable(r); err != nil {
return return
@@ -840,12 +840,12 @@ func (msg *BasicConsume) read(r io.Reader) (err error) {
} }
type BasicConsumeOk struct { type BasicConsumeOk struct {
ConsumerTag string ConsumerTag string `json:"consumerTag"`
} }
func (msg *BasicConsumeOk) read(r io.Reader) (err error) { func (msg *BasicConsumeOk) read(r io.Reader) (err error) {
if msg.ConsumerTag, err = readShortstr(r); err != nil { if msg.ConsumerTag, err = readShortStr(r); err != nil {
return return
} }
@@ -853,32 +853,32 @@ func (msg *BasicConsumeOk) read(r io.Reader) (err error) {
} }
type basicCancel struct { type basicCancel struct {
ConsumerTag string ConsumerTag string `json:"consumerTag"`
NoWait bool NoWait bool `json:"noWait"`
} }
func (msg *basicCancel) read(r io.Reader) (err error) { func (msg *basicCancel) read(r io.Reader) (err error) {
var bits byte var bits byte
if msg.ConsumerTag, err = readShortstr(r); err != nil { if msg.ConsumerTag, err = readShortStr(r); err != nil {
return return
} }
if err = binary.Read(r, binary.BigEndian, &bits); err != nil { if err = binary.Read(r, binary.BigEndian, &bits); err != nil {
return return
} }
msg.NoWait = (bits&(1<<0) > 0) msg.NoWait = bits&(1<<0) > 0
return return
} }
type basicCancelOk struct { type basicCancelOk struct {
ConsumerTag string ConsumerTag string `json:"consumerTag"`
} }
func (msg *basicCancelOk) read(r io.Reader) (err error) { func (msg *basicCancelOk) read(r io.Reader) (err error) {
if msg.ConsumerTag, err = readShortstr(r); err != nil { if msg.ConsumerTag, err = readShortStr(r); err != nil {
return return
} }
@@ -910,18 +910,18 @@ func (msg *BasicPublish) read(r io.Reader) (err error) {
return return
} }
if msg.Exchange, err = readShortstr(r); err != nil { if msg.Exchange, err = readShortStr(r); err != nil {
return return
} }
if msg.RoutingKey, err = readShortstr(r); err != nil { if msg.RoutingKey, err = readShortStr(r); err != nil {
return return
} }
if err = binary.Read(r, binary.BigEndian, &bits); err != nil { if err = binary.Read(r, binary.BigEndian, &bits); err != nil {
return return
} }
msg.Mandatory = (bits&(1<<0) > 0) msg.Mandatory = bits&(1<<0) > 0
msg.Immediate = (bits&(1<<1) > 0) msg.Immediate = bits&(1<<1) > 0
return return
} }
@@ -949,13 +949,13 @@ func (msg *basicReturn) read(r io.Reader) (err error) {
return return
} }
if msg.ReplyText, err = readShortstr(r); err != nil { if msg.ReplyText, err = readShortStr(r); err != nil {
return return
} }
if msg.Exchange, err = readShortstr(r); err != nil { if msg.Exchange, err = readShortStr(r); err != nil {
return return
} }
if msg.RoutingKey, err = readShortstr(r); err != nil { if msg.RoutingKey, err = readShortStr(r); err != nil {
return return
} }
@@ -983,7 +983,7 @@ func (msg *BasicDeliver) setContent(props Properties, body []byte) {
func (msg *BasicDeliver) read(r io.Reader) (err error) { func (msg *BasicDeliver) read(r io.Reader) (err error) {
var bits byte var bits byte
if msg.ConsumerTag, err = readShortstr(r); err != nil { if msg.ConsumerTag, err = readShortStr(r); err != nil {
return return
} }
@@ -994,12 +994,12 @@ func (msg *BasicDeliver) read(r io.Reader) (err error) {
if err = binary.Read(r, binary.BigEndian, &bits); err != nil { if err = binary.Read(r, binary.BigEndian, &bits); err != nil {
return return
} }
msg.Redelivered = (bits&(1<<0) > 0) msg.Redelivered = bits&(1<<0) > 0
if msg.Exchange, err = readShortstr(r); err != nil { if msg.Exchange, err = readShortStr(r); err != nil {
return return
} }
if msg.RoutingKey, err = readShortstr(r); err != nil { if msg.RoutingKey, err = readShortStr(r); err != nil {
return return
} }
@@ -1019,14 +1019,14 @@ func (msg *basicGet) read(r io.Reader) (err error) {
return return
} }
if msg.Queue, err = readShortstr(r); err != nil { if msg.Queue, err = readShortStr(r); err != nil {
return return
} }
if err = binary.Read(r, binary.BigEndian, &bits); err != nil { if err = binary.Read(r, binary.BigEndian, &bits); err != nil {
return return
} }
msg.NoAck = (bits&(1<<0) > 0) msg.NoAck = bits&(1<<0) > 0
return return
} }
@@ -1059,12 +1059,12 @@ func (msg *basicGetOk) read(r io.Reader) (err error) {
if err = binary.Read(r, binary.BigEndian, &bits); err != nil { if err = binary.Read(r, binary.BigEndian, &bits); err != nil {
return return
} }
msg.Redelivered = (bits&(1<<0) > 0) msg.Redelivered = bits&(1<<0) > 0
if msg.Exchange, err = readShortstr(r); err != nil { if msg.Exchange, err = readShortStr(r); err != nil {
return return
} }
if msg.RoutingKey, err = readShortstr(r); err != nil { if msg.RoutingKey, err = readShortStr(r); err != nil {
return return
} }
@@ -1081,7 +1081,7 @@ type basicGetEmpty struct {
func (msg *basicGetEmpty) read(r io.Reader) (err error) { func (msg *basicGetEmpty) read(r io.Reader) (err error) {
if msg.reserved1, err = readShortstr(r); err != nil { if msg.reserved1, err = readShortStr(r); err != nil {
return return
} }
@@ -1103,7 +1103,7 @@ func (msg *basicAck) read(r io.Reader) (err error) {
if err = binary.Read(r, binary.BigEndian, &bits); err != nil { if err = binary.Read(r, binary.BigEndian, &bits); err != nil {
return return
} }
msg.Multiple = (bits&(1<<0) > 0) msg.Multiple = bits&(1<<0) > 0
return return
} }
@@ -1123,7 +1123,7 @@ func (msg *basicReject) read(r io.Reader) (err error) {
if err = binary.Read(r, binary.BigEndian, &bits); err != nil { if err = binary.Read(r, binary.BigEndian, &bits); err != nil {
return return
} }
msg.Requeue = (bits&(1<<0) > 0) msg.Requeue = bits&(1<<0) > 0
return return
} }
@@ -1138,7 +1138,7 @@ func (msg *basicRecoverAsync) read(r io.Reader) (err error) {
if err = binary.Read(r, binary.BigEndian, &bits); err != nil { if err = binary.Read(r, binary.BigEndian, &bits); err != nil {
return return
} }
msg.Requeue = (bits&(1<<0) > 0) msg.Requeue = bits&(1<<0) > 0
return return
} }
@@ -1153,7 +1153,7 @@ func (msg *basicRecover) read(r io.Reader) (err error) {
if err = binary.Read(r, binary.BigEndian, &bits); err != nil { if err = binary.Read(r, binary.BigEndian, &bits); err != nil {
return return
} }
msg.Requeue = (bits&(1<<0) > 0) msg.Requeue = bits&(1<<0) > 0
return return
} }
@@ -1182,8 +1182,8 @@ func (msg *basicNack) read(r io.Reader) (err error) {
if err = binary.Read(r, binary.BigEndian, &bits); err != nil { if err = binary.Read(r, binary.BigEndian, &bits); err != nil {
return return
} }
msg.Multiple = (bits&(1<<0) > 0) msg.Multiple = bits&(1<<0) > 0
msg.Requeue = (bits&(1<<1) > 0) msg.Requeue = bits&(1<<1) > 0
return return
} }
@@ -1246,7 +1246,7 @@ func (msg *confirmSelect) read(r io.Reader) (err error) {
if err = binary.Read(r, binary.BigEndian, &bits); err != nil { if err = binary.Read(r, binary.BigEndian, &bits); err != nil {
return return
} }
msg.Nowait = (bits&(1<<0) > 0) msg.Nowait = bits&(1<<0) > 0
return return
} }

View File

@@ -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/expect10/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/expect16/http/\* expect

View File

@@ -4,6 +4,7 @@ go 1.17
require ( require (
github.com/beevik/etree v1.1.0 github.com/beevik/etree v1.1.0
github.com/google/martian v2.1.0+incompatible
github.com/mertyildiran/gqlparser/v2 v2.4.6 github.com/mertyildiran/gqlparser/v2 v2.4.6
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0
github.com/up9inc/mizu/tap/api v0.0.0 github.com/up9inc/mizu/tap/api v0.0.0
@@ -12,7 +13,6 @@ require (
require ( require (
github.com/davecgh/go-spew v1.1.1 // indirect github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/martian v2.1.0+incompatible // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/up9inc/mizu/tap/dbgctl v0.0.0 // indirect github.com/up9inc/mizu/tap/dbgctl v0.0.0 // indirect
golang.org/x/text v0.3.7 // indirect golang.org/x/text v0.3.7 // indirect

View File

@@ -18,10 +18,6 @@ func filterAndEmit(item *api.OutputChannelItem, emitter api.Emitter, options *ap
return return
} }
if options.EnableRedaction {
FilterSensitiveData(item, options)
}
replaceForwardedFor(item) replaceForwardedFor(item)
emitter.Emit(item) emitter.Emit(item)
@@ -32,7 +28,7 @@ func replaceForwardedFor(item *api.OutputChannelItem) {
return return
} }
request := item.Pair.Request.Payload.(api.HTTPPayload).Data.(*http.Request) request := item.Pair.Request.Payload.(HTTPPayload).Data.(*http.Request)
forwardedFor := request.Header.Get("X-Forwarded-For") forwardedFor := request.Header.Get("X-Forwarded-For")
if forwardedFor == "" { if forwardedFor == "" {

View File

@@ -6,13 +6,16 @@ import (
"reflect" "reflect"
"sort" "sort"
"strconv" "strconv"
"strings"
"github.com/up9inc/mizu/tap/api" "github.com/up9inc/mizu/tap/api"
) )
func mapSliceRebuildAsMap(mapSlice []interface{}) (newMap map[string]interface{}) { func mapSliceRebuildAsMap(mapSlice []interface{}) (newMap map[string]interface{}) {
newMap = make(map[string]interface{}) newMap = make(map[string]interface{})
for _, item := range mapSlice {
mergedMapSlice := mapSliceMergeRepeatedKeys(mapSlice)
for _, item := range mergedMapSlice {
h := item.(map[string]interface{}) h := item.(map[string]interface{})
newMap[h["name"].(string)] = h["value"] newMap[h["name"].(string)] = h["value"]
} }
@@ -20,6 +23,28 @@ func mapSliceRebuildAsMap(mapSlice []interface{}) (newMap map[string]interface{}
return return
} }
func mapSliceRebuildAsMergedMap(mapSlice []interface{}) (newMap map[string]interface{}) {
newMap = make(map[string]interface{})
mergedMapSlice := mapSliceMergeRepeatedKeys(mapSlice)
for _, item := range mergedMapSlice {
h := item.(map[string]interface{})
if valuesInterface, ok := h["value"].([]interface{}); ok {
var values []string
for _, valueInterface := range valuesInterface {
values = append(values, valueInterface.(string))
}
newMap[h["name"].(string)] = strings.Join(values, ",")
} else {
newMap[h["name"].(string)] = h["value"]
}
}
return
}
func mapSliceMergeRepeatedKeys(mapSlice []interface{}) (newMapSlice []interface{}) { func mapSliceMergeRepeatedKeys(mapSlice []interface{}) (newMapSlice []interface{}) {
newMapSlice = make([]interface{}, 0) newMapSlice = make([]interface{}, 0)
valuesMap := make(map[string][]interface{}) valuesMap := make(map[string][]interface{})
@@ -47,6 +72,24 @@ func mapSliceMergeRepeatedKeys(mapSlice []interface{}) (newMapSlice []interface{
return return
} }
func representMapAsTable(mapToTable map[string]interface{}, selectorPrefix string) (representation string) {
var table []api.TableData
keys := make([]string, 0, len(mapToTable))
for k := range mapToTable {
keys = append(keys, k)
}
sort.Strings(keys)
for _, key := range keys {
table = append(table, createTableForKey(key, mapToTable[key], selectorPrefix)...)
}
obj, _ := json.Marshal(table)
representation = string(obj)
return
}
func representMapSliceAsTable(mapSlice []interface{}, selectorPrefix string) (representation string) { func representMapSliceAsTable(mapSlice []interface{}, selectorPrefix string) (representation string) {
var table []api.TableData var table []api.TableData
for _, item := range mapSlice { for _, item := range mapSlice {
@@ -54,34 +97,7 @@ func representMapSliceAsTable(mapSlice []interface{}, selectorPrefix string) (re
key := h["name"].(string) key := h["name"].(string)
value := h["value"] value := h["value"]
var reflectKind reflect.Kind table = append(table, createTableForKey(key, value, selectorPrefix)...)
reflectType := reflect.TypeOf(value)
if reflectType == nil {
reflectKind = reflect.Interface
} else {
reflectKind = reflect.TypeOf(value).Kind()
}
switch reflectKind {
case reflect.Slice:
fallthrough
case reflect.Array:
for i, el := range value.([]interface{}) {
selector := fmt.Sprintf("%s.%s[%d]", selectorPrefix, key, i)
table = append(table, api.TableData{
Name: fmt.Sprintf("%s [%d]", key, i),
Value: el,
Selector: selector,
})
}
default:
selector := fmt.Sprintf("%s[\"%s\"]", selectorPrefix, key)
table = append(table, api.TableData{
Name: key,
Value: value,
Selector: selector,
})
}
} }
obj, _ := json.Marshal(table) obj, _ := json.Marshal(table)
@@ -89,6 +105,41 @@ func representMapSliceAsTable(mapSlice []interface{}, selectorPrefix string) (re
return return
} }
func createTableForKey(key string, value interface{}, selectorPrefix string) []api.TableData {
var table []api.TableData
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:
fallthrough
case reflect.Array:
for i, el := range value.([]interface{}) {
selector := fmt.Sprintf("%s.%s[%d]", selectorPrefix, key, i)
table = append(table, api.TableData{
Name: fmt.Sprintf("%s [%d]", key, i),
Value: el,
Selector: selector,
})
}
default:
selector := fmt.Sprintf("%s[\"%s\"]", selectorPrefix, key)
table = append(table, api.TableData{
Name: key,
Value: value,
Selector: selector,
})
}
return table
}
func representSliceAsTable(slice []interface{}, selectorPrefix string) (representation string) { func representSliceAsTable(slice []interface{}, selectorPrefix string) (representation string) {
var table []api.TableData var table []api.TableData
for i, item := range slice { for i, item := range slice {

View File

@@ -91,7 +91,7 @@ func (ga *Http2Assembler) readMessage() (streamID uint32, messageHTTP1 interface
// Exactly one Framer is used for each half connection. // Exactly one Framer is used for each half connection.
// (Instead of creating a new Framer for each ReadFrame operation) // (Instead of creating a new Framer for each ReadFrame operation)
// This is needed in order to decompress the headers, // This is needed in order to decompress the headers,
// because the compression context is updated with each requests/response. // because the compression context is updated with each request/response.
frame, err := ga.framer.ReadFrame() frame, err := ga.framer.ReadFrame()
if err != nil { if err != nil {
return return

View File

@@ -14,12 +14,14 @@ import (
"github.com/up9inc/mizu/tap/api" "github.com/up9inc/mizu/tap/api"
) )
var http10protocol api.Protocol = api.Protocol{ var http10protocol = api.Protocol{
Name: "http", ProtocolSummary: api.ProtocolSummary{
Name: "http",
Version: "1.0",
Abbreviation: "HTTP",
},
LongName: "Hypertext Transfer Protocol -- HTTP/1.0", LongName: "Hypertext Transfer Protocol -- HTTP/1.0",
Abbreviation: "HTTP",
Macro: "http", Macro: "http",
Version: "1.0",
BackgroundColor: "#205cf5", BackgroundColor: "#205cf5",
ForegroundColor: "#ffffff", ForegroundColor: "#ffffff",
FontSize: 12, FontSize: 12,
@@ -28,12 +30,14 @@ var http10protocol api.Protocol = api.Protocol{
Priority: 0, Priority: 0,
} }
var http11protocol api.Protocol = api.Protocol{ var http11protocol = api.Protocol{
Name: "http", ProtocolSummary: api.ProtocolSummary{
Name: "http",
Version: "1.1",
Abbreviation: "HTTP",
},
LongName: "Hypertext Transfer Protocol -- HTTP/1.1", LongName: "Hypertext Transfer Protocol -- HTTP/1.1",
Abbreviation: "HTTP",
Macro: "http", Macro: "http",
Version: "1.1",
BackgroundColor: "#205cf5", BackgroundColor: "#205cf5",
ForegroundColor: "#ffffff", ForegroundColor: "#ffffff",
FontSize: 12, FontSize: 12,
@@ -42,12 +46,14 @@ var http11protocol api.Protocol = api.Protocol{
Priority: 0, Priority: 0,
} }
var http2Protocol api.Protocol = api.Protocol{ var http2Protocol = api.Protocol{
Name: "http", ProtocolSummary: api.ProtocolSummary{
Name: "http",
Version: "2.0",
Abbreviation: "HTTP/2",
},
LongName: "Hypertext Transfer Protocol Version 2 (HTTP/2)", LongName: "Hypertext Transfer Protocol Version 2 (HTTP/2)",
Abbreviation: "HTTP/2",
Macro: "http2", Macro: "http2",
Version: "2.0",
BackgroundColor: "#244c5a", BackgroundColor: "#244c5a",
ForegroundColor: "#ffffff", ForegroundColor: "#ffffff",
FontSize: 11, FontSize: 11,
@@ -56,12 +62,14 @@ var http2Protocol api.Protocol = api.Protocol{
Priority: 0, Priority: 0,
} }
var grpcProtocol api.Protocol = api.Protocol{ var grpcProtocol = api.Protocol{
Name: "http", ProtocolSummary: api.ProtocolSummary{
Name: "http",
Version: "2.0",
Abbreviation: "gRPC",
},
LongName: "Hypertext Transfer Protocol Version 2 (HTTP/2) [ gRPC over HTTP/2 ]", LongName: "Hypertext Transfer Protocol Version 2 (HTTP/2) [ gRPC over HTTP/2 ]",
Abbreviation: "gRPC",
Macro: "grpc", Macro: "grpc",
Version: "2.0",
BackgroundColor: "#244c5a", BackgroundColor: "#244c5a",
ForegroundColor: "#ffffff", ForegroundColor: "#ffffff",
FontSize: 11, FontSize: 11,
@@ -70,12 +78,14 @@ var grpcProtocol api.Protocol = api.Protocol{
Priority: 0, Priority: 0,
} }
var graphQL1Protocol api.Protocol = api.Protocol{ var graphQL1Protocol = api.Protocol{
Name: "http", ProtocolSummary: api.ProtocolSummary{
Name: "http",
Version: "1.1",
Abbreviation: "GQL",
},
LongName: "Hypertext Transfer Protocol -- HTTP/1.1 [ GraphQL over HTTP/1.1 ]", LongName: "Hypertext Transfer Protocol -- HTTP/1.1 [ GraphQL over HTTP/1.1 ]",
Abbreviation: "GQL",
Macro: "gql", Macro: "gql",
Version: "1.1",
BackgroundColor: "#e10098", BackgroundColor: "#e10098",
ForegroundColor: "#ffffff", ForegroundColor: "#ffffff",
FontSize: 12, FontSize: 12,
@@ -84,12 +94,14 @@ var graphQL1Protocol api.Protocol = api.Protocol{
Priority: 0, Priority: 0,
} }
var graphQL2Protocol api.Protocol = api.Protocol{ var graphQL2Protocol = api.Protocol{
Name: "http", ProtocolSummary: api.ProtocolSummary{
Name: "http",
Version: "2.0",
Abbreviation: "GQL",
},
LongName: "Hypertext Transfer Protocol Version 2 (HTTP/2) [ GraphQL over HTTP/2 ]", LongName: "Hypertext Transfer Protocol Version 2 (HTTP/2) [ GraphQL over HTTP/2 ]",
Abbreviation: "GQL",
Macro: "gql", Macro: "gql",
Version: "2.0",
BackgroundColor: "#e10098", BackgroundColor: "#e10098",
ForegroundColor: "#ffffff", ForegroundColor: "#ffffff",
FontSize: 12, FontSize: 12,
@@ -98,6 +110,15 @@ var graphQL2Protocol api.Protocol = api.Protocol{
Priority: 0, Priority: 0,
} }
var protocolsMap = map[string]*api.Protocol{
http10protocol.ToString(): &http10protocol,
http11protocol.ToString(): &http11protocol,
http2Protocol.ToString(): &http2Protocol,
grpcProtocol.ToString(): &grpcProtocol,
graphQL1Protocol.ToString(): &graphQL1Protocol,
graphQL2Protocol.ToString(): &graphQL2Protocol,
}
const ( const (
TypeHttpRequest = iota TypeHttpRequest = iota
TypeHttpResponse TypeHttpResponse
@@ -109,6 +130,10 @@ func (d dissecting) Register(extension *api.Extension) {
extension.Protocol = &http11protocol extension.Protocol = &http11protocol
} }
func (d dissecting) GetProtocols() map[string]*api.Protocol {
return protocolsMap
}
func (d dissecting) Ping() { func (d dissecting) Ping() {
log.Printf("pong %s", http11protocol.Name) log.Printf("pong %s", http11protocol.Name)
} }
@@ -261,27 +286,21 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string,
reqDetails["pathSegments"] = strings.Split(path, "/")[1:] reqDetails["pathSegments"] = strings.Split(path, "/")[1:]
// Rearrange the maps for the querying // Rearrange the maps for the querying
reqDetails["_headers"] = reqDetails["headers"] reqDetails["headers"] = mapSliceRebuildAsMergedMap(reqDetails["headers"].([]interface{}))
reqDetails["headers"] = mapSliceRebuildAsMap(reqDetails["_headers"].([]interface{})) resDetails["headers"] = mapSliceRebuildAsMergedMap(resDetails["headers"].([]interface{}))
resDetails["_headers"] = resDetails["headers"]
resDetails["headers"] = mapSliceRebuildAsMap(resDetails["_headers"].([]interface{}))
reqDetails["_cookies"] = reqDetails["cookies"] reqDetails["cookies"] = mapSliceRebuildAsMergedMap(reqDetails["cookies"].([]interface{}))
reqDetails["cookies"] = mapSliceRebuildAsMap(reqDetails["_cookies"].([]interface{})) resDetails["cookies"] = mapSliceRebuildAsMergedMap(resDetails["cookies"].([]interface{}))
resDetails["_cookies"] = resDetails["cookies"]
resDetails["cookies"] = mapSliceRebuildAsMap(resDetails["_cookies"].([]interface{}))
reqDetails["_queryString"] = reqDetails["queryString"] reqDetails["queryString"] = mapSliceRebuildAsMap(reqDetails["queryString"].([]interface{}))
reqDetails["_queryStringMerged"] = mapSliceMergeRepeatedKeys(reqDetails["_queryString"].([]interface{}))
reqDetails["queryString"] = mapSliceRebuildAsMap(reqDetails["_queryStringMerged"].([]interface{}))
elapsedTime := item.Pair.Response.CaptureTime.Sub(item.Pair.Request.CaptureTime).Round(time.Millisecond).Milliseconds() elapsedTime := item.Pair.Response.CaptureTime.Sub(item.Pair.Request.CaptureTime).Round(time.Millisecond).Milliseconds()
if elapsedTime < 0 { if elapsedTime < 0 {
elapsedTime = 0 elapsedTime = 0
} }
httpPair, _ := json.Marshal(item.Pair)
return &api.Entry{ return &api.Entry{
Protocol: item.Protocol, Protocol: item.Protocol.ProtocolSummary,
Capture: item.Capture, Capture: item.Capture,
Source: &api.TCP{ Source: &api.TCP{
Name: resolvedSource, Name: resolvedSource,
@@ -302,7 +321,6 @@ func (d dissecting) Analyze(item *api.OutputChannelItem, resolvedSource string,
Timestamp: item.Timestamp, Timestamp: item.Timestamp,
StartTime: item.Pair.Request.CaptureTime, StartTime: item.Pair.Request.CaptureTime,
ElapsedTime: elapsedTime, ElapsedTime: elapsedTime,
HTTPPair: string(httpPair),
} }
} }
@@ -315,22 +333,20 @@ func (d dissecting) Summarize(entry *api.Entry) *api.BaseEntry {
statusQuery := fmt.Sprintf(`response.status == %d`, status) statusQuery := fmt.Sprintf(`response.status == %d`, status)
return &api.BaseEntry{ return &api.BaseEntry{
Id: entry.Id, Id: entry.Id,
Protocol: entry.Protocol, Protocol: *protocolsMap[entry.Protocol.ToString()],
Capture: entry.Capture, Capture: entry.Capture,
Summary: summary, Summary: summary,
SummaryQuery: summaryQuery, SummaryQuery: summaryQuery,
Status: status, Status: status,
StatusQuery: statusQuery, StatusQuery: statusQuery,
Method: method, Method: method,
MethodQuery: methodQuery, MethodQuery: methodQuery,
Timestamp: entry.Timestamp, Timestamp: entry.Timestamp,
Source: entry.Source, Source: entry.Source,
Destination: entry.Destination, Destination: entry.Destination,
IsOutgoing: entry.Outgoing, IsOutgoing: entry.Outgoing,
Latency: entry.ElapsedTime, Latency: entry.ElapsedTime,
Rules: entry.Rules,
ContractStatus: entry.ContractStatus,
} }
} }
@@ -375,19 +391,19 @@ func representRequest(request map[string]interface{}) (repRequest []interface{})
repRequest = append(repRequest, api.SectionData{ repRequest = append(repRequest, api.SectionData{
Type: api.TABLE, Type: api.TABLE,
Title: "Headers", Title: "Headers",
Data: representMapSliceAsTable(request["_headers"].([]interface{}), `request.headers`), Data: representMapAsTable(request["headers"].(map[string]interface{}), `request.headers`),
}) })
repRequest = append(repRequest, api.SectionData{ repRequest = append(repRequest, api.SectionData{
Type: api.TABLE, Type: api.TABLE,
Title: "Cookies", Title: "Cookies",
Data: representMapSliceAsTable(request["_cookies"].([]interface{}), `request.cookies`), Data: representMapAsTable(request["cookies"].(map[string]interface{}), `request.cookies`),
}) })
repRequest = append(repRequest, api.SectionData{ repRequest = append(repRequest, api.SectionData{
Type: api.TABLE, Type: api.TABLE,
Title: "Query String", Title: "Query String",
Data: representMapSliceAsTable(request["_queryStringMerged"].([]interface{}), `request.queryString`), Data: representMapAsTable(request["queryString"].(map[string]interface{}), `request.queryString`),
}) })
postData, _ := request["postData"].(map[string]interface{}) postData, _ := request["postData"].(map[string]interface{})
@@ -463,13 +479,13 @@ func representResponse(response map[string]interface{}) (repResponse []interface
repResponse = append(repResponse, api.SectionData{ repResponse = append(repResponse, api.SectionData{
Type: api.TABLE, Type: api.TABLE,
Title: "Headers", Title: "Headers",
Data: representMapSliceAsTable(response["_headers"].([]interface{}), `response.headers`), Data: representMapAsTable(response["headers"].(map[string]interface{}), `response.headers`),
}) })
repResponse = append(repResponse, api.SectionData{ repResponse = append(repResponse, api.SectionData{
Type: api.TABLE, Type: api.TABLE,
Title: "Cookies", Title: "Cookies",
Data: representMapSliceAsTable(response["_cookies"].([]interface{}), `response.cookies`), Data: representMapAsTable(response["cookies"].(map[string]interface{}), `response.cookies`),
}) })
content, _ := response["content"].(map[string]interface{}) content, _ := response["content"].(map[string]interface{})
@@ -505,10 +521,10 @@ func (d dissecting) Represent(request map[string]interface{}, response map[strin
func (d dissecting) Macros() map[string]string { func (d dissecting) Macros() map[string]string {
return map[string]string{ return map[string]string{
`http`: fmt.Sprintf(`proto.name == "%s" and proto.version.startsWith("%c")`, http11protocol.Name, http11protocol.Version[0]), `http`: fmt.Sprintf(`protocol.abbr == "%s"`, http11protocol.Abbreviation),
`http2`: fmt.Sprintf(`proto.name == "%s" and proto.version == "%s"`, http11protocol.Name, http2Protocol.Version), `http2`: fmt.Sprintf(`protocol.abbr == "%s"`, http2Protocol.Abbreviation),
`grpc`: fmt.Sprintf(`proto.name == "%s" and proto.version == "%s" and proto.macro == "%s"`, http11protocol.Name, grpcProtocol.Version, grpcProtocol.Macro), `grpc`: fmt.Sprintf(`protocol.abbr == "%s"`, grpcProtocol.Abbreviation),
`gql`: fmt.Sprintf(`proto.name == "%s" and proto.macro == "%s"`, graphQL1Protocol.Name, graphQL1Protocol.Macro), `gql`: fmt.Sprintf(`protocol.abbr == "%s"`, graphQL1Protocol.Abbreviation),
} }
} }

View File

@@ -44,10 +44,10 @@ func TestRegister(t *testing.T) {
func TestMacros(t *testing.T) { func TestMacros(t *testing.T) {
expectedMacros := map[string]string{ expectedMacros := map[string]string{
"http": `proto.name == "http" and proto.version.startsWith("1")`, "http": `protocol.abbr == "HTTP"`,
"http2": `proto.name == "http" and proto.version == "2.0"`, "http2": `protocol.abbr == "HTTP/2"`,
"grpc": `proto.name == "http" and proto.version == "2.0" and proto.macro == "grpc"`, "grpc": `protocol.abbr == "gRPC"`,
"gql": `proto.name == "http" and proto.macro == "gql"`, "gql": `protocol.abbr == "GQL"`,
} }
dissector := NewDissector() dissector := NewDissector()
macros := dissector.Macros() macros := dissector.Macros()

View File

@@ -29,7 +29,7 @@ func (matcher *requestResponseMatcher) registerRequest(ident string, request *ht
IsRequest: true, IsRequest: true,
CaptureTime: captureTime, CaptureTime: captureTime,
CaptureSize: captureSize, CaptureSize: captureSize,
Payload: api.HTTPPayload{ Payload: HTTPPayload{
Type: TypeHttpRequest, Type: TypeHttpRequest,
Data: request, Data: request,
}, },
@@ -53,7 +53,7 @@ func (matcher *requestResponseMatcher) registerResponse(ident string, response *
IsRequest: false, IsRequest: false,
CaptureTime: captureTime, CaptureTime: captureTime,
CaptureSize: captureSize, CaptureSize: captureSize,
Payload: api.HTTPPayload{ Payload: HTTPPayload{
Type: TypeHttpResponse, Type: TypeHttpResponse,
Data: response, Data: response,
}, },

View File

@@ -1,36 +1,20 @@
package http package http
import ( import (
"bytes"
"encoding/json"
"encoding/xml"
"errors"
"fmt"
"io/ioutil"
"net/http" "net/http"
"net/url"
"strings" "strings"
"github.com/beevik/etree"
"github.com/up9inc/mizu/tap/api" "github.com/up9inc/mizu/tap/api"
) )
const maskedFieldPlaceholderValue = "[REDACTED]"
const userAgent = "user-agent" const userAgent = "user-agent"
//these values MUST be all lower case and contain no `-` or `_` characters
var personallyIdentifiableDataFields = []string{"token", "authorization", "authentication", "cookie", "userid", "password",
"username", "user", "key", "passcode", "pass", "auth", "authtoken", "jwt",
"bearer", "clientid", "clientsecret", "redirecturi", "phonenumber",
"zip", "zipcode", "address", "country", "firstname", "lastname",
"middlename", "fname", "lname", "birthdate"}
func IsIgnoredUserAgent(item *api.OutputChannelItem, options *api.TrafficFilteringOptions) bool { func IsIgnoredUserAgent(item *api.OutputChannelItem, options *api.TrafficFilteringOptions) bool {
if item.Protocol.Name != "http" { if item.Protocol.Name != "http" {
return false return false
} }
request := item.Pair.Request.Payload.(api.HTTPPayload).Data.(*http.Request) request := item.Pair.Request.Payload.(HTTPPayload).Data.(*http.Request)
for headerKey, headerValues := range request.Header { for headerKey, headerValues := range request.Header {
if strings.ToLower(headerKey) == userAgent { if strings.ToLower(headerKey) == userAgent {
@@ -48,192 +32,3 @@ func IsIgnoredUserAgent(item *api.OutputChannelItem, options *api.TrafficFilteri
return false return false
} }
func FilterSensitiveData(item *api.OutputChannelItem, options *api.TrafficFilteringOptions) {
request := item.Pair.Request.Payload.(api.HTTPPayload).Data.(*http.Request)
response := item.Pair.Response.Payload.(api.HTTPPayload).Data.(*http.Response)
filterHeaders(&request.Header)
filterHeaders(&response.Header)
filterUrl(request.URL)
filterRequestBody(request, options)
filterResponseBody(response, options)
}
func filterRequestBody(request *http.Request, options *api.TrafficFilteringOptions) {
contenType := getContentTypeHeaderValue(request.Header)
body, err := ioutil.ReadAll(request.Body)
if err != nil {
return
}
filteredBody, err := filterHttpBody([]byte(body), contenType, options)
if err == nil {
request.Body = ioutil.NopCloser(bytes.NewBuffer(filteredBody))
} else {
request.Body = ioutil.NopCloser(bytes.NewBuffer(body))
}
}
func filterResponseBody(response *http.Response, options *api.TrafficFilteringOptions) {
contentType := getContentTypeHeaderValue(response.Header)
body, err := ioutil.ReadAll(response.Body)
if err != nil {
return
}
filteredBody, err := filterHttpBody([]byte(body), contentType, options)
if err == nil {
response.Body = ioutil.NopCloser(bytes.NewBuffer(filteredBody))
} else {
response.Body = ioutil.NopCloser(bytes.NewBuffer(body))
}
}
func filterHeaders(headers *http.Header) {
for key := range *headers {
if strings.ToLower(key) == userAgent {
continue
}
if strings.ToLower(key) == "cookie" {
headers.Del(key)
} else if isFieldNameSensitive(key) {
headers.Set(key, maskedFieldPlaceholderValue)
}
}
}
func getContentTypeHeaderValue(headers http.Header) string {
for key := range headers {
if strings.ToLower(key) == "content-type" {
return headers.Get(key)
}
}
return ""
}
func isFieldNameSensitive(fieldName string) bool {
if fieldName == ":authority" {
return false
}
name := strings.ToLower(fieldName)
name = strings.ReplaceAll(name, "_", "")
name = strings.ReplaceAll(name, "-", "")
name = strings.ReplaceAll(name, " ", "")
for _, sensitiveField := range personallyIdentifiableDataFields {
if strings.Contains(name, sensitiveField) {
return true
}
}
return false
}
func filterHttpBody(bytes []byte, contentType string, options *api.TrafficFilteringOptions) ([]byte, error) {
mimeType := strings.Split(contentType, ";")[0]
switch strings.ToLower(mimeType) {
case "application/json":
return filterJsonBody(bytes)
case "text/html":
fallthrough
case "application/xhtml+xml":
fallthrough
case "text/xml":
fallthrough
case "application/xml":
return filterXmlEtree(bytes)
case "text/plain":
if options != nil && options.PlainTextMaskingRegexes != nil {
return filterPlainText(bytes, options), nil
}
}
return bytes, nil
}
func filterPlainText(bytes []byte, options *api.TrafficFilteringOptions) []byte {
for _, regex := range options.PlainTextMaskingRegexes {
bytes = regex.ReplaceAll(bytes, []byte(maskedFieldPlaceholderValue))
}
return bytes
}
func filterXmlEtree(bytes []byte) ([]byte, error) {
if !IsValidXML(bytes) {
return nil, errors.New("Invalid XML")
}
xmlDoc := etree.NewDocument()
err := xmlDoc.ReadFromBytes(bytes)
if err != nil {
return nil, err
} else {
filterXmlElement(xmlDoc.Root())
}
return xmlDoc.WriteToBytes()
}
func IsValidXML(data []byte) bool {
return xml.Unmarshal(data, new(interface{})) == nil
}
func filterXmlElement(element *etree.Element) {
for i, attribute := range element.Attr {
if isFieldNameSensitive(attribute.Key) {
element.Attr[i].Value = maskedFieldPlaceholderValue
}
}
if element.ChildElements() == nil || len(element.ChildElements()) == 0 {
if isFieldNameSensitive(element.Tag) {
element.SetText(maskedFieldPlaceholderValue)
}
} else {
for _, element := range element.ChildElements() {
filterXmlElement(element)
}
}
}
func filterJsonBody(bytes []byte) ([]byte, error) {
var bodyJsonMap map[string]interface{}
err := json.Unmarshal(bytes, &bodyJsonMap)
if err != nil {
return nil, err
}
filterJsonMap(bodyJsonMap)
return json.Marshal(bodyJsonMap)
}
func filterJsonMap(jsonMap map[string]interface{}) {
for key, value := range jsonMap {
// Do not replace nil values with maskedFieldPlaceholderValue
if value == nil {
continue
}
nestedMap, isNested := value.(map[string]interface{})
if isNested {
filterJsonMap(nestedMap)
} else {
if isFieldNameSensitive(key) {
jsonMap[key] = maskedFieldPlaceholderValue
}
}
}
}
func filterUrl(url *url.URL) {
if len(url.RawQuery) > 0 {
newQueryArgs := make([]string, 0)
for urlQueryParamName, urlQueryParamValues := range url.Query() {
newValues := urlQueryParamValues
if isFieldNameSensitive(urlQueryParamName) {
newValues = []string{maskedFieldPlaceholderValue}
}
for _, paramValue := range newValues {
newQueryArgs = append(newQueryArgs, fmt.Sprintf("%s=%s", urlQueryParamName, paramValue))
}
}
url.RawQuery = strings.Join(newQueryArgs, "&")
}
}

View File

@@ -0,0 +1,100 @@
package http
import (
"encoding/json"
"errors"
"fmt"
"net/http"
"sort"
"github.com/google/martian/har"
)
type HTTPPayload struct {
Type uint8
Data interface{}
}
type HTTPPayloader interface {
MarshalJSON() ([]byte, error)
}
type HTTPWrapper struct {
Method string `json:"method"`
Url string `json:"url"`
Details interface{} `json:"details"`
}
func (h HTTPPayload) MarshalJSON() ([]byte, error) {
switch h.Type {
case TypeHttpRequest:
harRequest, err := har.NewRequest(h.Data.(*http.Request), true)
if err != nil {
return nil, errors.New("Failed converting request to HAR")
}
sort.Slice(harRequest.Headers, func(i, j int) bool {
if harRequest.Headers[i].Name < harRequest.Headers[j].Name {
return true
}
if harRequest.Headers[i].Name > harRequest.Headers[j].Name {
return false
}
return harRequest.Headers[i].Value < harRequest.Headers[j].Value
})
sort.Slice(harRequest.QueryString, func(i, j int) bool {
if harRequest.QueryString[i].Name < harRequest.QueryString[j].Name {
return true
}
if harRequest.QueryString[i].Name > harRequest.QueryString[j].Name {
return false
}
return harRequest.QueryString[i].Value < harRequest.QueryString[j].Value
})
if harRequest.PostData != nil {
sort.Slice(harRequest.PostData.Params, func(i, j int) bool {
if harRequest.PostData.Params[i].Name < harRequest.PostData.Params[j].Name {
return true
}
if harRequest.PostData.Params[i].Name > harRequest.PostData.Params[j].Name {
return false
}
return harRequest.PostData.Params[i].Value < harRequest.PostData.Params[j].Value
})
}
return json.Marshal(&HTTPWrapper{
Method: harRequest.Method,
Url: "",
Details: harRequest,
})
case TypeHttpResponse:
harResponse, err := har.NewResponse(h.Data.(*http.Response), true)
if err != nil {
return nil, errors.New("Failed converting response to HAR")
}
sort.Slice(harResponse.Headers, func(i, j int) bool {
if harResponse.Headers[i].Name < harResponse.Headers[j].Name {
return true
}
if harResponse.Headers[i].Name > harResponse.Headers[j].Name {
return false
}
return harResponse.Headers[i].Value < harResponse.Headers[j].Value
})
sort.Slice(harResponse.Cookies, func(i, j int) bool {
if harResponse.Cookies[i].Name < harResponse.Cookies[j].Name {
return true
}
if harResponse.Cookies[i].Name > harResponse.Cookies[j].Name {
return false
}
return harResponse.Cookies[i].Value < harResponse.Cookies[j].Value
})
return json.Marshal(&HTTPWrapper{
Method: "",
Url: "",
Details: harResponse,
})
default:
panic(fmt.Sprintf("HTTP payload cannot be marshaled: %v", h.Type))
}
}

Some files were not shown because too many files have changed in this diff Show More