Compare commits

..

4 Commits

Author SHA1 Message Date
M. Mert Yıldıran
03b1313a9f Don't use Queryable for the Mime type and Encoding fields but use it directly in CollapsibleTitle suffixed components and only enable it for EntryBodySection (#550)
Co-authored-by: gadotroee <55343099+gadotroee@users.noreply.github.com>
2021-12-23 17:45:51 +03:00
M. Mert Yıldıran
32dfe40e18 Make EntryItem more responsive (#552) 2021-12-23 10:25:39 +03:00
M. Mert Yıldıran
12aaa762f6 Fix React Hook useEffect has a missing dependency: 'handleQueryChange' warning (#551) 2021-12-22 20:23:21 +03:00
David Levanon
a75bac181d support linkerd (#547)
* support linkerd - initial commit

* renaming readEnvironmentVariable
2021-12-20 13:57:58 +02:00
8 changed files with 220 additions and 81 deletions

View File

@@ -0,0 +1,38 @@
package source
import (
"io/ioutil"
"regexp"
"strings"
"github.com/up9inc/mizu/shared/logger"
)
var numberRegex = regexp.MustCompile("[0-9]+")
func getSingleValueFromEnvironmentVariableFile(filePath string, variableName string) (string, error) {
bytes, err := ioutil.ReadFile(filePath)
if err != nil {
logger.Log.Warningf("Error reading environment file %v - %v", filePath, err)
return "", err
}
envs := strings.Split(string(bytes), string([]byte{0}))
for _, env := range envs {
if !strings.Contains(env, "=") {
continue
}
parts := strings.Split(env, "=")
varName := parts[0]
value := parts[1]
if variableName == varName {
return value, nil
}
}
return "", nil
}

View File

@@ -4,7 +4,6 @@ import (
"fmt"
"io/ioutil"
"os"
"regexp"
"strings"
"github.com/up9inc/mizu/shared/logger"
@@ -13,8 +12,6 @@ import (
const envoyBinary = "/envoy"
var numberRegex = regexp.MustCompile("[0-9]+")
func discoverRelevantEnvoyPids(procfs string, pods []v1.Pod) ([]string, error) {
result := make([]string, 0)
@@ -36,7 +33,7 @@ func discoverRelevantEnvoyPids(procfs string, pods []v1.Pod) ([]string, error) {
continue
}
if checkPid(procfs, pid.Name(), pods) {
if checkEnvoyPid(procfs, pid.Name(), pods) {
result = append(result, pid.Name())
}
}
@@ -46,7 +43,7 @@ func discoverRelevantEnvoyPids(procfs string, pods []v1.Pod) ([]string, error) {
return result, nil
}
func checkPid(procfs string, pid string, pods []v1.Pod) bool {
func checkEnvoyPid(procfs string, pid string, pods []v1.Pod) bool {
execLink := fmt.Sprintf("%v/%v/exe", procfs, pid)
exec, err := os.Readlink(execLink)
@@ -63,7 +60,7 @@ func checkPid(procfs string, pid string, pods []v1.Pod) bool {
}
environmentFile := fmt.Sprintf("%v/%v/environ", procfs, pid)
podIp, err := readEnvironmentVariable(environmentFile, "INSTANCE_IP")
podIp, err := getSingleValueFromEnvironmentVariableFile(environmentFile, "INSTANCE_IP")
if err != nil {
return false
@@ -84,30 +81,3 @@ func checkPid(procfs string, pid string, pods []v1.Pod) bool {
return false
}
func readEnvironmentVariable(file string, name string) (string, error) {
bytes, err := ioutil.ReadFile(file)
if err != nil {
logger.Log.Warningf("Error reading environment file %v - %v", file, err)
return "", err
}
envs := strings.Split(string(bytes), string([]byte{0}))
for _, env := range envs {
if !strings.Contains(env, "=") {
continue
}
parts := strings.Split(env, "=")
varName := parts[0]
value := parts[1]
if name == varName {
return value, nil
}
}
return "", nil
}

View File

@@ -0,0 +1,83 @@
package source
import (
"fmt"
"io/ioutil"
"os"
"strings"
"github.com/up9inc/mizu/shared/logger"
v1 "k8s.io/api/core/v1"
)
const linkerdBinary = "/linkerd2-proxy"
func discoverRelevantLinkerdPids(procfs string, pods []v1.Pod) ([]string, error) {
result := make([]string, 0)
pids, err := ioutil.ReadDir(procfs)
if err != nil {
return result, err
}
logger.Log.Infof("Starting linkerd auto discoverer %v %v - scanning %v potential pids",
procfs, pods, len(pids))
for _, pid := range pids {
if !pid.IsDir() {
continue
}
if !numberRegex.MatchString(pid.Name()) {
continue
}
if checkLinkerdPid(procfs, pid.Name(), pods) {
result = append(result, pid.Name())
}
}
logger.Log.Infof("Found %v relevant linkerd processes - %v", len(result), result)
return result, nil
}
func checkLinkerdPid(procfs string, pid string, pods []v1.Pod) bool {
execLink := fmt.Sprintf("%v/%v/exe", procfs, pid)
exec, err := os.Readlink(execLink)
if err != nil {
// Debug on purpose - it may happen due to many reasons and we only care
// for it during troubleshooting
//
logger.Log.Debugf("Unable to read link %v - %v\n", execLink, err)
return false
}
if !strings.HasSuffix(exec, linkerdBinary) {
return false
}
environmentFile := fmt.Sprintf("%v/%v/environ", procfs, pid)
podName, err := getSingleValueFromEnvironmentVariableFile(environmentFile, "_pod_name")
if err != nil {
return false
}
if podName == "" {
logger.Log.Debugf("Found a linkerd process without _pod_name variable %v\n", pid)
return false
}
logger.Log.Infof("Found linkerd pid %v with pod name %v", pid, podName)
for _, pod := range pods {
if pod.Name == podName {
return true
}
}
return false
}

View File

@@ -16,7 +16,7 @@ type PacketSourceManager struct {
}
func NewPacketSourceManager(procfs string, pids string, filename string, interfaceName string,
istio bool, pods []v1.Pod, behaviour TcpPacketSourceBehaviour) (*PacketSourceManager, error) {
mtls bool, pods []v1.Pod, behaviour TcpPacketSourceBehaviour) (*PacketSourceManager, error) {
sources := make([]*tcpPacketSource, 0)
sources, err := createHostSource(sources, filename, interfaceName, behaviour)
@@ -25,7 +25,8 @@ func NewPacketSourceManager(procfs string, pids string, filename string, interfa
}
sources = createSourcesFromPids(sources, procfs, pids, interfaceName, behaviour)
sources = createSourcesFromEnvoy(sources, istio, procfs, pods, interfaceName, behaviour)
sources = createSourcesFromEnvoy(sources, mtls, procfs, pods, interfaceName, behaviour)
sources = createSourcesFromLinkerd(sources, mtls, procfs, pods, interfaceName, behaviour)
return &PacketSourceManager{
sources: sources,
@@ -54,13 +55,13 @@ func createSourcesFromPids(sources []*tcpPacketSource, procfs string, pids strin
return sources
}
func createSourcesFromEnvoy(sources []*tcpPacketSource, istio bool, procfs string, clusterIps []v1.Pod,
func createSourcesFromEnvoy(sources []*tcpPacketSource, mtls bool, procfs string, pods []v1.Pod,
interfaceName string, behaviour TcpPacketSourceBehaviour) []*tcpPacketSource {
if !istio {
if !mtls {
return sources
}
envoyPids, err := discoverRelevantEnvoyPids(procfs, clusterIps)
envoyPids, err := discoverRelevantEnvoyPids(procfs, pods)
if err != nil {
logger.Log.Warningf("Unable to discover envoy pids - %v", err)
@@ -73,6 +74,25 @@ func createSourcesFromEnvoy(sources []*tcpPacketSource, istio bool, procfs strin
return sources
}
func createSourcesFromLinkerd(sources []*tcpPacketSource, mtls bool, procfs string, pods []v1.Pod,
interfaceName string, behaviour TcpPacketSourceBehaviour) []*tcpPacketSource {
if !mtls {
return sources
}
linkerdPids, err := discoverRelevantLinkerdPids(procfs, pods)
if err != nil {
logger.Log.Warningf("Unable to discover linkerd pids - %v", err)
return sources
}
netnsSources := newNetnsPacketSources(procfs, linkerdPids, interfaceName, behaviour)
sources = append(sources, netnsSources...)
return sources
}
func newHostPacketSource(filename string, interfaceName string,
behaviour TcpPacketSourceBehaviour) (*tcpPacketSource, error) {
var name string

View File

@@ -10,12 +10,14 @@ import ProtobufDecoder from "protobuf-decoder";
interface EntryViewLineProps {
label: string;
value: number | string;
updateQuery: any;
selector: string;
updateQuery?: any;
selector?: string;
overrideQueryValue?: string;
displayIconOnMouseOver?: boolean;
useTooltip?: boolean;
}
const EntryViewLine: React.FC<EntryViewLineProps> = ({label, value, updateQuery, selector, overrideQueryValue}) => {
const EntryViewLine: React.FC<EntryViewLineProps> = ({label, value, updateQuery = null, selector = "", overrideQueryValue = "", displayIconOnMouseOver = true, useTooltip = true}) => {
let query: string;
if (!selector) {
query = "";
@@ -34,7 +36,8 @@ const EntryViewLine: React.FC<EntryViewLineProps> = ({label, value, updateQuery,
style={{float: "right", height: "18px"}}
iconStyle={{marginRight: "20px"}}
flipped={true}
displayIconOnMouseOver={true}
useTooltip={useTooltip}
displayIconOnMouseOver={displayIconOnMouseOver}
>
{label}
</Queryable>
@@ -55,30 +58,47 @@ const EntryViewLine: React.FC<EntryViewLineProps> = ({label, value, updateQuery,
interface EntrySectionCollapsibleTitleProps {
title: string,
color: string,
isExpanded: boolean,
expanded: boolean,
setExpanded: any,
query?: string,
updateQuery?: any,
}
const EntrySectionCollapsibleTitle: React.FC<EntrySectionCollapsibleTitleProps> = ({title, color, isExpanded}) => {
const EntrySectionCollapsibleTitle: React.FC<EntrySectionCollapsibleTitleProps> = ({title, color, expanded, setExpanded, query = "", updateQuery = null}) => {
return <div className={styles.title}>
<div className={`${styles.button} ${isExpanded ? styles.expanded : ''}`} style={{backgroundColor: color}}>
{isExpanded ? '-' : '+'}
<div
className={`${styles.button} ${expanded ? styles.expanded : ''}`}
style={{backgroundColor: color}}
onClick={() => {
setExpanded(!expanded)
}}
>
{expanded ? '-' : '+'}
</div>
<span>{title}</span>
<Queryable
query={query}
updateQuery={updateQuery}
useTooltip={updateQuery ? true : false}
displayIconOnMouseOver={updateQuery ? true : false}
>
<span>{title}</span>
</Queryable>
</div>
}
interface EntrySectionContainerProps {
title: string,
color: string,
query?: string,
updateQuery?: any,
}
export const EntrySectionContainer: React.FC<EntrySectionContainerProps> = ({title, color, children}) => {
export const EntrySectionContainer: React.FC<EntrySectionContainerProps> = ({title, color, children, query = "", updateQuery = null}) => {
const [expanded, setExpanded] = useState(true);
return <CollapsibleContainer
className={styles.collapsibleContainer}
isExpanded={expanded}
onClick={() => setExpanded(!expanded)}
title={<EntrySectionCollapsibleTitle title={title} color={color} isExpanded={expanded}/>}
expanded={expanded}
title={<EntrySectionCollapsibleTitle title={title} color={color} expanded={expanded} setExpanded={setExpanded} query={query} updateQuery={updateQuery}/>}
>
{children}
</CollapsibleContainer>
@@ -133,11 +153,16 @@ export const EntryBodySection: React.FC<EntryBodySectionProps> = ({
}
return <React.Fragment>
{content && content?.length > 0 && <EntrySectionContainer title='Body' color={color}>
{content && content?.length > 0 && <EntrySectionContainer
title='Body'
color={color}
query={`${selector} == r".*"`}
updateQuery={updateQuery}
>
<table>
<tbody>
<EntryViewLine label={'Mime type'} value={contentType} updateQuery={updateQuery} selector={selector} overrideQueryValue={`r".*"`}/>
{encoding && <EntryViewLine label={'Encoding'} value={encoding} updateQuery={updateQuery} selector={selector} overrideQueryValue={`r".*"`}/>}
<EntryViewLine label={'Mime type'} value={contentType} useTooltip={false}/>
{encoding && <EntryViewLine label={'Encoding'} value={encoding} useTooltip={false}/>}
</tbody>
</table>
@@ -195,13 +220,20 @@ interface EntryPolicySectionProps {
interface EntryPolicySectionCollapsibleTitleProps {
label: string;
matched: string;
isExpanded: boolean;
expanded: boolean;
setExpanded: any;
}
const EntryPolicySectionCollapsibleTitle: React.FC<EntryPolicySectionCollapsibleTitleProps> = ({label, matched, isExpanded}) => {
const EntryPolicySectionCollapsibleTitle: React.FC<EntryPolicySectionCollapsibleTitleProps> = ({label, matched, expanded, setExpanded}) => {
return <div className={styles.title}>
<span className={`${styles.button} ${isExpanded ? styles.expanded : ''}`}>
{isExpanded ? '-' : '+'}
<span
className={`${styles.button}
${expanded ? styles.expanded : ''}`}
onClick={() => {
setExpanded(!expanded)
}}
>
{expanded ? '-' : '+'}
</span>
<span>
<tr className={styles.dataLine}>
@@ -222,9 +254,8 @@ export const EntryPolicySectionContainer: React.FC<EntryPolicySectionContainerPr
const [expanded, setExpanded] = useState(false);
return <CollapsibleContainer
className={styles.collapsibleContainer}
isExpanded={expanded}
onClick={() => setExpanded(!expanded)}
title={<EntryPolicySectionCollapsibleTitle label={label} matched={matched} isExpanded={expanded}/>}
expanded={expanded}
title={<EntryPolicySectionCollapsibleTitle label={label} matched={matched} expanded={expanded} setExpanded={setExpanded}/>}
>
{children}
</CollapsibleContainer>

View File

@@ -92,3 +92,13 @@
.ip
margin-left: 5px
@media (max-width: 1760px)
.timestamp
display: none
.separatorRight
border-right: 0px
@media (max-width: 1340px)
.separatorRight
display: none

View File

@@ -91,7 +91,7 @@ export const TrafficPage: React.FC<TrafficPageProps> = ({setAnalyzeStatus, onTLS
useEffect(() => {
handleQueryChange(query);
}, [query]);
}, [query, handleQueryChange]);
useEffect(() => {
if (query) {

View File

@@ -1,38 +1,25 @@
import React, {useState} from "react";
import React from "react";
import collapsedImg from "../assets/collapsed.svg";
import expandedImg from "../assets/expanded.svg";
import "./style/CollapsibleContainer.sass";
interface Props {
title: string | React.ReactNode,
onClick?: (e: React.SyntheticEvent) => void,
isExpanded?: boolean,
expanded: boolean,
titleClassName?: string,
stickyHeader?: boolean,
className?: string,
initialExpanded?: boolean;
passiveOnClick?: boolean; //whether specifying onClick overrides internal _isExpanded state handling
stickyHeader?: boolean,
}
const CollapsibleContainer: React.FC<Props> = ({title, children, isExpanded, onClick, titleClassName, stickyHeader = false, className, initialExpanded = true, passiveOnClick}) => {
const [_isExpanded, _setExpanded] = useState(initialExpanded);
let expanded = isExpanded !== undefined ? isExpanded : _isExpanded;
const CollapsibleContainer: React.FC<Props> = ({title, children, expanded, titleClassName, className, stickyHeader = false}) => {
const classNames = `CollapsibleContainer ${expanded ? "CollapsibleContainer-Expanded" : "CollapsibleContainer-Collapsed"} ${className ? className : ''}`;
// This is needed to achieve the sticky header feature.
// This is needed to achieve the sticky header feature.
// It is needed an un-contained component for the css to work properly.
const content = <React.Fragment>
<div
className={`CollapsibleContainer-Header ${stickyHeader ? "CollapsibleContainer-Header-Sticky" : ""}
className={`CollapsibleContainer-Header ${stickyHeader ? "CollapsibleContainer-Header-Sticky" : ""}
${expanded ? "CollapsibleContainer-Header-Expanded" : ""}`}
onClick={(e) => {
if (onClick) {
onClick(e)
if (passiveOnClick !== true)
return;
}
_setExpanded(!_isExpanded)
}}
>
{
React.isValidElement(title)?