Compare commits

..

11 Commits

Author SHA1 Message Date
lirazyehezkel
32ba653d12 TLS icon z index (#1028) 2022-04-20 14:34:16 +03:00
AmitUp9
e03db7b09b Bug/UI/tra 4473 grpc decoding error (#1025)
* note added and formatting added

* showing message on ui instead of console error
2022-04-20 11:20:14 +03:00
gadotroee
de533730d3 Change the affinity to be valid when we are tapping multiple nodes (#1023) 2022-04-19 19:35:17 +03:00
lirazyehezkel
d834fcc3cb Entries count changes frequently (#1021)
Co-authored-by: leon-up9 <97597983+leon-up9@users.noreply.github.com>
2022-04-19 19:19:43 +03:00
gadotroee
1624b0d7b9 Apply daemon set by field selector metadata.name instead of label (#1022) 2022-04-19 18:22:29 +03:00
M. Mert Yıldıran
9715bb046b GetEntry unmarshaling error indicates an error message sent by the database server (#1020) 2022-04-19 16:23:23 +03:00
M. Mert Yıldıran
65e5ebe23c Upgrade Basenine to 0.7.3 (#1019)
* Upgrade Basenine to `0.7.3`

* Bring back `github.com/patrickmn/go-cache` that's removed by `go mod tidy`
2022-04-19 14:10:37 +03:00
leon-up9
30986c3b22 Link component (#1005)
* Link component

* change defualt use

* PR comments

Co-authored-by: Leon <>
2022-04-19 13:50:34 +03:00
Igor Gov
1e167f2757 Trigger by commit message acceptance test on PR to develop (#1017) 2022-04-19 09:12:30 +03:00
gadotroee
149e86d050 Run unit tests when tap/api changes (#1016)
* update test files paths
2022-04-19 08:51:32 +03:00
David Levanon
1213162b85 Add kube namespace to tls (TRA-4443) (#1013)
* add namespace to tls - initial commit
* add tls namespace to mizu entry
2022-04-18 16:12:51 +03:00
28 changed files with 262 additions and 148 deletions

View File

@@ -0,0 +1,38 @@
name: Acceptance tests on PR
on: push
concurrency:
group: acceptance-tests-on-pr-${{ github.ref }}
cancel-in-progress: true
jobs:
run-tests:
name: Run tests
runs-on: ubuntu-latest
if: ${{ contains(github.event.head_commit.message, '#run_acceptance_tests') }}
steps:
- name: Set up Go 1.17
uses: actions/setup-go@v2
with:
go-version: '^1.17'
- name: Check out code into the Go module directory
uses: actions/checkout@v2
- name: Setup acceptance test
run: ./acceptanceTests/setup.sh
- name: Create k8s users and change context
env:
USERNAME_UNRESTRICTED: user-with-clusterwide-access
USERNAME_RESTRICTED: user-with-restricted-access
run: |
./acceptanceTests/create_user.sh "${USERNAME_UNRESTRICTED}"
./acceptanceTests/create_user.sh "${USERNAME_RESTRICTED}"
kubectl apply -f cli/cmd/permissionFiles/permissions-all-namespaces-tap.yaml
kubectl config use-context ${USERNAME_UNRESTRICTED}
- name: Test
run: make acceptance-test

View File

@@ -56,7 +56,7 @@ jobs:
- name: Check extensions modified files
id: ext_modified_files
run: devops/check_modified_files.sh tap/extensions/
run: devops/check_modified_files.sh tap/extensions/ tap/api/
- name: Extensions Test
if: github.event_name == 'push' || steps.ext_modified_files.outputs.matched == 'true'
@@ -64,4 +64,3 @@ jobs:
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v2

View File

@@ -87,8 +87,8 @@ RUN go build -ldflags="-extldflags=-static -s -w \
-X 'github.com/up9inc/mizu/agent/pkg/version.Ver=${VER}'" -o mizuagent .
# Download Basenine executable, verify the sha1sum
ADD https://github.com/up9inc/basenine/releases/download/v0.7.2/basenine_linux_${GOARCH} ./basenine_linux_${GOARCH}
ADD https://github.com/up9inc/basenine/releases/download/v0.7.2/basenine_linux_${GOARCH}.sha256 ./basenine_linux_${GOARCH}.sha256
ADD https://github.com/up9inc/basenine/releases/download/v0.7.3/basenine_linux_${GOARCH} ./basenine_linux_${GOARCH}
ADD https://github.com/up9inc/basenine/releases/download/v0.7.3/basenine_linux_${GOARCH}.sha256 ./basenine_linux_${GOARCH}.sha256
RUN shasum -a 256 -c basenine_linux_"${GOARCH}".sha256 && \
chmod +x ./basenine_linux_"${GOARCH}" && \

View File

@@ -19,9 +19,9 @@ require (
github.com/nav-inc/datetime v0.1.3
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
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/up9inc/basenine/client/go v0.0.0-20220413173135-69508ca741d7
github.com/up9inc/basenine/client/go v0.0.0-20220419100955-e2ca51087607
github.com/up9inc/mizu/shared v0.0.0
github.com/up9inc/mizu/tap 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.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ=
github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
github.com/up9inc/basenine/client/go v0.0.0-20220413173135-69508ca741d7 h1:9aciby1Byjn50gVXpOuvWSe48GdSK1uS2bcBKMZYHKI=
github.com/up9inc/basenine/client/go v0.0.0-20220413173135-69508ca741d7/go.mod h1:SvJGPoa/6erhUQV7kvHBwM/0x5LyO6XaG2lUaCaKiUI=
github.com/up9inc/basenine/client/go v0.0.0-20220419100955-e2ca51087607 h1:UqxUSkOYOmsLZWQtMSk02ttnhdRwBRLOLt2aDiS9tEk=
github.com/up9inc/basenine/client/go v0.0.0-20220419100955-e2ca51087607/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/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0=
github.com/wI2L/jsondiff v0.1.1 h1:r2TkoEet7E4JMO5+s1RCY2R0LrNPNHY6hbDeow2hRHw=

View File

@@ -128,6 +128,11 @@ BasenineReconnect:
for item := range outputItems {
extension := extensionsMap[item.Protocol.Name]
resolvedSource, resolvedDestionation, namespace := resolveIP(item.ConnectionInfo)
if namespace == "" && item.Namespace != tapApi.UNKNOWN_NAMESPACE {
namespace = item.Namespace
}
mizuEntry := extension.Dissector.Analyze(item, resolvedSource, resolvedDestionation, namespace)
if extension.Protocol.Name == "http" {
if !disableOASValidation {

View File

@@ -2,6 +2,7 @@ package entries
import (
"encoding/json"
"errors"
"time"
basenine "github.com/up9inc/basenine/client/go"
@@ -64,7 +65,7 @@ func (e *BasenineEntriesProvider) GetEntry(singleEntryRequest *models.SingleEntr
}
err = json.Unmarshal(bytes, &entry)
if err != nil {
return nil, err
return nil, errors.New(string(bytes))
}
extension := app.ExtensionsMap[entry.Protocol.Name]

View File

@@ -11,7 +11,7 @@ require (
github.com/op/go-logging v0.0.0-20160315200505-970db520ece7
github.com/spf13/cobra v1.3.0
github.com/spf13/pflag v1.0.5
github.com/up9inc/basenine/server/lib v0.0.0-20220413173135-69508ca741d7
github.com/up9inc/basenine/server/lib v0.0.0-20220419100955-e2ca51087607
github.com/up9inc/mizu/shared v0.0.0
github.com/up9inc/mizu/tap/api v0.0.0
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/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/up9inc/basenine/server/lib v0.0.0-20220413173135-69508ca741d7 h1:3Mi+0tQFVHXYcrFhwH/h6/2b0tayLcYeFPXyzDV3rvc=
github.com/up9inc/basenine/server/lib v0.0.0-20220413173135-69508ca741d7/go.mod h1:v0hIh31iwDGbkkdeSSppdMNm1oIigfCA2mG2XajKnf8=
github.com/up9inc/basenine/server/lib v0.0.0-20220419100955-e2ca51087607 h1:gCOwbfjsLslDw63yj/3l9d5TH7ikhIWHd7j0lE9U26U=
github.com/up9inc/basenine/server/lib v0.0.0-20220419100955-e2ca51087607/go.mod h1:v0hIh31iwDGbkkdeSSppdMNm1oIigfCA2mG2XajKnf8=
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 v1.1.0 h1:G/1DjNkPpfZCFt9CSh6b5/nY4VimlbHF3Rh4obvtzDk=

View File

@@ -805,14 +805,20 @@ func (provider *Provider) ApplyMizuTapperDaemonSet(ctx context.Context, namespac
agentResources := applyconfcore.ResourceRequirements().WithRequests(agentResourceRequests).WithLimits(agentResourceLimits)
agentContainer.WithResources(agentResources)
nodeSelectorRequirement := applyconfcore.NodeSelectorRequirement()
nodeSelectorRequirement.WithKey("kubernetes.io/hostname")
nodeSelectorRequirement.WithOperator(core.NodeSelectorOpIn)
nodeSelectorRequirement.WithValues(nodeNames...)
nodeSelectorTerm := applyconfcore.NodeSelectorTerm()
nodeSelectorTerm.WithMatchExpressions(nodeSelectorRequirement)
matchFields := make([]*applyconfcore.NodeSelectorTermApplyConfiguration, 0)
for _, nodeName := range nodeNames {
nodeSelectorRequirement := applyconfcore.NodeSelectorRequirement()
nodeSelectorRequirement.WithKey("metadata.name")
nodeSelectorRequirement.WithOperator(core.NodeSelectorOpIn)
nodeSelectorRequirement.WithValues(nodeName)
nodeSelectorTerm := applyconfcore.NodeSelectorTerm()
nodeSelectorTerm.WithMatchFields(nodeSelectorRequirement)
matchFields = append(matchFields, nodeSelectorTerm)
}
nodeSelector := applyconfcore.NodeSelector()
nodeSelector.WithNodeSelectorTerms(nodeSelectorTerm)
nodeSelector.WithNodeSelectorTerms(matchFields...)
nodeAffinity := applyconfcore.NodeAffinity()
nodeAffinity.WithRequiredDuringSchedulingIgnoredDuringExecution(nodeSelector)
affinity := applyconfcore.Affinity()

View File

@@ -26,7 +26,8 @@ func GetNodeHostToTappedPodsMap(tappedPods []core.Pod) shared.NodeToPodsMap {
func getMinimizedPod(fullPod core.Pod) core.Pod {
return core.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: fullPod.Name,
Name: fullPod.Name,
Namespace: fullPod.Namespace,
},
Status: core.PodStatus{
PodIP: fullPod.Status.PodIP,

View File

@@ -18,6 +18,7 @@ import (
)
const mizuTestEnvVar = "MIZU_TEST"
const UNKNOWN_NAMESPACE = ""
var UnknownIp net.IP = net.IP{0, 0, 0, 0}
var UnknownPort uint16 = 0
@@ -92,14 +93,15 @@ type RequestResponsePair struct {
Response GenericMessage `json:"response"`
}
// `Protocol` is modified in the later stages of data propagation. Therefore it's not a pointer.
type OutputChannelItem struct {
// `Protocol` is modified in later stages of data propagation. Therefore, it's not a pointer.
Protocol Protocol
Capture Capture
Timestamp int64
ConnectionInfo *ConnectionInfo
Pair *RequestResponsePair
Summary *BaseEntry
Namespace string
}
type SuperTimer struct {

View File

@@ -13,4 +13,4 @@ test-pull-bin:
test-pull-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/expect7/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/expect8/amqp/\* expect

View File

@@ -13,4 +13,4 @@ test-pull-bin:
test-pull-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/expect7/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/expect8/http/\* expect

View File

@@ -13,4 +13,4 @@ test-pull-bin:
test-pull-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/expect7/kafka/\* expect
@[ "${skipexpect}" ] && echo "Skipping downloading expected JSONs" || gsutil -o 'GSUtil:parallel_process_count=5' -o 'GSUtil:parallel_thread_count=5' -m cp -r gs://static.up9.io/mizu/test-pcap/expect8/kafka/\* expect

View File

@@ -13,4 +13,4 @@ test-pull-bin:
test-pull-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/expect7/redis/\* expect
@[ "${skipexpect}" ] && echo "Skipping downloading expected JSONs" || gsutil -o 'GSUtil:parallel_process_count=5' -o 'GSUtil:parallel_thread_count=5' -m cp -r gs://static.up9.io/mizu/test-pcap/expect8/redis/\* expect

View File

@@ -0,0 +1,13 @@
package tlstapper
import "github.com/up9inc/mizu/tap/api"
type tlsEmitter struct {
delegate api.Emitter
namespace string
}
func (e *tlsEmitter) Emit(item *api.OutputChannelItem) {
item.Namespace = e.namespace
e.delegate.Emit(item)
}

View File

@@ -5,6 +5,7 @@ import (
"bytes"
"fmt"
"net"
"sync"
"encoding/binary"
"encoding/hex"
@@ -19,13 +20,14 @@ import (
)
type tlsPoller struct {
tls *TlsTapper
readers map[string]*tlsReader
closedReaders chan string
reqResMatcher api.RequestResponseMatcher
chunksReader *perf.Reader
extension *api.Extension
procfs string
tls *TlsTapper
readers map[string]*tlsReader
closedReaders chan string
reqResMatcher api.RequestResponseMatcher
chunksReader *perf.Reader
extension *api.Extension
procfs string
pidToNamespace sync.Map
}
func newTlsPoller(tls *TlsTapper, extension *api.Extension, procfs string) *tlsPoller {
@@ -151,16 +153,21 @@ func (p *tlsPoller) startNewTlsReader(chunk *tlsChunk, ip net.IP, port uint16, k
tcpid := p.buildTcpId(chunk, ip, port)
go dissect(extension, reader, chunk.isRequest(), &tcpid, emitter, options, p.reqResMatcher)
tlsEmitter := &tlsEmitter{
delegate: emitter,
namespace: p.getNamespace(chunk.Pid),
}
go dissect(extension, reader, chunk.isRequest(), &tcpid, tlsEmitter, options, p.reqResMatcher)
return reader
}
func dissect(extension *api.Extension, reader *tlsReader, isRequest bool, tcpid *api.TcpID,
emitter api.Emitter, options *api.TrafficFilteringOptions, reqResMatcher api.RequestResponseMatcher) {
tlsEmitter *tlsEmitter, options *api.TrafficFilteringOptions, reqResMatcher api.RequestResponseMatcher) {
b := bufio.NewReader(reader)
err := extension.Dissector.Dissect(b, reader.progress, api.Ebpf, isRequest, tcpid, &api.CounterPair{},
&api.SuperTimer{}, &api.SuperIdentifier{}, emitter, options, reqResMatcher)
&api.SuperTimer{}, &api.SuperIdentifier{}, tlsEmitter, options, reqResMatcher)
if err != nil {
logger.Log.Warningf("Error dissecting TLS %v - %v", tcpid, err)
@@ -205,6 +212,33 @@ func (p *tlsPoller) buildTcpId(chunk *tlsChunk, ip net.IP, port uint16) api.TcpI
}
}
func (p *tlsPoller) addPid(pid uint32, namespace string) {
p.pidToNamespace.Store(pid, namespace)
}
func (p *tlsPoller) getNamespace(pid uint32) string {
namespaceIfc, ok := p.pidToNamespace.Load(pid)
if !ok {
return api.UNKNOWN_NAMESPACE
}
namespace, ok := namespaceIfc.(string)
if !ok {
return api.UNKNOWN_NAMESPACE
}
return namespace
}
func (p *tlsPoller) clearPids() {
p.pidToNamespace.Range(func(key, v interface{}) bool {
p.pidToNamespace.Delete(key)
return true
})
}
func (p *tlsPoller) logTls(chunk *tlsChunk, ip net.IP, port uint16) {
var flagsStr string

View File

@@ -24,11 +24,11 @@ func UpdateTapTargets(tls *TlsTapper, pods *[]v1.Pod, procfs string) error {
if err != nil {
return err
}
tls.ClearPids()
for _, pid := range containerPids {
if err := tls.AddPid(procfs, pid); err != nil {
for pid, pod := range containerPids {
if err := tls.AddPid(procfs, pid, pod.Namespace); err != nil {
LogError(err)
}
}
@@ -36,8 +36,8 @@ func UpdateTapTargets(tls *TlsTapper, pods *[]v1.Pod, procfs string) error {
return nil
}
func findContainerPids(procfs string, containerIds map[string]bool) ([]uint32, error) {
result := make([]uint32, 0)
func findContainerPids(procfs string, containerIds map[string]v1.Pod) (map[uint32]v1.Pod, error) {
result := make(map[uint32]v1.Pod)
pids, err := ioutil.ReadDir(procfs)
@@ -63,7 +63,9 @@ func findContainerPids(procfs string, containerIds map[string]bool) ([]uint32, e
continue
}
if _, ok := containerIds[cgroup]; !ok {
pod, ok := containerIds[cgroup]
if !ok {
continue
}
@@ -73,14 +75,14 @@ func findContainerPids(procfs string, containerIds map[string]bool) ([]uint32, e
continue
}
result = append(result, uint32(pidNumber))
result[uint32(pidNumber)] = pod
}
return result, nil
}
func buildContainerIdsMap(pods *[]v1.Pod) map[string]bool {
result := make(map[string]bool)
func buildContainerIdsMap(pods *[]v1.Pod) map[string]v1.Pod {
result := make(map[string]v1.Pod)
for _, pod := range *pods {
for _, container := range pod.Status.ContainerStatuses {
@@ -91,7 +93,7 @@ func buildContainerIdsMap(pods *[]v1.Pod) map[string]bool {
continue
}
result[url.Host] = true
result[url.Host] = pod
}
}
@@ -141,14 +143,14 @@ func extractCgroup(lines []string) string {
// /kubepods.slice/kubepods-burstable.slice/kubepods-burstable-pod3beae8e0_164d_4689_a087_efd902d8c2ab.slice/docker-<ID>.scope
// /kubepods/besteffort/pod7709c1d5-447c-428f-bed9-8ddec35c93f4/<ID>
//
// This function extract the <ID> out of the cgroup path, the <ID> should match
// This function extract the <ID> out of the cgroup path, the <ID> should match
// the "Container ID:" field when running kubectl describe pod <POD>
//
func normalizeCgroup(cgrouppath string) string {
basename := strings.TrimSpace(path.Base(cgrouppath))
if strings.Contains(basename, "-") {
basename = basename[strings.Index(basename, "-") + 1:]
basename = basename[strings.Index(basename, "-")+1:]
}
if strings.Contains(basename, ".") {

View File

@@ -1,11 +1,12 @@
package tlstapper
import (
"sync"
"github.com/cilium/ebpf/rlimit"
"github.com/go-errors/errors"
"github.com/up9inc/mizu/shared/logger"
"github.com/up9inc/mizu/tap/api"
"sync"
)
const GLOABL_TAP_PID = 0
@@ -58,10 +59,10 @@ func (t *TlsTapper) PollForLogging() {
}
func (t *TlsTapper) GlobalTap(sslLibrary string) error {
return t.tapPid(GLOABL_TAP_PID, sslLibrary)
return t.tapPid(GLOABL_TAP_PID, sslLibrary, api.UNKNOWN_NAMESPACE)
}
func (t *TlsTapper) AddPid(procfs string, pid uint32) error {
func (t *TlsTapper) AddPid(procfs string, pid uint32, namespace string) error {
sslLibrary, err := findSsllib(procfs, pid)
if err != nil {
@@ -69,7 +70,7 @@ func (t *TlsTapper) AddPid(procfs string, pid uint32) error {
return nil // hide the error on purpose, its OK for a process to not use libssl.so
}
return t.tapPid(pid, sslLibrary)
return t.tapPid(pid, sslLibrary, namespace)
}
func (t *TlsTapper) RemovePid(pid uint32) error {
@@ -85,12 +86,13 @@ func (t *TlsTapper) RemovePid(pid uint32) error {
}
func (t *TlsTapper) ClearPids() {
t.poller.clearPids()
t.registeredPids.Range(func(key, v interface{}) bool {
pid := key.(uint32)
if pid == GLOABL_TAP_PID {
return true
}
if err := t.RemovePid(pid); err != nil {
LogError(err)
}
@@ -133,7 +135,7 @@ func setupRLimit() error {
return nil
}
func (t *TlsTapper) tapPid(pid uint32, sslLibrary string) error {
func (t *TlsTapper) tapPid(pid uint32, sslLibrary string, namespace string) error {
logger.Log.Infof("Tapping TLS (pid: %v) (sslLibrary: %v)", pid, sslLibrary)
newSsl := sslHooks{}
@@ -144,12 +146,14 @@ func (t *TlsTapper) tapPid(pid uint32, sslLibrary string) error {
t.sslHooksStructs = append(t.sslHooksStructs, newSsl)
t.poller.addPid(pid, namespace)
pids := t.bpfObjects.tlsTapperMaps.PidsMap
if err := pids.Put(pid, uint32(1)); err != nil {
return errors.Wrap(err, 0)
}
t.registeredPids.Store(pid, true)
return nil

View File

@@ -49,7 +49,7 @@
"moment": "^2.29.1",
"node-fetch": "^3.1.1",
"numeral": "^2.0.6",
"protobuf-decoder": "^0.1.0",
"protobuf-decoder": "^0.1.2",
"react-graph-vis": "^1.0.7",
"react-lowlight": "^3.0.0",
"react-router-dom": "^6.2.1",

View File

@@ -12,7 +12,7 @@ import TrafficViewerApiAtom from "../../recoil/TrafficViewerApi";
import TrafficViewerApi from "./TrafficViewerApi";
import focusedEntryIdAtom from "../../recoil/focusedEntryId";
import {toast} from "react-toastify";
import {TOAST_CONTAINER_ID} from "../../configs/Consts";
import {MAX_ENTRIES, TOAST_CONTAINER_ID} from "../../configs/Consts";
import tappingStatusAtom from "../../recoil/tappingStatus";
import leftOffTopAtom from "../../recoil/leftOffTop";
@@ -98,8 +98,8 @@ export const EntriesList: React.FC<EntriesListProps> = ({
setIsLoadingTop(false);
const newEntries = [...data.data.reverse(), ...entries];
if(newEntries.length > 10000) {
newEntries.splice(10000, newEntries.length - 10000)
if(newEntries.length > MAX_ENTRIES) {
newEntries.splice(MAX_ENTRIES, newEntries.length - MAX_ENTRIES)
}
setEntries(newEntries);
@@ -125,9 +125,9 @@ export const EntriesList: React.FC<EntriesListProps> = ({
useEffect(() => {
const newEntries = [...entries];
if (newEntries.length > 10000) {
if (newEntries.length > MAX_ENTRIES) {
setLeftOffTop(newEntries[0].id);
newEntries.splice(0, newEntries.length - 10000)
newEntries.splice(0, newEntries.length - MAX_ENTRIES)
setNoMoreDataTop(false);
setEntries(newEntries);
}
@@ -209,7 +209,7 @@ export const EntriesList: React.FC<EntriesListProps> = ({
</div>
<div className={styles.footer}>
<div>Displaying <b id="entries-length">{entries?.length}</b> results out of <b
<div>Displaying <b id="entries-length">{entries?.length > MAX_ENTRIES ? MAX_ENTRIES : entries?.length}</b> results out of <b
id="total-entries">{queriedTotal}</b> total
</div>
{startTime !== 0 && <div>Started listening at <span style={{

View File

@@ -1,13 +1,13 @@
import styles from "./EntrySections.module.sass";
import React, {useState} from "react";
import {SyntaxHighlighter} from "../../UI/SyntaxHighlighter/index";
import React, { useState } from "react";
import { SyntaxHighlighter } from "../../UI/SyntaxHighlighter/index";
import CollapsibleContainer from "../../UI/CollapsibleContainer";
import FancyTextDisplay from "../../UI/FancyTextDisplay";
import Queryable from "../../UI/Queryable";
import Checkbox from "../../UI/Checkbox";
import ProtobufDecoder from "protobuf-decoder";
import {default as jsonBeautify} from "json-beautify";
import {default as xmlBeautify} from "xml-formatter";
import { default as jsonBeautify } from "json-beautify";
import { default as xmlBeautify } from "xml-formatter";
interface EntryViewLineProps {
label: string;
@@ -18,40 +18,40 @@ interface EntryViewLineProps {
useTooltip?: boolean;
}
const EntryViewLine: React.FC<EntryViewLineProps> = ({label, value, selector = "", overrideQueryValue = "", displayIconOnMouseOver = true, useTooltip = true}) => {
const EntryViewLine: React.FC<EntryViewLineProps> = ({ label, value, selector = "", overrideQueryValue = "", displayIconOnMouseOver = true, useTooltip = true }) => {
let query: string;
if (!selector) {
query = "";
} else if (overrideQueryValue) {
query = `${selector} == ${overrideQueryValue}`;
} else if (typeof(value) == "string") {
} else if (typeof (value) == "string") {
query = `${selector} == "${JSON.stringify(value).slice(1, -1)}"`;
} else {
query = `${selector} == ${value}`;
}
return (label && <tr className={styles.dataLine}>
<td className={`${styles.dataKey}`}>
<Queryable
query={query}
style={{float: "right", height: "18px"}}
iconStyle={{marginRight: "20px"}}
flipped={true}
useTooltip={useTooltip}
displayIconOnMouseOver={displayIconOnMouseOver}
>
{label}
</Queryable>
</td>
<td>
<FancyTextDisplay
className={styles.dataValue}
text={value}
applyTextEllipsis={false}
flipped={true}
displayIconOnMouseOver={true}
/>
</td>
</tr>) || null;
<td className={`${styles.dataKey}`}>
<Queryable
query={query}
style={{ float: "right", height: "18px" }}
iconStyle={{ marginRight: "20px" }}
flipped={true}
useTooltip={useTooltip}
displayIconOnMouseOver={displayIconOnMouseOver}
>
{label}
</Queryable>
</td>
<td>
<FancyTextDisplay
className={styles.dataValue}
text={value}
applyTextEllipsis={false}
flipped={true}
displayIconOnMouseOver={true}
/>
</td>
</tr>) || null;
}
@@ -63,11 +63,11 @@ interface EntrySectionCollapsibleTitleProps {
query?: string,
}
const EntrySectionCollapsibleTitle: React.FC<EntrySectionCollapsibleTitleProps> = ({title, color, expanded, setExpanded, query = ""}) => {
const EntrySectionCollapsibleTitle: React.FC<EntrySectionCollapsibleTitleProps> = ({ title, color, expanded, setExpanded, query = "" }) => {
return <div className={styles.title}>
<div
className={`${styles.button} ${expanded ? styles.expanded : ''}`}
style={{backgroundColor: color}}
style={{ backgroundColor: color }}
onClick={() => {
setExpanded(!expanded)
}}
@@ -90,12 +90,12 @@ interface EntrySectionContainerProps {
query?: string,
}
export const EntrySectionContainer: React.FC<EntrySectionContainerProps> = ({title, color, children, query = ""}) => {
export const EntrySectionContainer: React.FC<EntrySectionContainerProps> = ({ title, color, children, query = "" }) => {
const [expanded, setExpanded] = useState(true);
return <CollapsibleContainer
className={styles.collapsibleContainer}
expanded={expanded}
title={<EntrySectionCollapsibleTitle title={title} color={color} expanded={expanded} setExpanded={setExpanded} query={query}/>}
title={<EntrySectionCollapsibleTitle title={title} color={color} expanded={expanded} setExpanded={setExpanded} query={query} />}
>
{children}
</CollapsibleContainer>
@@ -130,6 +130,7 @@ export const EntryBodySection: React.FC<EntryBodySectionProps> = ({
const isBase64Encoding = encoding === 'base64';
const supportsPrettying = supportedFormats.some(format => contentType?.indexOf(format) > -1);
const [isDecodeGrpc, setIsDecodeGrpc] = useState(true);
const formatTextBody = (body: any): string => {
if (!decodeBase64) return body;
@@ -141,7 +142,7 @@ export const EntryBodySection: React.FC<EntryBodySectionProps> = ({
if (jsonLikeFormats.some(format => contentType?.indexOf(format) > -1)) {
if (!isPretty) return bodyBuf;
return jsonBeautify(JSON.parse(bodyBuf), null, 2, 80);
} else if (xmlLikeFormats.some(format => contentType?.indexOf(format) > -1)) {
} else if (xmlLikeFormats.some(format => contentType?.indexOf(format) > -1)) {
if (!isPretty) return bodyBuf;
return xmlBeautify(bodyBuf, {
indentation: ' ',
@@ -157,49 +158,55 @@ export const EntryBodySection: React.FC<EntryBodySectionProps> = ({
return jsonBeautify(protobufDecoded, null, 2, 80);
}
} catch (error) {
console.error(error);
if(isDecodeGrpc)
setIsDecodeGrpc(false);
if (!String(error).includes("More than one message in")){
console.error(error);
}
}
return bodyBuf;
}
return <React.Fragment>
{content && content?.length > 0 && <EntrySectionContainer
title={title}
color={color}
query={`${selector} == r".*"`}
>
<div style={{display: 'flex', alignItems: 'center', alignContent: 'center', margin: "5px 0"}}>
{supportsPrettying && <div style={{paddingTop: 3}}>
<Checkbox checked={isPretty} onToggle={() => {setIsPretty(!isPretty)}}/>
title={title}
color={color}
query={`${selector} == r".*"`}
>
<div style={{ display: 'flex', alignItems: 'center', alignContent: 'center', margin: "5px 0" }}>
{supportsPrettying && <div style={{ paddingTop: 3 }}>
<Checkbox checked={isPretty} onToggle={() => { setIsPretty(!isPretty) }} />
</div>}
{supportsPrettying && <span style={{marginLeft: '.2rem'}}>Pretty</span>}
{supportsPrettying && <span style={{ marginLeft: '.2rem' }}>Pretty</span>}
<div style={{paddingTop: 3, paddingLeft: supportsPrettying ? 20 : 0}}>
<Checkbox checked={showLineNumbers} onToggle={() => {setShowLineNumbers(!showLineNumbers)}}/>
<div style={{ paddingTop: 3, paddingLeft: supportsPrettying ? 20 : 0 }}>
<Checkbox checked={showLineNumbers} onToggle={() => { setShowLineNumbers(!showLineNumbers) }} />
</div>
<span style={{marginLeft: '.2rem'}}>Line numbers</span>
{isBase64Encoding && <div style={{paddingTop: 3, paddingLeft: 20}}>
<Checkbox checked={decodeBase64} onToggle={() => {setDecodeBase64(!decodeBase64)}}/>
<span style={{ marginLeft: '.2rem' }}>Line numbers</span>
{isBase64Encoding && <div style={{ paddingTop: 3, paddingLeft: 20 }}>
<Checkbox checked={decodeBase64} onToggle={() => { setDecodeBase64(!decodeBase64) }} />
</div>}
{isBase64Encoding && <span style={{marginLeft: '.2rem'}}>Decode Base64</span>}
</div>
{isBase64Encoding && <span style={{ marginLeft: '.2rem' }}>Decode Base64</span>}
{!isDecodeGrpc && <span style={{ fontSize: '12px', color: '#DB2156', marginLeft: '.8rem' }}>More than one message in protobuf payload is not supported</span>}
</div>
<SyntaxHighlighter
<SyntaxHighlighter
code={formatTextBody(content)}
showLineNumbers={showLineNumbers}
/>
</EntrySectionContainer>}
</React.Fragment>
}
interface EntrySectionProps {
title: string,
color: string,
arrayToIterate: any[],
}
export const EntryTableSection: React.FC<EntrySectionProps> = ({title, color, arrayToIterate}) => {
export const EntryTableSection: React.FC<EntrySectionProps> = ({ title, color, arrayToIterate }) => {
let arrayToIterateSorted: any[];
if (arrayToIterate) {
arrayToIterateSorted = arrayToIterate.sort((a, b) => {
@@ -220,7 +227,7 @@ export const EntryTableSection: React.FC<EntrySectionProps> = ({title, color, ar
<EntrySectionContainer title={title} color={color}>
<table>
<tbody id={`tbody-${title}`}>
{arrayToIterateSorted.map(({name, value, selector}, index) => <EntryViewLine
{arrayToIterateSorted.map(({ name, value, selector }, index) => <EntryViewLine
key={index}
label={name}
value={value}
@@ -228,7 +235,7 @@ export const EntryTableSection: React.FC<EntrySectionProps> = ({title, color, ar
/>)}
</tbody>
</table>
</EntrySectionContainer> : <span/>
</EntrySectionContainer> : <span />
}
</React.Fragment>
}
@@ -247,7 +254,7 @@ interface EntryPolicySectionCollapsibleTitleProps {
setExpanded: any;
}
const EntryPolicySectionCollapsibleTitle: React.FC<EntryPolicySectionCollapsibleTitleProps> = ({label, matched, expanded, setExpanded}) => {
const EntryPolicySectionCollapsibleTitle: React.FC<EntryPolicySectionCollapsibleTitleProps> = ({ label, matched, expanded, setExpanded }) => {
return <div className={styles.title}>
<span
className={`${styles.button}
@@ -260,8 +267,8 @@ const EntryPolicySectionCollapsibleTitle: React.FC<EntryPolicySectionCollapsible
</span>
<span>
<tr className={styles.dataLine}>
<td className={`${styles.dataKey} ${styles.rulesTitleSuccess}`}>{label}</td>
<td className={`${styles.dataKey} ${matched === 'Success' ? styles.rulesMatchedSuccess : styles.rulesMatchedFailure}`}>{matched}</td>
<td className={`${styles.dataKey} ${styles.rulesTitleSuccess}`}>{label}</td>
<td className={`${styles.dataKey} ${matched === 'Success' ? styles.rulesMatchedSuccess : styles.rulesMatchedFailure}`}>{matched}</td>
</tr>
</span>
</div>
@@ -273,28 +280,28 @@ interface EntryPolicySectionContainerProps {
children?: any;
}
export const EntryPolicySectionContainer: React.FC<EntryPolicySectionContainerProps> = ({label, matched, children}) => {
export const EntryPolicySectionContainer: React.FC<EntryPolicySectionContainerProps> = ({ label, matched, children }) => {
const [expanded, setExpanded] = useState(false);
return <CollapsibleContainer
className={styles.collapsibleContainer}
expanded={expanded}
title={<EntryPolicySectionCollapsibleTitle label={label} matched={matched} expanded={expanded} setExpanded={setExpanded}/>}
title={<EntryPolicySectionCollapsibleTitle label={label} matched={matched} expanded={expanded} setExpanded={setExpanded} />}
>
{children}
</CollapsibleContainer>
}
export const EntryTablePolicySection: React.FC<EntryPolicySectionProps> = ({title, color, latency, arrayToIterate}) => {
export const EntryTablePolicySection: React.FC<EntryPolicySectionProps> = ({ title, color, latency, arrayToIterate }) => {
return <React.Fragment>
{
arrayToIterate && arrayToIterate.length > 0 ?
<React.Fragment>
<EntrySectionContainer title={title} color={color}>
<table>
<tbody>
{arrayToIterate.map(({rule, matched}, index) => {
<EntrySectionContainer title={title} color={color}>
<table>
<tbody>
{arrayToIterate.map(({ rule, matched }, index) => {
return (
<EntryPolicySectionContainer key={index} label={rule.Name} matched={matched && (rule.Type === 'slo' ? rule.ResponseTime >= latency : true)? "Success" : "Failure"}>
<EntryPolicySectionContainer key={index} label={rule.Name} matched={matched && (rule.Type === 'slo' ? rule.ResponseTime >= latency : true) ? "Success" : "Failure"}>
{
<React.Fragment>
{
@@ -330,11 +337,11 @@ export const EntryTablePolicySection: React.FC<EntryPolicySectionProps> = ({titl
</EntryPolicySectionContainer>
)
}
)
}
</tbody>
</table>
</EntrySectionContainer>
)
}
</tbody>
</table>
</EntrySectionContainer>
</React.Fragment> : <span className={styles.noRules}>No rules could be applied to this request.</span>
}
</React.Fragment>
@@ -347,7 +354,7 @@ interface EntryContractSectionProps {
contractContent: string,
}
export const EntryContractSection: React.FC<EntryContractSectionProps> = ({color, requestReason, responseReason, contractContent}) => {
export const EntryContractSection: React.FC<EntryContractSectionProps> = ({ color, requestReason, responseReason, contractContent }) => {
return <React.Fragment>
{requestReason && <EntrySectionContainer title="Request" color={color}>
{requestReason}

View File

@@ -67,7 +67,6 @@
.capture img
height: 14px
z-index: 1000
margin-top: 12px
margin-left: -2px

View File

@@ -1,19 +1,22 @@
import React, { CSSProperties } from "react";
import React from "react";
import styles from "./style/InformationIcon.module.sass"
const DEFUALT_LINK = "https://getmizu.io/docs"
export interface InformationIconProps {
interface LinkProps {
link?: string,
style?: CSSProperties
className?: string
title?: string
}
export const InformationIcon: React.FC<InformationIconProps> = ({ link, style }) => {
return <React.Fragment>
<a href={DEFUALT_LINK ? DEFUALT_LINK : link} style={style} className={styles.linkStyle} title="documentation" target="_blank">
<span>Docs</span>
</a>
</React.Fragment>
export const Link: React.FC<LinkProps> = ({ link, className, title, children }) => {
return <a href={link} className={className} title={title} target="_blank">
{children}
</a>
}
export const InformationIcon: React.FC<LinkProps> = ({ className }) => {
return <Link title="documentation" className={`${styles.linkStyle} ${className}`} link={DEFUALT_LINK}>
<span>Docs</span>
</Link>
}

View File

@@ -5,10 +5,10 @@ import Tooltip from "./Tooltip";
import Checkbox from "./Checkbox"
import { StatusBar } from "./StatusBar";
import CustomModal from "./CustomModal";
import { InformationIcon } from "./InformationIcon";
import { InformationIcon, Link } from "./InformationIcon";
import SelectList from "./SelectList";
import NoDataMessage from "./NoDataMessage";
export { LoadingOverlay, Select, Tabs, Tooltip, Checkbox, CustomModal, InformationIcon, SelectList, NoDataMessage }
export { LoadingOverlay, Select, Tabs, Tooltip, Checkbox, CustomModal, InformationIcon, SelectList, NoDataMessage, Link }
export { StatusBar }

View File

@@ -1 +1,2 @@
export const TOAST_CONTAINER_ID = "Common";
export const TOAST_CONTAINER_ID = "Common";
export const MAX_ENTRIES = 10000;

View File

@@ -27,7 +27,6 @@
"node-fetch": "^3.1.1",
"node-sass": "^6.0.0",
"numeral": "^2.0.6",
"protobuf-decoder": "^0.1.0",
"react": "^17.0.2",
"react-copy-to-clipboard": "^5.0.3",
"react-dom": "^17.0.2",