Compare commits

..

20 Commits

Author SHA1 Message Date
AmitUp9
10dffd9331 TRA-4419 remove headers from OAS select (#936) 2022-03-28 10:01:57 +03:00
leon-up9
0a800e8d8a passed containerId in the object config (#935)
* passed containerId in the object config

* pkg version

* tmp: run acceptance tests, revert before merge

* reverte

Co-authored-by: Leon <>
2022-03-27 19:41:51 +03:00
RamiBerm
068a4ff86e TRA-4422 line numbers fix (#934)
* fix line numbering in body syntax highlighter

* Packages
2022-03-27 16:17:34 +03:00
leon-up9
c45a869b75 Fix/regration-fixes-24.3 (#933)
* link open in a new tab

* fixed double toast

* added const

* javiers new icon

* epbg img fix

* pkg update

* changed import

* formated

Co-authored-by: Leon <>
2022-03-27 15:47:46 +03:00
leon-up9
0a793cd9e0 added props (#924) 2022-03-27 11:31:40 +03:00
Adrian Gąsior
8d19080c11 Updated Dockerfile and fixed typo in Makefile (#929)
* Updated Dockerfile and fixed typo in Makefile

* PR request

* added small hotfix to basenine
2022-03-27 01:39:50 +03:00
Nimrod Gilboa Markevich
319c3c7a8d Initialize tapper before ws (#932) 2022-03-26 21:25:18 +03:00
M. Mert Yıldıran
0e7704eb15 Bump the version to 0.6.6 and fix the index shift bug that occurs after database truncation (#931) 2022-03-26 18:25:38 +03:00
gadotroee
dbcb776139 no message (#930) 2022-03-26 13:19:04 +03:00
Igor Gov
a3de34f544 Turn OAS feature ON by default (#927)
* Turn OAS feature ON by default
2022-03-24 20:40:16 +02:00
Nimrod Gilboa Markevich
99667984d6 Update tap targets without reinitializing packet source manager (#925) 2022-03-24 15:39:20 +02:00
David Levanon
763b0e7362 quick tls update pods solution (#918)
Update TLS tappers when tapped pods are updated via WS.
2022-03-24 15:21:56 +02:00
AmitUp9
e07e04377f mizu and ui-common version update (#923) 2022-03-24 12:31:08 +02:00
AmitUp9
3c8f63ed92 Feature/UI/tra 4390 status bar banner demo env (#921)
* no message

* banner styling condition added and button text transform disabled

* added prps to container

* build fix
2022-03-24 12:14:31 +02:00
leon-up9
11a2246cb9 Fix/entry-title-responsive-comments (#922)
* Make `EntryTitle` component responsive

* useRequetTextByWidth added

* renamed

Co-authored-by: M. Mert Yildiran <mehmet@up9.com>
Co-authored-by: Leon <>
2022-03-24 12:09:28 +02:00
leon-up9
a2595afd5e changed icon (#920)
Co-authored-by: Leon <>
2022-03-24 10:43:35 +02:00
AmitUp9
0f4710918f TRA-4122 oas gui grooming (#915)
* oas styling
* oas button text change
* ui-common version update
* font fix
* version updating
Co-authored-by: gadotroee <55343099+gadotroee@users.noreply.github.com>
2022-03-23 22:15:04 +02:00
RoyUP9
4bdda920d5 Fix for check command (#916)
* Fix for check command

* empty commit for checks

Co-authored-by: Roee Gadot <roee.gadot@up9.com>
2022-03-23 22:02:29 +02:00
Adrian Gąsior
59e6268ddd Refactored Dockerfile (#902)
* Refactored Dockerfile

* PR request
2022-03-23 16:16:37 +02:00
leon-up9
2513e9099f UI/tra 4406 add an information icon (#913)
* information icon added

* new icon and position

* icon changed

* new Ver

* space removed

Co-authored-by: Adam Kol <adam@up9.com>
Co-authored-by: Leon <>
2022-03-23 14:54:51 +02:00
46 changed files with 4310 additions and 1135 deletions

View File

@@ -6,8 +6,7 @@ FROM node:16 AS front-end
WORKDIR /app/ui-build WORKDIR /app/ui-build
COPY ui/package.json . COPY ui/package.json ui/package-lock.json ./
COPY ui/package-lock.json .
RUN npm i RUN npm i
COPY ui . COPY ui .
RUN npm run build RUN npm run build
@@ -15,7 +14,7 @@ RUN npm run build
### Base builder image for native builds architecture ### Base builder image for native builds architecture
FROM golang:1.17-alpine AS builder-native-base FROM golang:1.17-alpine AS builder-native-base
ENV CGO_ENABLED=1 GOOS=linux ENV CGO_ENABLED=1 GOOS=linux
RUN apk add libpcap-dev g++ perl-utils RUN apk add --no-cache libpcap-dev g++ perl-utils
### Intermediate builder image for x86-64 to x86-64 native builds ### Intermediate builder image for x86-64 to x86-64 native builds
@@ -77,17 +76,16 @@ RUN go build -ldflags="-extldflags=-static -s -w \
-X 'github.com/up9inc/mizu/agent/pkg/version.Ver=${VER}'" -o mizuagent . -X 'github.com/up9inc/mizu/agent/pkg/version.Ver=${VER}'" -o mizuagent .
# Download Basenine executable, verify the sha1sum # Download Basenine executable, verify the sha1sum
ADD https://github.com/up9inc/basenine/releases/download/v0.6.5/basenine_linux_${GOARCH} ./basenine_linux_${GOARCH} ADD https://github.com/up9inc/basenine/releases/download/v0.6.6/basenine_linux_${GOARCH} ./basenine_linux_${GOARCH}
ADD https://github.com/up9inc/basenine/releases/download/v0.6.5/basenine_linux_${GOARCH}.sha256 ./basenine_linux_${GOARCH}.sha256 ADD https://github.com/up9inc/basenine/releases/download/v0.6.6/basenine_linux_${GOARCH}.sha256 ./basenine_linux_${GOARCH}.sha256
RUN shasum -a 256 -c basenine_linux_${GOARCH}.sha256
RUN chmod +x ./basenine_linux_${GOARCH}
RUN mv ./basenine_linux_${GOARCH} ./basenine
RUN shasum -a 256 -c basenine_linux_"${GOARCH}".sha256 && \
chmod +x ./basenine_linux_"${GOARCH}" && \
mv ./basenine_linux_"${GOARCH}" ./basenine
### The shipped image ### The shipped image
ARG TARGETARCH=amd64 ARG TARGETARCH=amd64
FROM ${TARGETARCH}/busybox:latest FROM ${TARGETARCH}/busybox:latest
# gin-gonic runs in debug mode without this # gin-gonic runs in debug mode without this
ENV GIN_MODE=release ENV GIN_MODE=release

View File

@@ -73,7 +73,7 @@ clean-agent: ## Clean agent.
clean-cli: ## Clean CLI. clean-cli: ## Clean CLI.
@(cd cli; make clean ; echo "CLI cleanup done" ) @(cd cli; make clean ; echo "CLI cleanup done" )
clean-docker: ## Run clen docker clean-docker: ## Run clean docker
@(echo "DOCKER cleanup - NOT IMPLEMENTED YET " ) @(echo "DOCKER cleanup - NOT IMPLEMENTED YET " )
test-lint: ## Run lint on all modules test-lint: ## Run lint on all modules

View File

@@ -20,7 +20,7 @@ require (
github.com/orcaman/concurrent-map v1.0.0 github.com/orcaman/concurrent-map v1.0.0
github.com/patrickmn/go-cache v2.1.0+incompatible github.com/patrickmn/go-cache v2.1.0+incompatible
github.com/stretchr/testify v1.7.0 github.com/stretchr/testify v1.7.0
github.com/up9inc/basenine/client/go v0.0.0-20220317230530-8472d80307f6 github.com/up9inc/basenine/client/go v0.0.0-20220326121918-785f3061c8ce
github.com/up9inc/mizu/shared v0.0.0 github.com/up9inc/mizu/shared v0.0.0
github.com/up9inc/mizu/tap v0.0.0 github.com/up9inc/mizu/tap v0.0.0
github.com/up9inc/mizu/tap/api v0.0.0 github.com/up9inc/mizu/tap/api v0.0.0

View File

@@ -681,8 +681,8 @@ github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ= github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ=
github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw= github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
github.com/up9inc/basenine/client/go v0.0.0-20220317230530-8472d80307f6 h1:c0aVbLKYeFDAg246+NDgie2y484bsc20NaKLo8ODV3E= github.com/up9inc/basenine/client/go v0.0.0-20220326121918-785f3061c8ce h1:vMTCpKItc9OyTLJXocNaq2NcBU5EnurJgTVOYb8W8dw=
github.com/up9inc/basenine/client/go v0.0.0-20220317230530-8472d80307f6/go.mod h1:SvJGPoa/6erhUQV7kvHBwM/0x5LyO6XaG2lUaCaKiUI= github.com/up9inc/basenine/client/go v0.0.0-20220326121918-785f3061c8ce/go.mod h1:SvJGPoa/6erhUQV7kvHBwM/0x5LyO6XaG2lUaCaKiUI=
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74 h1:gga7acRE695APm9hlsSMoOoE65U4/TcqNj90mc69Rlg=
github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/wI2L/jsondiff v0.1.1 h1:r2TkoEet7E4JMO5+s1RCY2R0LrNPNHY6hbDeow2hRHw= github.com/wI2L/jsondiff v0.1.1 h1:r2TkoEet7E4JMO5+s1RCY2R0LrNPNHY6hbDeow2hRHw=

View File

@@ -111,9 +111,9 @@ func checkRulesPermissions(ctx context.Context, kubernetesProvider *kubernetes.P
func checkPermissionExist(group string, resource string, verb string, namespace string, exist bool, err error) bool { func checkPermissionExist(group string, resource string, verb string, namespace string, exist bool, err error) bool {
var groupAndNamespace string var groupAndNamespace string
if group != "" && namespace != "" { if group != "" && namespace != "" {
groupAndNamespace = fmt.Sprintf("in group '%v' and namespace '%v'", group, namespace) groupAndNamespace = fmt.Sprintf("in api group '%v' and namespace '%v'", group, namespace)
} else if group != "" { } else if group != "" {
groupAndNamespace = fmt.Sprintf("in group '%v'", group) groupAndNamespace = fmt.Sprintf("in api group '%v'", group)
} else if namespace != "" { } else if namespace != "" {
groupAndNamespace = fmt.Sprintf("in namespace '%v'", namespace) groupAndNamespace = fmt.Sprintf("in namespace '%v'", namespace)
} }

View File

@@ -27,13 +27,21 @@ func runMizuCheck() {
checkPassed = check.KubernetesVersion(kubernetesVersion) checkPassed = check.KubernetesVersion(kubernetesVersion)
} }
if config.Config.Check.PreTap { if config.Config.Check.PreTap || config.Config.Check.PreInstall || config.Config.Check.ImagePull {
if checkPassed { if config.Config.Check.PreTap {
checkPassed = check.TapKubernetesPermissions(ctx, embedFS, kubernetesProvider) if checkPassed {
checkPassed = check.TapKubernetesPermissions(ctx, embedFS, kubernetesProvider)
}
} else if config.Config.Check.PreInstall {
if checkPassed {
checkPassed = check.InstallKubernetesPermissions(ctx, kubernetesProvider)
}
} }
} else if config.Config.Check.PreInstall {
if checkPassed { if config.Config.Check.ImagePull {
checkPassed = check.InstallKubernetesPermissions(ctx, kubernetesProvider) if checkPassed {
checkPassed = check.ImagePullInCluster(ctx, kubernetesProvider)
}
} }
} else { } else {
if checkPassed { if checkPassed {
@@ -45,12 +53,6 @@ func runMizuCheck() {
} }
} }
if config.Config.Check.ImagePull {
if checkPassed {
checkPassed = check.ImagePullInCluster(ctx, kubernetesProvider)
}
}
if checkPassed { if checkPassed {
logger.Log.Infof("\nStatus check results are %v", fmt.Sprintf(uiUtils.Green, "√")) logger.Log.Infof("\nStatus check results are %v", fmt.Sprintf(uiUtils.Green, "√"))
} else { } else {

View File

@@ -40,7 +40,7 @@ type ConfigStruct struct {
HeadlessMode bool `yaml:"headless" default:"false"` HeadlessMode bool `yaml:"headless" default:"false"`
LogLevelStr string `yaml:"log-level,omitempty" default:"INFO" readonly:""` LogLevelStr string `yaml:"log-level,omitempty" default:"INFO" readonly:""`
ServiceMap bool `yaml:"service-map" default:"true"` ServiceMap bool `yaml:"service-map" default:"true"`
OAS bool `yaml:"oas,omitempty" default:"false" readonly:""` OAS bool `yaml:"oas" default:"true"`
Elastic shared.ElasticConfig `yaml:"elastic"` Elastic shared.ElasticConfig `yaml:"elastic"`
} }

View File

@@ -11,7 +11,7 @@ require (
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
github.com/spf13/cobra v1.3.0 github.com/spf13/cobra v1.3.0
github.com/spf13/pflag v1.0.5 github.com/spf13/pflag v1.0.5
github.com/up9inc/basenine/server/lib v0.0.0-20220317230530-8472d80307f6 github.com/up9inc/basenine/server/lib v0.0.0-20220326121918-785f3061c8ce
github.com/up9inc/mizu/shared v0.0.0 github.com/up9inc/mizu/shared v0.0.0
github.com/up9inc/mizu/tap/api v0.0.0 github.com/up9inc/mizu/tap/api v0.0.0
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8

View File

@@ -600,8 +600,8 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM=
github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc=
github.com/up9inc/basenine/server/lib v0.0.0-20220317230530-8472d80307f6 h1:+RZTD+HdfIW2SMbc65yWkruTY+g5/1Av074m62A74ls= github.com/up9inc/basenine/server/lib v0.0.0-20220326121918-785f3061c8ce h1:PypqybjmuxftGkX4NmP4JAUyEykZj2r6W4r9lnRZ/kE=
github.com/up9inc/basenine/server/lib v0.0.0-20220317230530-8472d80307f6/go.mod h1:ZIkxWiJm65jYQIso9k+OZKhR7gQ1we2jNyE2kQX9IQI= github.com/up9inc/basenine/server/lib v0.0.0-20220326121918-785f3061c8ce/go.mod h1:ZIkxWiJm65jYQIso9k+OZKhR7gQ1we2jNyE2kQX9IQI=
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg=
github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk= github.com/xlab/treeprint v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk=

View File

@@ -1,18 +1,20 @@
FROM dockcross/linux-arm64-musl:latest AS builder-from-amd64-to-arm64v8 FROM dockcross/linux-arm64-musl:latest AS builder-from-amd64-to-arm64v8
# Install Go # Install Go
RUN curl https://go.dev/dl/go1.17.6.linux-amd64.tar.gz -Lo ./go.linux-amd64.tar.gz RUN curl https://go.dev/dl/go1.17.6.linux-amd64.tar.gz -Lo ./go.linux-amd64.tar.gz \
RUN curl https://go.dev/dl/go1.17.6.linux-amd64.tar.gz.asc -Lo ./go.linux-amd64.tar.gz.asc && curl https://go.dev/dl/go1.17.6.linux-amd64.tar.gz.asc -Lo ./go.linux-amd64.tar.gz.asc \
RUN curl https://dl.google.com/dl/linux/linux_signing_key.pub -Lo linux_signing_key.pub && curl https://dl.google.com/dl/linux/linux_signing_key.pub -Lo linux_signing_key.pub \
RUN gpg --import linux_signing_key.pub && gpg --verify ./go.linux-amd64.tar.gz.asc ./go.linux-amd64.tar.gz && gpg --import linux_signing_key.pub && gpg --verify ./go.linux-amd64.tar.gz.asc ./go.linux-amd64.tar.gz \
RUN rm -rf /usr/local/go && tar -C /usr/local -xzf go.linux-amd64.tar.gz && rm -rf /usr/local/go && tar -C /usr/local -xzf go.linux-amd64.tar.gz
ENV PATH "$PATH:/usr/local/go/bin" ENV PATH "$PATH:/usr/local/go/bin"
# Compile libpcap from source # Compile libpcap from source
RUN curl https://www.tcpdump.org/release/libpcap-1.10.1.tar.gz -Lo ./libpcap.tar.gz RUN curl https://www.tcpdump.org/release/libpcap-1.10.1.tar.gz -Lo ./libpcap.tar.gz \
RUN curl https://www.tcpdump.org/release/libpcap-1.10.1.tar.gz.sig -Lo ./libpcap.tar.gz.sig && curl https://www.tcpdump.org/release/libpcap-1.10.1.tar.gz.sig -Lo ./libpcap.tar.gz.sig \
RUN curl https://www.tcpdump.org/release/signing-key.asc -Lo ./signing-key.asc && curl https://www.tcpdump.org/release/signing-key.asc -Lo ./signing-key.asc \
RUN gpg --import signing-key.asc && gpg --verify libpcap.tar.gz.sig libpcap.tar.gz && gpg --import signing-key.asc && gpg --verify libpcap.tar.gz.sig libpcap.tar.gz \
RUN tar -xzf libpcap.tar.gz && mv ./libpcap-* ./libpcap && tar -xzf libpcap.tar.gz && mv ./libpcap-* ./libpcap
RUN cd ./libpcap && ./configure --host=arm && make WORKDIR /work/libpcap
RUN cp /work/libpcap/libpcap.a /usr/xcc/aarch64-linux-musl-cross/lib/gcc/aarch64-linux-musl/*/ RUN ./configure --host=arm && make \
&& cp /work/libpcap/libpcap.a /usr/xcc/aarch64-linux-musl-cross/lib/gcc/aarch64-linux-musl/*/

View File

@@ -66,6 +66,7 @@ var filteringOptions *api.TrafficFilteringOptions // global
var tapTargets []v1.Pod // global var tapTargets []v1.Pod // global
var packetSourceManager *source.PacketSourceManager // global var packetSourceManager *source.PacketSourceManager // global
var mainPacketInputChan chan source.TcpPacketInfo // global var mainPacketInputChan chan source.TcpPacketInfo // global
var tlsTapperInstance *tlstapper.TlsTapper // global
func inArrayInt(arr []int, valueToCheck int) bool { func inArrayInt(arr []int, valueToCheck int) bool {
for _, value := range arr { for _, value := range arr {
@@ -92,7 +93,7 @@ func StartPassiveTapper(opts *TapOpts, outputItems chan *api.OutputChannelItem,
if *tls { if *tls {
for _, e := range extensions { for _, e := range extensions {
if e.Protocol.Name == "http" { if e.Protocol.Name == "http" {
startTlsTapper(e, outputItems, options) tlsTapperInstance = startTlsTapper(e, outputItems, options)
break break
} }
} }
@@ -102,24 +103,39 @@ func StartPassiveTapper(opts *TapOpts, outputItems chan *api.OutputChannelItem,
diagnose.StartMemoryProfiler(os.Getenv(MemoryProfilingDumpPath), os.Getenv(MemoryProfilingTimeIntervalSeconds)) diagnose.StartMemoryProfiler(os.Getenv(MemoryProfilingDumpPath), os.Getenv(MemoryProfilingTimeIntervalSeconds))
} }
go startPassiveTapper(opts, outputItems) streamsMap, assembler := initializePassiveTapper(opts, outputItems)
go startPassiveTapper(streamsMap, assembler)
} }
func UpdateTapTargets(newTapTargets []v1.Pod) { func UpdateTapTargets(newTapTargets []v1.Pod) {
success := true
tapTargets = newTapTargets tapTargets = newTapTargets
if err := initializePacketSources(); err != nil {
logger.Log.Fatal(err) packetSourceManager.UpdatePods(tapTargets)
if tlsTapperInstance != nil {
if err := tlstapper.UpdateTapTargets(tlsTapperInstance, &tapTargets, *procfs); err != nil {
tlstapper.LogError(err)
success = false
}
} }
printNewTapTargets()
printNewTapTargets(success)
} }
func printNewTapTargets() { func printNewTapTargets(success bool) {
printStr := "" printStr := ""
for _, tapTarget := range tapTargets { for _, tapTarget := range tapTargets {
printStr += fmt.Sprintf("%s (%s), ", tapTarget.Status.PodIP, tapTarget.Name) printStr += fmt.Sprintf("%s (%s), ", tapTarget.Status.PodIP, tapTarget.Name)
} }
printStr = strings.TrimRight(printStr, ", ") printStr = strings.TrimRight(printStr, ", ")
logger.Log.Infof("Now tapping: %s", printStr)
if success {
logger.Log.Infof("Now tapping: %s", printStr)
} else {
logger.Log.Errorf("Failed to start tapping: %s", printStr)
}
} }
func printPeriodicStats(cleaner *Cleaner) { func printPeriodicStats(cleaner *Cleaner) {
@@ -190,9 +206,8 @@ func initializePacketSources() error {
} }
} }
func startPassiveTapper(opts *TapOpts, outputItems chan *api.OutputChannelItem) { func initializePassiveTapper(opts *TapOpts, outputItems chan *api.OutputChannelItem) (*tcpStreamMap, *tcpAssembler) {
streamsMap := NewTcpStreamMap() streamsMap := NewTcpStreamMap()
go streamsMap.closeTimedoutTcpStreamChannels()
diagnose.InitializeErrorsMap(*debug, *verbose, *quiet) diagnose.InitializeErrorsMap(*debug, *verbose, *quiet)
diagnose.InitializeTapperInternalStats() diagnose.InitializeTapperInternalStats()
@@ -205,6 +220,12 @@ func startPassiveTapper(opts *TapOpts, outputItems chan *api.OutputChannelItem)
assembler := NewTcpAssembler(outputItems, streamsMap, opts) assembler := NewTcpAssembler(outputItems, streamsMap, opts)
return streamsMap, assembler
}
func startPassiveTapper(streamsMap *tcpStreamMap, assembler *tcpAssembler) {
go streamsMap.closeTimedoutTcpStreamChannels()
diagnose.AppStats.SetStartTime(time.Now()) diagnose.AppStats.SetStartTime(time.Now())
staleConnectionTimeout := time.Second * time.Duration(*staleTimeoutSeconds) staleConnectionTimeout := time.Second * time.Duration(*staleTimeoutSeconds)
@@ -236,13 +257,18 @@ func startPassiveTapper(opts *TapOpts, outputItems chan *api.OutputChannelItem)
logger.Log.Infof("AppStats: %v", diagnose.AppStats) logger.Log.Infof("AppStats: %v", diagnose.AppStats)
} }
func startTlsTapper(extension *api.Extension, outputItems chan *api.OutputChannelItem, options *api.TrafficFilteringOptions) { func startTlsTapper(extension *api.Extension, outputItems chan *api.OutputChannelItem, options *api.TrafficFilteringOptions) *tlstapper.TlsTapper {
tls := tlstapper.TlsTapper{} tls := tlstapper.TlsTapper{}
tlsPerfBufferSize := os.Getpagesize() * 100 tlsPerfBufferSize := os.Getpagesize() * 100
if err := tls.Init(tlsPerfBufferSize, *procfs, extension); err != nil { if err := tls.Init(tlsPerfBufferSize, *procfs, extension); err != nil {
tlstapper.LogError(err) tlstapper.LogError(err)
return return nil
}
if err := tlstapper.UpdateTapTargets(&tls, &tapTargets, *procfs); err != nil {
tlstapper.LogError(err)
return nil
} }
// A quick way to instrument libssl.so without PID filtering - used for debuging and troubleshooting // A quick way to instrument libssl.so without PID filtering - used for debuging and troubleshooting
@@ -250,19 +276,16 @@ func startTlsTapper(extension *api.Extension, outputItems chan *api.OutputChanne
if os.Getenv("MIZU_GLOBAL_SSL_LIBRARY") != "" { if os.Getenv("MIZU_GLOBAL_SSL_LIBRARY") != "" {
if err := tls.GlobalTap(os.Getenv("MIZU_GLOBAL_SSL_LIBRARY")); err != nil { if err := tls.GlobalTap(os.Getenv("MIZU_GLOBAL_SSL_LIBRARY")); err != nil {
tlstapper.LogError(err) tlstapper.LogError(err)
return return nil
} }
} }
if err := tlstapper.UpdateTapTargets(&tls, &tapTargets, *procfs); err != nil {
tlstapper.LogError(err)
return
}
var emitter api.Emitter = &api.Emitting{ var emitter api.Emitter = &api.Emitting{
AppStats: &diagnose.AppStats, AppStats: &diagnose.AppStats,
OutputChannel: outputItems, OutputChannel: outputItems,
} }
go tls.Poll(emitter, options) go tls.Poll(emitter, options)
return &tls
} }

View File

@@ -11,8 +11,16 @@ import (
const bpfFilterMaxPods = 150 const bpfFilterMaxPods = 150
const hostSourcePid = "0" const hostSourcePid = "0"
type PacketSourceManagerConfig struct {
mtls bool
procfs string
interfaceName string
behaviour TcpPacketSourceBehaviour
}
type PacketSourceManager struct { type PacketSourceManager struct {
sources map[string]*tcpPacketSource sources map[string]*tcpPacketSource
config PacketSourceManagerConfig
} }
func NewPacketSourceManager(procfs string, filename string, interfaceName string, func NewPacketSourceManager(procfs string, filename string, interfaceName string,
@@ -28,7 +36,14 @@ func NewPacketSourceManager(procfs string, filename string, interfaceName string
}, },
} }
sourceManager.UpdatePods(mtls, procfs, pods, interfaceName, behaviour) sourceManager.config = PacketSourceManagerConfig{
mtls: mtls,
procfs: procfs,
interfaceName: interfaceName,
behaviour: behaviour,
}
sourceManager.UpdatePods(pods)
return sourceManager, nil return sourceManager, nil
} }
@@ -49,10 +64,9 @@ func newHostPacketSource(filename string, interfaceName string,
return source, nil return source, nil
} }
func (m *PacketSourceManager) UpdatePods(mtls bool, procfs string, pods []v1.Pod, func (m *PacketSourceManager) UpdatePods(pods []v1.Pod) {
interfaceName string, behaviour TcpPacketSourceBehaviour) { if m.config.mtls {
if mtls { m.updateMtlsPods(m.config.procfs, pods, m.config.interfaceName, m.config.behaviour)
m.updateMtlsPods(procfs, pods, interfaceName, behaviour)
} }
m.setBPFFilter(pods) m.setBPFFilter(pods)

View File

@@ -24,6 +24,8 @@ func UpdateTapTargets(tls *TlsTapper, pods *[]v1.Pod, procfs string) error {
if err != nil { if err != nil {
return err return err
} }
tls.ClearPids()
for _, pid := range containerPids { for _, pid := range containerPids {
if err := tls.AddPid(procfs, pid); err != nil { if err := tls.AddPid(procfs, pid); err != nil {

View File

@@ -5,6 +5,7 @@ import (
"github.com/go-errors/errors" "github.com/go-errors/errors"
"github.com/up9inc/mizu/shared/logger" "github.com/up9inc/mizu/shared/logger"
"github.com/up9inc/mizu/tap/api" "github.com/up9inc/mizu/tap/api"
"sync"
) )
//go:generate go run github.com/cilium/ebpf/cmd/bpf2go tlsTapper bpf/tls_tapper.c -- -O2 -g -D__TARGET_ARCH_x86 //go:generate go run github.com/cilium/ebpf/cmd/bpf2go tlsTapper bpf/tls_tapper.c -- -O2 -g -D__TARGET_ARCH_x86
@@ -14,6 +15,7 @@ type TlsTapper struct {
syscallHooks syscallHooks syscallHooks syscallHooks
sslHooksStructs []sslHooks sslHooksStructs []sslHooks
poller *tlsPoller poller *tlsPoller
registeredPids sync.Map
} }
func (t *TlsTapper) Init(bufferSize int, procfs string, extension *api.Extension) error { func (t *TlsTapper) Init(bufferSize int, procfs string, extension *api.Extension) error {
@@ -70,6 +72,16 @@ func (t *TlsTapper) RemovePid(pid uint32) error {
return nil return nil
} }
func (t *TlsTapper) ClearPids() {
t.registeredPids.Range(func(key, v interface{}) bool {
if err := t.RemovePid(key.(uint32)); err != nil {
LogError(err)
}
t.registeredPids.Delete(key)
return true
})
}
func (t *TlsTapper) Close() []error { func (t *TlsTapper) Close() []error {
errors := make([]error, 0) errors := make([]error, 0)
@@ -116,6 +128,8 @@ func (t *TlsTapper) tapPid(pid uint32, sslLibrary string) error {
if err := pids.Put(pid, uint32(1)); err != nil { if err := pids.Put(pid, uint32(1)); err != nil {
return errors.Wrap(err, 0) return errors.Wrap(err, 0)
} }
t.registeredPids.Store(pid, true)
return nil return nil
} }

View File

@@ -1,4 +1,4 @@
import TrafficViewer,{useWS, DEFAULT_QUERY} from '@up9/mizu-common'; import TrafficViewer,{useWS, DEFAULT_QUERY, OasModal} from '@up9/mizu-common';
import "@up9/mizu-common/dist/index.css" import "@up9/mizu-common/dist/index.css"
import {useEffect} from 'react'; import {useEffect} from 'react';
import Api, {getWebsocketUrl} from "./api"; import Api, {getWebsocketUrl} from "./api";
@@ -17,8 +17,7 @@ const App = () => {
},[]) },[])
return <> return <>
<TrafficViewer message={message} error={error} isWebSocketOpen={isOpen}
trafficViewerApiProp={trafficViewerApi} ></TrafficViewer>
</> </>
} }

View File

@@ -1,12 +1,12 @@
{ {
"name": "@up9/mizu-common", "name": "@up9/mizu-common",
"version": "1.0.10", "version": "1.0.135",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "@up9/mizu-common", "name": "@up9/mizu-common",
"version": "1.0.10", "version": "1.0.135",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@craco/craco": "^6.4.3", "@craco/craco": "^6.4.3",

View File

@@ -1,6 +1,6 @@
{ {
"name": "@up9/mizu-common", "name": "@up9/mizu-common",
"version": "1.0.132", "version": "1.0.142",
"description": "Made with create-react-library", "description": "Made with create-react-library",
"author": "", "author": "",
"license": "MIT", "license": "MIT",
@@ -27,7 +27,7 @@
"@material-ui/icons": "^4.11.2", "@material-ui/icons": "^4.11.2",
"@material-ui/lab": "^4.0.0-alpha.60", "@material-ui/lab": "^4.0.0-alpha.60",
"node-sass": "^6.0.0", "node-sass": "^6.0.0",
"react":"^17.0.2", "react": "^17.0.2",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"recoil": "^0.5.2", "recoil": "^0.5.2",
"react-copy-to-clipboard": "^5.0.3", "react-copy-to-clipboard": "^5.0.3",
@@ -77,7 +77,7 @@
"rollup-plugin-postcss": "^4.0.2", "rollup-plugin-postcss": "^4.0.2",
"rollup-plugin-sass": "^1.2.10", "rollup-plugin-sass": "^1.2.10",
"rollup-plugin-scss": "^3.0.0", "rollup-plugin-scss": "^3.0.0",
"react":"^17.0.2", "react": "^17.0.2",
"react-dom": "^17.0.2", "react-dom": "^17.0.2",
"typescript": "^4.2.4" "typescript": "^4.2.4"
}, },
@@ -90,4 +90,4 @@
"files": [ "files": [
"dist" "dist"
] ]
} }

View File

@@ -6,23 +6,32 @@
padding: 10px padding: 10px
.selectHeader .selectHeader
font-family: Source Sans Pro,Lucida Grande,Tahoma,sans-serif
display: flex display: flex
align-items: center align-items: center
font-weight: 900
width: 100% width: 100%
margin-top: -1% margin-top: -1%
.openApilogo .openApilogo
width: 36px width: 43px
.title .title
color:#494677 color:#494677
font-family: Lato font-family: Source Sans Pro,Lucida Grande,Tahoma,sans-serif
font-size: 20px font-size: 28px
font-weight: 600 font-weight: 600
.selectContainer .selectContainer
margin-left: 1% width: 14%
margin-bottom: 1%
margin-top: 1%
.redoc .redoc
height: 98% height: 85%
overflow-y: scroll overflow-y: scroll
.borderLine
border-top: 1px solid #dee6fe
margin-bottom: 1%

View File

@@ -1,4 +1,4 @@
import { Box, Fade, FormControl, MenuItem, Modal, Backdrop, ListSubheader } from "@material-ui/core"; import { Box, Fade, FormControl, MenuItem, Modal, Backdrop } from "@material-ui/core";
import { useCallback, useEffect, useState } from "react"; import { useCallback, useEffect, useState } from "react";
import { RedocStandalone } from "redoc"; import { RedocStandalone } from "redoc";
import closeIcon from "assets/closeIcon.svg"; import closeIcon from "assets/closeIcon.svg";
@@ -9,6 +9,7 @@ import { redocThemeOptions } from "./redocThemeOptions";
import React from "react"; import React from "react";
import { Select } from "../UI/Select"; import { Select } from "../UI/Select";
const modalStyle = { const modalStyle = {
position: 'absolute', position: 'absolute',
top: '6%', top: '6%',
@@ -23,63 +24,44 @@ const modalStyle = {
color: '#000', color: '#000',
}; };
const ipAddressWithPortRegex = new RegExp('([0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}.[0-9]{1,3}):([0-9]{1,5})');
const OasModal = ({ openModal, handleCloseModal, getOasServices, getOasByService}) => { const OasModal = ({ openModal, handleCloseModal, getOasServices, getOasByService }) => {
const [oasServices, setOasServices] = useState([] as string[]) const [oasServices, setOasServices] = useState([] as string[])
const [selectedServiceName, setSelectedServiceName] = useState(""); const [selectedServiceName, setSelectedServiceName] = useState("");
const [selectedServiceSpec, setSelectedServiceSpec] = useState(null); const [selectedServiceSpec, setSelectedServiceSpec] = useState(null);
const [resolvedServices, setResolvedServices] = useState([]);
const [unResolvedServices, setUnResolvedServices] = useState([]);
const onSelectedOASService = useCallback( async (selectedService) => { const onSelectedOASService = async (selectedService) => {
if (!!selectedService){ if (oasServices.length === 0) {
setSelectedServiceName(selectedService); setSelectedServiceSpec(null);
if(oasServices.length === 0){ setSelectedServiceName("");
return return
} }
try { else {
const data = await getOasByService(selectedService); setSelectedServiceName(selectedService ? selectedService : oasServices[0]);
setSelectedServiceSpec(data); }
try {
const data = await getOasByService(selectedService ? selectedService : oasServices[0]);
setSelectedServiceSpec(data);
} catch (e) { } catch (e) {
toast.error("Error occurred while fetching service OAS spec"); toast.error("Error occurred while fetching service OAS spec");
console.error(e); console.error(e);
} }
} };
},[oasServices.length])
const resolvedArrayBuilder = useCallback(async(services) => {
const resServices = [];
const unResServices = [];
services.forEach(s => {
if(ipAddressWithPortRegex.test(s)){
unResServices.push(s);
}
else {
resServices.push(s);
}
});
resServices.sort();
unResServices.sort();
onSelectedOASService(resServices[0]);
setResolvedServices(resServices);
setUnResolvedServices(unResServices);
},[onSelectedOASService])
useEffect(() => { useEffect(() => {
(async () => { (async () => {
try { try {
const services = await getOasServices(); const services = await getOasServices();
resolvedArrayBuilder(services);
setOasServices(services); setOasServices(services);
} catch (e) { } catch (e) {
console.error(e); console.error(e);
} }
})(); })();
}, [openModal,resolvedArrayBuilder]); }, [openModal]);
useEffect(() => {
onSelectedOASService(null);
},[oasServices])
return ( return (
<Modal <Modal
@@ -90,48 +72,41 @@ const OasModal = ({ openModal, handleCloseModal, getOasServices, getOasByService
closeAfterTransition closeAfterTransition
BackdropComponent={Backdrop} BackdropComponent={Backdrop}
BackdropProps={{ BackdropProps={{
timeout: 500, timeout: 500,
}} }}
> >
<Fade in={openModal}> <Fade in={openModal}>
<Box sx={modalStyle}> <Box sx={modalStyle}>
<div className={style.boxContainer}> <div className={style.boxContainer}>
<div className={style.selectHeader}> <div className={style.selectHeader}>
<div><img src={openApiLogo} alt="openApi" className={style.openApilogo}/></div> <div><img src={openApiLogo} alt="openAPI" className={style.openApilogo} /></div>
<div className={style.title}>OpenAPI selected service: </div> <div className={style.title}>OpenAPI</div>
<div className={style.selectContainer} >
<FormControl>
<Select
labelId="service-select-label"
id="service-select"
placeholder="Show OAS"
value={selectedServiceName}
onChangeCb={onSelectedOASService}
>
<ListSubheader disableSticky={true}>Resolved</ListSubheader>
{resolvedServices.map((service) => (
<MenuItem key={service} value={service}>
{service}
</MenuItem>
))}
<ListSubheader disableSticky={true}>UnResolved</ListSubheader>
{unResolvedServices.map((service) => (
<MenuItem key={service} value={service}>
{service}
</MenuItem>
))}
</Select>
</FormControl>
</div>
</div> </div>
<div style={{ cursor: "pointer" }}> <div style={{ cursor: "pointer" }}>
<img src={closeIcon} alt="close" onClick={handleCloseModal} /> <img src={closeIcon} alt="close" onClick={handleCloseModal} />
</div> </div>
</div> </div>
<div className={style.selectContainer} >
<FormControl>
<Select
labelId="service-select-label"
id="service-select"
value={selectedServiceName}
onChangeCb={onSelectedOASService}
>
{oasServices.map((service) => (
<MenuItem key={service} value={service}>
{service}
</MenuItem>
))}
</Select>
</FormControl>
</div>
<div className={style.borderLine}></div>
<div className={style.redoc}> <div className={style.redoc}>
{selectedServiceSpec && <RedocStandalone {selectedServiceSpec && <RedocStandalone
spec={selectedServiceSpec} spec={selectedServiceSpec}
options={redocThemeOptions}/>} options={redocThemeOptions} />}
</div> </div>
</Box> </Box>
</Fade> </Fade>

View File

@@ -1,35 +1,52 @@
export const redocThemeOptions = { const fontFamilyVar = "Source Sans Pro, Lucida Grande, Tahoma, sans-serif"
theme:{
codeBlock:{ export const redocThemeOptions = {
backgroundColor:"#11171a", theme: {
}, codeBlock: {
colors:{ backgroundColor: "#14161c",
responses:{ },
error:{ components: {
tabTextColor:"#1b1b29" buttons: {
}, fontFamily: fontFamilyVar,
info:{ },
tabTextColor:"#1b1b29", httpBadges: {
}, fontFamily: fontFamilyVar,
success:{ }
tabTextColor:"#0c0b1a" },
}, colors: {
}, responses: {
text:{ error: {
primary:"#1b1b29", tabTextColor: "#1b1b29"
secondary:"#4d4d4d" },
} info: {
}, tabTextColor: "#1b1b29",
rightPanel:{ },
backgroundColor:"#253237", success: {
}, tabTextColor: "#0c0b1a"
sidebar:{ },
backgroundColor:"#ffffff" },
}, text: {
typography:{ primary: "#1b1b29",
code:{ secondary: "#4d4d4d"
color:"#0c0b1a" }
} },
} rightPanel: {
} backgroundColor: "#0D0B1D",
} },
sidebar: {
backgroundColor: "#ffffff"
},
typography: {
code: {
color: "#0c0b1a",
fontFamily: fontFamilyVar
},
fontFamily: fontFamilyVar,
fontSize: "90%",
fontWieght: "normal",
headings: {
fontFamily: fontFamilyVar
}
}
}
}

View File

@@ -1,16 +1,18 @@
import React, {useEffect, useState} from "react"; import React, { useEffect, useState } from "react";
import EntryViewer from "./EntryDetailed/EntryViewer"; import EntryViewer from "./EntryDetailed/EntryViewer";
import {EntryItem} from "./EntryListItem/EntryListItem"; import { EntryItem } from "./EntryListItem/EntryListItem";
import {makeStyles} from "@material-ui/core"; import { makeStyles } from "@material-ui/core";
import Protocol from "../UI/Protocol" import Protocol from "../UI/Protocol"
import Queryable from "../UI/Queryable"; import Queryable from "../UI/Queryable";
import {toast} from "react-toastify"; import { toast } from "react-toastify";
import {RecoilState, useRecoilState, useRecoilValue} from "recoil"; import { RecoilState, useRecoilState, useRecoilValue } from "recoil";
import focusedEntryIdAtom from "../../recoil/focusedEntryId"; import focusedEntryIdAtom from "../../recoil/focusedEntryId";
import trafficViewerApi from "../../recoil/TrafficViewerApi"; import trafficViewerApi from "../../recoil/TrafficViewerApi";
import TrafficViewerApi from "./TrafficViewerApi"; import TrafficViewerApi from "./TrafficViewerApi";
import TrafficViewerApiAtom from "../../recoil/TrafficViewerApi/atom"; import TrafficViewerApiAtom from "../../recoil/TrafficViewerApi/atom";
import queryAtom from "../../recoil/query/atom"; import queryAtom from "../../recoil/query/atom";
import useWindowDimensions, { useRequestTextByWidth } from "../../hooks/WindowDimensionsHook";
import { TOAST_CONTAINER_ID } from "../../configs/Consts";
const useStyles = makeStyles(() => ({ const useStyles = makeStyles(() => ({
entryTitle: { entryTitle: {
@@ -35,56 +37,59 @@ const useStyles = makeStyles(() => ({
})); }));
export const formatSize = (n: number) => n > 1000 ? `${Math.round(n / 1000)}KB` : `${n} B`; export const formatSize = (n: number) => n > 1000 ? `${Math.round(n / 1000)}KB` : `${n} B`;
const minSizeDisplayRequestSize = 880;
const EntryTitle: React.FC<any> = ({protocol, data, elapsedTime}) => { const EntryTitle: React.FC<any> = ({ protocol, data, elapsedTime }) => {
const classes = useStyles(); const classes = useStyles();
const request = data.request; const request = data.request;
const response = data.response; const response = data.response;
const { width } = useWindowDimensions();
const { requestText, responseText, elapsedTimeText } = useRequestTextByWidth(width)
return <div className={classes.entryTitle}> return <div className={classes.entryTitle}>
<Protocol protocol={protocol} horizontal={true}/> <Protocol protocol={protocol} horizontal={true} />
<div style={{right: "30px", position: "absolute", display: "flex"}}> {(width > minSizeDisplayRequestSize) && <div style={{ right: "30px", position: "absolute", display: "flex" }}>
{request && <Queryable {request && <Queryable
query={`requestSize == ${data.requestSize}`} query={`requestSize == ${data.requestSize}`}
style={{margin: "0 18px"}} style={{ margin: "0 18px" }}
displayIconOnMouseOver={true} displayIconOnMouseOver={true}
> >
<div <div
style={{opacity: 0.5}} style={{ opacity: 0.5 }}
id="entryDetailedTitleRequestSize" id="entryDetailedTitleRequestSize"
> >
{`Request: ${formatSize(data.requestSize)}`} {`${requestText}${formatSize(data.requestSize)}`}
</div> </div>
</Queryable>} </Queryable>}
{response && <Queryable {response && <Queryable
query={`responseSize == ${data.responseSize}`} query={`responseSize == ${data.responseSize}`}
style={{margin: "0 18px"}} style={{ margin: "0 18px" }}
displayIconOnMouseOver={true} displayIconOnMouseOver={true}
> >
<div <div
style={{opacity: 0.5}} style={{ opacity: 0.5 }}
id="entryDetailedTitleResponseSize" id="entryDetailedTitleResponseSize"
> >
{`Response: ${formatSize(data.responseSize)}`} {`${responseText}${formatSize(data.responseSize)}`}
</div> </div>
</Queryable>} </Queryable>}
{response && <Queryable {response && <Queryable
query={`elapsedTime >= ${elapsedTime}`} query={`elapsedTime >= ${elapsedTime}`}
style={{marginRight: 18}} style={{ margin: "0 0 0 18px" }}
displayIconOnMouseOver={true} displayIconOnMouseOver={true}
> >
<div <div
style={{opacity: 0.5}} style={{ opacity: 0.5 }}
id="entryDetailedTitleElapsedTime" id="entryDetailedTitleElapsedTime"
> >
{`Elapsed Time: ${Math.round(elapsedTime)}ms`} {`${elapsedTimeText}${Math.round(elapsedTime)}ms`}
</div> </div>
</Queryable>} </Queryable>}
</div> </div>}
</div>; </div>;
}; };
const EntrySummary: React.FC<any> = ({entry}) => { const EntrySummary: React.FC<any> = ({ entry }) => {
return <EntryItem return <EntryItem
key={`entry-${entry.id}`} key={`entry-${entry.id}`}
entry={entry} entry={entry}
@@ -113,14 +118,10 @@ export const EntryDetailed = () => {
} catch (error) { } catch (error) {
if (error.response?.data?.type) { if (error.response?.data?.type) {
toast[error.response.data.type](`Entry[${focusedEntryId}]: ${error.response.data.msg}`, { toast[error.response.data.type](`Entry[${focusedEntryId}]: ${error.response.data.msg}`, {
position: "bottom-right",
theme: "colored", theme: "colored",
autoClose: error.response.data.autoClose, autoClose: error.response.data.autoClose,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true,
draggable: true,
progress: undefined, progress: undefined,
containerId: TOAST_CONTAINER_ID
}); });
} }
console.error(error); console.error(error);
@@ -135,7 +136,7 @@ export const EntryDetailed = () => {
data={entryData.data} data={entryData.data}
elapsedTime={entryData.data.elapsedTime} elapsedTime={entryData.data.elapsedTime}
/>} />}
{entryData && <EntrySummary entry={entryData.base}/>} {entryData && <EntrySummary entry={entryData.base} />}
<React.Fragment> <React.Fragment>
{entryData && <EntryViewer {entryData && <EntryViewer
representation={entryData.representation} representation={entryData.representation}

View File

@@ -4,7 +4,7 @@ import SwapHorizIcon from '@material-ui/icons/SwapHoriz';
import styles from './EntryListItem.module.sass'; import styles from './EntryListItem.module.sass';
import StatusCode, {getClassification, StatusCodeClassification} from "../../UI/StatusCode"; import StatusCode, {getClassification, StatusCodeClassification} from "../../UI/StatusCode";
import Protocol, {ProtocolInterface} from "../../UI/Protocol" import Protocol, {ProtocolInterface} from "../../UI/Protocol"
import eBPFLogo from '../../assets/ebpf.png'; import eBPFLogo from 'assets/ebpf.png';
import {Summary} from "../../UI/Summary"; import {Summary} from "../../UI/Summary";
import Queryable from "../../UI/Queryable"; import Queryable from "../../UI/Queryable";
import ingoingIconSuccess from "assets/ingoing-traffic-success.svg" import ingoingIconSuccess from "assets/ingoing-traffic-success.svg"

View File

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -8,8 +8,7 @@ import { EntryDetailed } from "./EntryDetailed";
import playIcon from 'assets/run.svg'; import playIcon from 'assets/run.svg';
import pauseIcon from 'assets/pause.svg'; import pauseIcon from 'assets/pause.svg';
import variables from '../../variables.module.scss'; import variables from '../../variables.module.scss';
import { toast,ToastContainer } from 'react-toastify'; import { toast, ToastContainer } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
import debounce from 'lodash/debounce'; import debounce from 'lodash/debounce';
import { RecoilRoot, RecoilState, useRecoilState, useRecoilValue, useSetRecoilState } from "recoil"; import { RecoilRoot, RecoilState, useRecoilState, useRecoilValue, useSetRecoilState } from "recoil";
import entriesAtom from "../../recoil/entries"; import entriesAtom from "../../recoil/entries";
@@ -20,6 +19,7 @@ import trafficViewerApiAtom from "../../recoil/TrafficViewerApi"
import TrafficViewerApi from "./TrafficViewerApi"; import TrafficViewerApi from "./TrafficViewerApi";
import { StatusBar } from "../UI/StatusBar"; import { StatusBar } from "../UI/StatusBar";
import tappingStatusAtom from "../../recoil/tappingStatus/atom"; import tappingStatusAtom from "../../recoil/tappingStatus/atom";
import { TOAST_CONTAINER_ID } from "../../configs/Consts";
const useLayoutStyles = makeStyles(() => ({ const useLayoutStyles = makeStyles(() => ({
details: { details: {
@@ -47,13 +47,14 @@ interface TrafficViewerProps {
trafficViewerApiProp: TrafficViewerApi, trafficViewerApiProp: TrafficViewerApi,
actionButtons?: JSX.Element, actionButtons?: JSX.Element,
isShowStatusBar?: boolean, isShowStatusBar?: boolean,
webSocketUrl : string, webSocketUrl: string,
isCloseWebSocket : boolean isCloseWebSocket: boolean,
isDemoBannerView: boolean
} }
export const TrafficViewer : React.FC<TrafficViewerProps> = ({setAnalyzeStatus, trafficViewerApiProp, export const TrafficViewer: React.FC<TrafficViewerProps> = ({ setAnalyzeStatus, trafficViewerApiProp,
actionButtons,isShowStatusBar,webSocketUrl, actionButtons, isShowStatusBar, webSocketUrl,
isCloseWebSocket}) => { isCloseWebSocket, isDemoBannerView }) => {
const classes = useLayoutStyles(); const classes = useLayoutStyles();
@@ -105,9 +106,9 @@ export const TrafficViewer : React.FC<TrafficViewerProps> = ({setAnalyzeStatus,
handleQueryChange(query); handleQueryChange(query);
}, [query, handleQueryChange]); }, [query, handleQueryChange]);
useEffect(()=>{ useEffect(() => {
isCloseWebSocket && closeWebSocket() isCloseWebSocket && closeWebSocket()
},[isCloseWebSocket]) }, [isCloseWebSocket])
const ws = useRef(null); const ws = useRef(null);
@@ -125,7 +126,7 @@ export const TrafficViewer : React.FC<TrafficViewerProps> = ({setAnalyzeStatus,
sendQueryWhenWsOpen(query); sendQueryWhenWsOpen(query);
ws.current.onclose = () => { ws.current.onclose = () => {
if(window.location.pathname === "/") if (window.location.pathname === "/")
setForceRender(forceRender + 1); setForceRender(forceRender + 1);
} }
ws.current.onerror = (event) => { ws.current.onerror = (event) => {
@@ -139,13 +140,13 @@ export const TrafficViewer : React.FC<TrafficViewerProps> = ({setAnalyzeStatus,
openWebSocket(`leftOff(${leftOffBottom})`, false); openWebSocket(`leftOff(${leftOffBottom})`, false);
} }
} }
} catch (e) {} } catch (e) { }
} }
const sendQueryWhenWsOpen = (query) => { const sendQueryWhenWsOpen = (query) => {
setTimeout(() => { setTimeout(() => {
if (ws?.current?.readyState === WebSocket.OPEN) { if (ws?.current?.readyState === WebSocket.OPEN) {
ws.current.send(JSON.stringify({"query": query, "enableFullEntries": false})); ws.current.send(JSON.stringify({ "query": query, "enableFullEntries": false }));
} else { } else {
sendQueryWhenWsOpen(query); sendQueryWhenWsOpen(query);
} }
@@ -153,7 +154,7 @@ export const TrafficViewer : React.FC<TrafficViewerProps> = ({setAnalyzeStatus,
} }
const closeWebSocket = () => { const closeWebSocket = () => {
if(ws?.current?.readyState === WebSocket.OPEN) { if (ws?.current?.readyState === WebSocket.OPEN) {
ws.current.close(); ws.current.close();
} }
} }
@@ -185,14 +186,11 @@ export const TrafficViewer : React.FC<TrafficViewerProps> = ({setAnalyzeStatus,
break; break;
case "toast": case "toast":
toast[message.data.type](message.data.text, { toast[message.data.type](message.data.text, {
position: "bottom-right",
theme: "colored", theme: "colored",
autoClose: message.data.autoClose, autoClose: message.data.autoClose,
hideProgressBar: false,
closeOnClick: true,
pauseOnHover: true, pauseOnHover: true,
draggable: true,
progress: undefined, progress: undefined,
containerId: TOAST_CONTAINER_ID
}); });
break; break;
case "queryMetadata": case "queryMetadata":
@@ -216,13 +214,13 @@ export const TrafficViewer : React.FC<TrafficViewerProps> = ({setAnalyzeStatus,
} }
useEffect(() => { useEffect(() => {
setTrafficViewerApiState({...trafficViewerApiProp, webSocket : {close : closeWebSocket}}); setTrafficViewerApiState({ ...trafficViewerApiProp, webSocket: { close: closeWebSocket } });
(async () => { (async () => {
openWebSocket("leftOff(-1)", true); openWebSocket("leftOff(-1)", true);
try{ try {
const tapStatusResponse = await trafficViewerApiProp.tapStatus(); const tapStatusResponse = await trafficViewerApiProp.tapStatus();
setTappingStatus(tapStatusResponse); setTappingStatus(tapStatusResponse);
if(setAnalyzeStatus) { if (setAnalyzeStatus) {
const analyzeStatusResponse = await trafficViewerApiProp.analyzeStatus(); const analyzeStatusResponse = await trafficViewerApiProp.analyzeStatus();
setAnalyzeStatus(analyzeStatusResponse); setAnalyzeStatus(analyzeStatusResponse);
} }
@@ -234,7 +232,7 @@ export const TrafficViewer : React.FC<TrafficViewerProps> = ({setAnalyzeStatus,
}, []); }, []);
const toggleConnection = () => { const toggleConnection = () => {
if(ws?.current?.readyState === WebSocket.OPEN) { if (ws?.current?.readyState === WebSocket.OPEN) {
ws?.current?.close(); ws?.current?.close();
} else { } else {
if (query) { if (query) {
@@ -293,7 +291,7 @@ export const TrafficViewer : React.FC<TrafficViewerProps> = ({setAnalyzeStatus,
return ( return (
<div className={TrafficViewerStyles.TrafficPage}> <div className={TrafficViewerStyles.TrafficPage}>
{tappingStatus && isShowStatusBar && <StatusBar />} {tappingStatus && isShowStatusBar && <StatusBar isDemoBannerView={isDemoBannerView} />}
<div className={TrafficViewerStyles.TrafficPageHeader}> <div className={TrafficViewerStyles.TrafficPageHeader}>
<div className={TrafficViewerStyles.TrafficPageStreamStatus}> <div className={TrafficViewerStyles.TrafficPageStreamStatus}>
<img className={TrafficViewerStyles.playPauseIcon} style={{ visibility: ws?.current?.readyState === WebSocket.OPEN ? "visible" : "hidden" }} alt="pause" <img className={TrafficViewerStyles.playPauseIcon} style={{ visibility: ws?.current?.readyState === WebSocket.OPEN ? "visible" : "hidden" }} alt="pause"
@@ -348,19 +346,28 @@ export const TrafficViewer : React.FC<TrafficViewerProps> = ({setAnalyzeStatus,
setAddressesWithTLS={setAddressesWithTLS} setAddressesWithTLS={setAddressesWithTLS}
userDismissedTLSWarning={userDismissedTLSWarning} userDismissedTLSWarning={userDismissedTLSWarning}
setUserDismissedTLSWarning={setUserDismissedTLSWarning} /> setUserDismissedTLSWarning={setUserDismissedTLSWarning} />
<ToastContainer/>
</div> </div>
); );
}; };
const MemoiedTrafficViewer = React.memo(TrafficViewer) const MemoiedTrafficViewer = React.memo(TrafficViewer)
const TrafficViewerContainer: React.FC<TrafficViewerProps> = ({ setAnalyzeStatus, trafficViewerApiProp, const TrafficViewerContainer: React.FC<TrafficViewerProps> = ({ setAnalyzeStatus, trafficViewerApiProp,
actionButtons, isShowStatusBar = true , actionButtons, isShowStatusBar = true,
webSocketUrl, isCloseWebSocket}) => { webSocketUrl, isCloseWebSocket, isDemoBannerView }) => {
return <RecoilRoot> return <RecoilRoot>
<MemoiedTrafficViewer actionButtons={actionButtons} isShowStatusBar={isShowStatusBar} webSocketUrl={webSocketUrl} <MemoiedTrafficViewer actionButtons={actionButtons} isShowStatusBar={isShowStatusBar} webSocketUrl={webSocketUrl}
isCloseWebSocket={isCloseWebSocket} trafficViewerApiProp={trafficViewerApiProp} isCloseWebSocket={isCloseWebSocket} trafficViewerApiProp={trafficViewerApiProp}
setAnalyzeStatus={setAnalyzeStatus} /> setAnalyzeStatus={setAnalyzeStatus} isDemoBannerView={isDemoBannerView} />
<ToastContainer enableMultiContainer containerId={TOAST_CONTAINER_ID}
position="bottom-right"
autoClose={5000}
hideProgressBar={false}
newestOnTop={false}
closeOnClick
rtl={false}
pauseOnFocusLoss
draggable
pauseOnHover />
</RecoilRoot> </RecoilRoot>
} }

View File

@@ -6,11 +6,11 @@ export interface Props {
disabled?: boolean; disabled?: boolean;
} }
const Checkbox: React.FC<Props> = ({checked, onToggle, disabled}) => { const Checkbox: React.FC<Props> = ({checked, onToggle, disabled, ...props}) => {
return ( return (
<div> <div>
<input style={!disabled ? {cursor: "pointer"}: {}} type="checkbox" checked={checked} disabled={disabled} onChange={(event) => onToggle(event.target.checked)}/> <input style={!disabled ? {cursor: "pointer"}: {}} type="checkbox" checked={checked} disabled={disabled} onChange={(event) => onToggle(event.target.checked)} {...props}/>
</div> </div>
); );
}; };

View File

@@ -0,0 +1,20 @@
import React, { CSSProperties } from "react";
import infoImg from 'assets/info.svg';
import styles from "./style/InformationIcon.module.sass"
const DEFUALT_LINK = "https://getmizu.io/docs"
export interface InformationIconProps{
link?: string,
style? : CSSProperties
}
export const InformationIcon: React.FC<InformationIconProps> = ({link,style}) => {
return <React.Fragment>
<a href={DEFUALT_LINK ? DEFUALT_LINK : link} style={style} className={styles.flex} title="documentation" target="_blank">
<img className="headerIcon" src={infoImg} alt="Info icon"/>
</a>
</React.Fragment>
}

View File

@@ -19,7 +19,7 @@ const menuProps: any = {
}; };
// icons styles are not overwritten from the Props, only as a separate object // icons styles are not overwritten from the Props, only as a separate object
const classes = {icon: styles.icon, selectMenu: styles.list}; const classes = {icon: styles.icon, selectMenu: styles.list, select: styles.oasSelect, root:styles.root};
const defaultProps = { const defaultProps = {
MenuProps: menuProps, MenuProps: menuProps,

View File

@@ -10,12 +10,16 @@ const pluralize = (noun: string, amount: number) => {
return `${noun}${amount !== 1 ? 's' : ''}` return `${noun}${amount !== 1 ? 's' : ''}`
} }
export const StatusBar = () => { interface StatusBarProps {
isDemoBannerView: boolean;
}
export const StatusBar = ({isDemoBannerView}) => {
const tappingStatus = useRecoilValue(tappingStatusAtom); const tappingStatus = useRecoilValue(tappingStatusAtom);
const [expandedBar, setExpandedBar] = useState(false); const [expandedBar, setExpandedBar] = useState(false);
const {uniqueNamespaces, amountOfPods, amountOfTappedPods, amountOfUntappedPods} = useRecoilValue(tappingStatusDetails); const {uniqueNamespaces, amountOfPods, amountOfTappedPods, amountOfUntappedPods} = useRecoilValue(tappingStatusDetails);
return <div className={`${style.statusBar} ${(expandedBar ? `${style.expandedStatusBar}` : "")}`} onMouseOver={() => setExpandedBar(true)} onMouseLeave={() => setExpandedBar(false)} data-cy="expandedStatusBar"> return <div className={`${isDemoBannerView ? `${style.banner}` : ''} ${style.statusBar} ${(expandedBar ? `${style.expandedStatusBar}` : "")}`} onMouseOver={() => setExpandedBar(true)} onMouseLeave={() => setExpandedBar(false)} data-cy="expandedStatusBar">
<div className={style.podsCount}> <div className={style.podsCount}>
{tappingStatus.some(pod => !pod.isTapped) && <img src={warningIcon} alt="warning"/>} {tappingStatus.some(pod => !pod.isTapped) && <img src={warningIcon} alt="warning"/>}
<span className={style.podsCountText} data-cy="podsCountText"> <span className={style.podsCountText} data-cy="podsCountText">

View File

@@ -0,0 +1,39 @@
.highlighterContainer
&.fitScreen
pre
max-height: 90vh
overflow: auto
pre
code
font-size: 0.75rem
&:first-child
margin-right: 0.75rem
background: #F7F9FC
.react-syntax-highlighter-line-number
color: rgb(98, 126, 247)
&:last-child
display: block
code.hljs
white-space: pre-wrap
code.hljs:before
counter-reset: listing
.hljsMarkerLine
counter-increment: listing
.hljsMarkerLine:before
content: counter(listing) " "
display: inline-block
width: 3rem
padding-left: auto
margin-left: auto
text-align: right
opacity: .5

View File

@@ -1,49 +0,0 @@
.highlighterContainer {
&.fitScreen {
pre {
max-height: 90vh;
overflow: auto;
}
}
pre {
code {
font-size: 0.75rem;
&:first-child {
margin-right: 0.75rem;
background: #F7F9FC;
.react-syntax-highlighter-line-number {
color: rgb(98, 126, 247);
}
}
&:last-child {
display: block;
}
}
}
}
code.hljs {
white-space: pre-wrap;
}
code.hljs:before {
counter-reset: listing;
}
code.hljs .hljs-marker-line {
counter-increment: listing;
}
code.hljs .hljs-marker-line:before {
content: counter(listing) " ";
display: inline-block;
width: 3rem;
padding-left: auto;
margin-left: auto;
text-align: right;
opacity: .5;
}

View File

@@ -1,7 +1,7 @@
import React from 'react'; import React from 'react';
import Lowlight from 'react-lowlight' import Lowlight from 'react-lowlight'
import 'highlight.js/styles/atom-one-light.css' import 'highlight.js/styles/atom-one-light.css'
import './index.scss'; import styles from './index.module.sass';
import xml from 'highlight.js/lib/languages/xml' import xml from 'highlight.js/lib/languages/xml'
import json from 'highlight.js/lib/languages/json' import json from 'highlight.js/lib/languages/json'
@@ -37,11 +37,11 @@ export const SyntaxHighlighter: React.FC<Props> = ({
const markers = showLineNumbers ? code.split("\n").map((item, i) => { const markers = showLineNumbers ? code.split("\n").map((item, i) => {
return { return {
line: i + 1, line: i + 1,
className: 'hljs-marker-line' className: styles.hljsMarkerLine
} }
}) : []; }) : [];
return <div style={{fontSize: ".75rem"}}><Lowlight language={language ? language : ""} value={code} markers={markers}/></div>; return <div style={{fontSize: ".75rem"}} className={styles.highlighterContainer}><Lowlight language={language ? language : ""} value={code} markers={markers}/></div>;
}; };
export default SyntaxHighlighter; export default SyntaxHighlighter;

View File

@@ -76,6 +76,7 @@ const Tabs: React.FC<Props> = ({classes={}, tabs, currentTab, color, onChange, l
{tabs.map(({tab, disabled, disabledMessage, highlight, badge}, index) => { {tabs.map(({tab, disabled, disabledMessage, highlight, badge}, index) => {
const active = currentTab === tab; const active = currentTab === tab;
const tabLink = <span const tabLink = <span
data-cy={"tab-" + tab}
key={tab} key={tab}
className={`${_classes.tab} ${active ? _classes.active : ''} ${disabled ? _classes.disabled : ''} ${highlight ? _classes.highlight : ''} ${dark ? 'dark' : ''}`} className={`${_classes.tab} ${active ? _classes.active : ''} ${disabled ? _classes.disabled : ''} ${highlight ? _classes.highlight : ''} ${dark ? 'dark' : ''}`}
onClick={() => !disabled && onChange(tab)} onClick={() => !disabled && onChange(tab)}

View File

@@ -0,0 +1,5 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M19 21H6.14286C5.07143 21 4 20.32 4 18.96C4 17.6 5.07143 16.92 6.14286 16.92H19V4H6.14286C5.07143 4 4 5.02 4 6.04V18.96M16.8571 17.6V20.32V17.6Z" stroke="#627EF7" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<rect x="8" y="7" width="7" height="2" fill="#627EF7"/>
<rect x="8" y="11" width="4" height="2" fill="#627EF7"/>
</svg>

After

Width:  |  Height:  |  Size: 454 B

View File

@@ -5,7 +5,8 @@ import Tooltip from "./Tooltip";
import Checkbox from "./Checkbox" import Checkbox from "./Checkbox"
import { StatusBar } from "./StatusBar"; import { StatusBar } from "./StatusBar";
import CustomModal from "./CustomModal"; import CustomModal from "./CustomModal";
import { InformationIcon } from "./InformationIcon";
export {LoadingOverlay,Select,Tabs,Tooltip,Checkbox,CustomModal} export {LoadingOverlay,Select,Tabs,Tooltip,Checkbox,CustomModal,InformationIcon}
export {StatusBar} export {StatusBar}

View File

@@ -0,0 +1,2 @@
.flex
display: flex

View File

@@ -3,3 +3,15 @@
.list .list
margin-top: 8px margin-top: 8px
.oasSelect
font-weight: normal
padding: 8px 4px 8px 12px !important
border: 1px solid #9d9d9d !important
border-radius: 9px !important
font-family: Source Sans Pro, Lucida Grande, Tahoma, sans-serif !important
width: 216px !important
.root
font-family: Source Sans Pro, Lucida Grande, Tahoma, sans-serif !important

View File

@@ -19,6 +19,9 @@
overflow: hidden overflow: hidden
max-width: clamp(150px,50%,600px) max-width: clamp(150px,50%,600px)
&.banner
top: 53px
.podsCount .podsCount
display: flex display: flex
justify-content: center justify-content: center

View File

@@ -0,0 +1 @@
export const TOAST_CONTAINER_ID = "Common";

View File

@@ -0,0 +1,43 @@
import { useState, useEffect } from 'react';
function getWindowDimensions() {
const { innerWidth: width, innerHeight: height } = window;
return {
width,
height
};
}
export function useRequestTextByWidth(windowWidth){
let requestText = "Request: "
let responseText = "Response: "
let elapsedTimeText = "Elapsed Time: "
if (windowWidth < 1078) {
requestText = ""
responseText = ""
elapsedTimeText = ""
} else if (windowWidth < 1356) {
requestText = "Req: "
responseText = "Res: "
elapsedTimeText = "ET: "
}
return {requestText, responseText, elapsedTimeText}
}
export default function useWindowDimensions() {
const [windowDimensions, setWindowDimensions] = useState(getWindowDimensions());
useEffect(() => {
function handleResize() {
setWindowDimensions(getWindowDimensions());
}
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return windowDimensions;
}

4657
ui/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -13,7 +13,7 @@
"@types/jest": "^26.0.22", "@types/jest": "^26.0.22",
"@types/node": "^12.20.10", "@types/node": "^12.20.10",
"@uiw/react-textarea-code-editor": "^1.4.12", "@uiw/react-textarea-code-editor": "^1.4.12",
"@up9/mizu-common": "1.0.131", "@up9/mizu-common": "1.0.142",
"axios": "^0.25.0", "axios": "^0.25.0",
"core-js": "^3.20.2", "core-js": "^3.20.2",
"craco-babel-loader": "^1.0.3", "craco-babel-loader": "^1.0.3",
@@ -75,4 +75,4 @@
"last 1 safari version" "last 1 safari version"
] ]
} }
} }

View File

@@ -3,6 +3,7 @@ import {AuthPresentation} from "../AuthPresentation/AuthPresentation";
import {AnalyzeButton} from "@up9/mizu-common" import {AnalyzeButton} from "@up9/mizu-common"
import logo from '../assets/Mizu-logo.svg'; import logo from '../assets/Mizu-logo.svg';
import './Header.sass'; import './Header.sass';
import {UI} from "@up9/mizu-common"
interface HeaderProps { interface HeaderProps {
analyzeStatus: any analyzeStatus: any
@@ -15,6 +16,7 @@ export const Header: React.FC<HeaderProps> = ({analyzeStatus}) => {
</div> </div>
<div style={{display: "flex", alignItems: "center"}}> <div style={{display: "flex", alignItems: "center"}}>
{analyzeStatus?.isAnalyzing && <AnalyzeButton analyzeStatus={analyzeStatus}/>} {analyzeStatus?.isAnalyzing && <AnalyzeButton analyzeStatus={analyzeStatus}/>}
<UI.InformationIcon/>
<AuthPresentation/> <AuthPresentation/>
</div> </div>
</div>; </div>;

View File

@@ -40,19 +40,19 @@ const trafficViewerApi = {...api}
{window["isOasEnabled"] && <Button {window["isOasEnabled"] && <Button
startIcon={<img className="custom" src={services} alt="services"></img>} startIcon={<img className="custom" src={services} alt="services"></img>}
size="large" size="large"
type="submit"
variant="contained" variant="contained"
className={commonClasses.outlinedButton + " " + commonClasses.imagedButton} className={commonClasses.outlinedButton + " " + commonClasses.imagedButton}
style={{ marginRight: 25 }} style={{ marginRight: 25, textTransform: 'unset' }}
onClick={handleOpenOasModal}> onClick={handleOpenOasModal}>
Show OAS OpenAPI Specs
</Button>} </Button>}
{window["isServiceMapEnabled"] && <Button {window["isServiceMapEnabled"] && <Button
startIcon={<img src={serviceMap} className="custom" alt="service-map" style={{marginRight:"8%"}}></img>} startIcon={<img src={serviceMap} className="custom" alt="service-map" style={{marginRight:"8%"}}></img>}
size="large" size="large"
variant="contained" variant="contained"
className={commonClasses.outlinedButton + " " + commonClasses.imagedButton} className={commonClasses.outlinedButton + " " + commonClasses.imagedButton}
onClick={openServiceMapModalDebounce}> onClick={openServiceMapModalDebounce}
style={{textTransform: 'unset'}}>
Service Map Service Map
</Button>} </Button>}
</div> </div>
@@ -66,7 +66,7 @@ const trafficViewerApi = {...api}
return ( return (
<> <>
<TrafficViewer setAnalyzeStatus={setAnalyzeStatus} webSocketUrl={getWebsocketUrl()} isCloseWebSocket={!openWebSocket} <TrafficViewer setAnalyzeStatus={setAnalyzeStatus} webSocketUrl={getWebsocketUrl()} isCloseWebSocket={!openWebSocket}
trafficViewerApiProp={trafficViewerApi} actionButtons={actionButtons} isShowStatusBar={!openOasModal}/> trafficViewerApiProp={trafficViewerApi} actionButtons={actionButtons} isShowStatusBar={!openOasModal} isDemoBannerView={false}/>
</> </>
); );
}; };

View File

@@ -11,6 +11,7 @@ import ServiceMapOptions from './ServiceMapOptions'
import { useCommonStyles } from "../../helpers/commonStyle"; import { useCommonStyles } from "../../helpers/commonStyle";
import refresh from "../assets/refresh.svg"; import refresh from "../assets/refresh.svg";
import close from "../assets/close.svg"; import close from "../assets/close.svg";
import { TOAST_CONTAINER_ID } from "../../consts";
interface GraphData { interface GraphData {
nodes: Node[]; nodes: Node[];
@@ -140,7 +141,7 @@ export const ServiceMapModal: React.FC<ServiceMapModalProps> = ({ isOpen, onOpen
setGraphData(newGraphData) setGraphData(newGraphData)
} catch (ex) { } catch (ex) {
toast.error("An error occurred while loading Mizu Service Map, see console for mode details"); toast.error("An error occurred while loading Mizu Service Map, see console for mode details", { containerId: TOAST_CONTAINER_ID });
console.error(ex); console.error(ex);
} finally { } finally {
setIsLoading(false) setIsLoading(false)
@@ -176,20 +177,20 @@ export const ServiceMapModal: React.FC<ServiceMapModalProps> = ({ isOpen, onOpen
<img alt="spinner" src={spinnerImg} style={{ height: 50 }} /> <img alt="spinner" src={spinnerImg} style={{ height: 50 }} />
</div>} </div>}
{!isLoading && <div style={{ height: "100%", width: "100%" }}> {!isLoading && <div style={{ height: "100%", width: "100%" }}>
<div style={{ display: "flex", justifyContent: "space-between" }}> <div style={{ display: "flex", justifyContent: "space-between" }}>
<div> <div>
<Button <Button
startIcon={<img src={refresh} className="custom" alt="refresh" style={{ marginRight:"8%"}}></img>} startIcon={<img src={refresh} className="custom" alt="refresh" style={{ marginRight: "8%" }}></img>}
size="medium" size="medium"
variant="contained" variant="contained"
className={commonClasses.outlinedButton + " " + commonClasses.imagedButton} className={commonClasses.outlinedButton + " " + commonClasses.imagedButton}
onClick={refreshServiceMap} onClick={refreshServiceMap}
> >
Refresh Refresh
</Button> </Button>
</div>
<img src={close} alt="close" onClick={() => onClose()} style={{ cursor: "pointer" }}></img>
</div> </div>
<img src={close} alt="close" onClick={() => onClose()} style={{cursor:"pointer"}}></img>
</div>
<Graph <Graph
graph={graphData} graph={graphData}
options={ServiceMapOptions} options={ServiceMapOptions}

View File

@@ -1 +1,2 @@
export const adminUsername = "admin"; export const adminUsername = "admin";
export const TOAST_CONTAINER_ID = "Community";

View File

@@ -1,14 +1,15 @@
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import './index.sass'; import './index.sass';
import {ToastContainer} from "react-toastify"; import {ToastContainer} from "react-toastify";
import 'react-toastify/dist/ReactToastify.css'; import 'react-toastify/dist/ReactToastify.min.css';
import {RecoilRoot} from "recoil"; import {RecoilRoot} from "recoil";
import App from './App'; import App from './App';
import { TOAST_CONTAINER_ID } from './consts';
ReactDOM.render( <> ReactDOM.render( <>
<RecoilRoot> <RecoilRoot>
<App/> <App/>
<ToastContainer <ToastContainer enableMultiContainer containerId={TOAST_CONTAINER_ID}
position="bottom-right" position="bottom-right"
autoClose={5000} autoClose={5000}
hideProgressBar={false} hideProgressBar={false}