UNPKG

@skydive-project/skydive-ui

Version:
622 lines (592 loc) 19.4 kB
import { Node, Link, NodeAttrs } from './Topology' import Tools from './Tools' const WEIGHT_NONE = 0 const WEIGHT_SUBMARINER_BROKER = 2 const WEIGHT_SUBMARINER_CLUSTER = 3 const WEIGHT_SUBMARINER_NODE = 4 const WEIGHT_SUBMARINER_POD = 5 const WEIGHT_FABRIC = 10 const WEIGHT_PHYSICAL = 13 const WEIGHT_BRIDGES = 14 const WEIGHT_PORTS = 15 const WEIGHT_VIRTUAL = 17 const WEIGHT_NAMESPACES = 18 const WEIGHT_VMS = 19 const WEIGHT_K8S_FEDERATION = 100 const WEIGHT_K8S_CLUSTER = 101 const WEIGHT_K8S_NODE = 102 const WEIGHT_K8S_POD = 103 var DefaultConfig = { subTitle: "", filters: [ { id: "default", label: "Default", gremlin: "" }, { id: "namespaces", label: "Namespaces", gremlin: "G.V().Has('Type', 'host').as('host')" + ".out().Has('Type', 'netns').descendants().as('netns')" + ".select('host', 'netns').SubGraph()" } ], defaultFilter: 'default', _newAttrs: function (node: Node): NodeAttrs { var name = node.data.Name if (name.length > 24) { name = node.data.Name.substring(0, 24) + "." } var attrs = { classes: [node.data.Type], name: name, icon: "\uf192", href: '', iconClass: '', weight: 0, badges: [] } return attrs }, _nodeAttrsK8s: function (node: Node): NodeAttrs { var attrs = this._newAttrs(node) switch (node.data.Type) { case "cluster": attrs.href = "assets/icons/cluster.png" attrs.weight = WEIGHT_K8S_CLUSTER break case "configmap": attrs.href = "assets/icons/configmap.png" attrs.weight = WEIGHT_K8S_POD break case "container": attrs.href = "assets/icons/container.png" attrs.weight = WEIGHT_K8S_POD break case "cronjob": attrs.href = "assets/icons/cronjob.png" attrs.weight = WEIGHT_K8S_POD break case "daemonset": attrs.href = "assets/icons/daemonset.png" attrs.weight = WEIGHT_K8S_POD break case "deployment": attrs.href = "assets/icons/deployment.png" attrs.weight = WEIGHT_K8S_POD break case "endpoints": attrs.href = "assets/icons/endpoints.png" attrs.weight = WEIGHT_K8S_POD break case "ingress": attrs.href = "assets/icons/ingress.png" attrs.weight = WEIGHT_K8S_POD break case "job": attrs.href = "assets/icons/job.png" attrs.weight = WEIGHT_K8S_POD break case "node": attrs.icon = "\uf109" attrs.weight = WEIGHT_K8S_NODE break case "persistentvolume": attrs.href = "assets/icons/persistentvolume.png" attrs.weight = WEIGHT_K8S_POD break case "persistentvolumeclaim": attrs.href = "assets/icons/persistentvolumeclaim.png" attrs.weight = WEIGHT_K8S_POD break case "pod": attrs.href = "assets/icons/pod.png" attrs.weight = WEIGHT_K8S_POD break case "networkpolicy": attrs.href = "assets/icons/networkpolicy.png" attrs.weight = WEIGHT_K8S_POD break case "namespace": attrs.icon = "\uf24d" attrs.weight = WEIGHT_K8S_NODE break case "replicaset": attrs.href = "assets/icons/replicaset.png" attrs.weight = WEIGHT_K8S_POD break case "replicationcontroller": attrs.href = "assets/icons/replicationcontroller.png" attrs.weight = WEIGHT_K8S_POD break case "secret": attrs.href = "assets/icons/secret.png" attrs.weight = WEIGHT_K8S_POD break case "service": attrs.href = "assets/icons/service.png" attrs.weight = WEIGHT_K8S_POD break case "statefulset": attrs.href = "assets/icons/statefulset.png" attrs.weight = WEIGHT_K8S_POD break case "storageclass": attrs.href = "assets/icons/storageclass.png" attrs.weight = WEIGHT_K8S_NODE break default: attrs.href = "assets/icons/k8s.png" attrs.weight = WEIGHT_K8S_POD } return attrs }, _nodeAttrsInfra: function (node: Node): NodeAttrs { var attrs = this._newAttrs(node) if (node.data.OfPort) { attrs.weight = WEIGHT_PORTS } switch (node.data.Type) { case "Broker": attrs.icon = "\uf109" attrs.weight = WEIGHT_SUBMARINER_BROKER attrs.badges = ["\uf084"] break case "Cluster": attrs.icon = "\uf6ff" attrs.weight = WEIGHT_SUBMARINER_CLUSTER break case "Node": attrs.icon = "\uf109" attrs.weight = WEIGHT_SUBMARINER_NODE break case "Pod": attrs.icon = "\uf24d" attrs.weight = WEIGHT_SUBMARINER_POD switch (node.data.Rule) { case "routeagent": attrs.badges = ["\uf084"] break case "gateway": attrs.badges = ["\uf1e6","\uf084"] break } break case "host": attrs.icon = "\uf109" attrs.weight = WEIGHT_PHYSICAL break case "switch": attrs.icon = "\uf6ff" break case "bridge": case "ovsbridge": attrs.icon = "\uf6ff" attrs.weight = WEIGHT_BRIDGES break case "erspan": attrs.icon = "\uf1e0" break case "geneve": case "vxlan": case "gre": case "gretap": attrs.icon = "\uf55b" break case "device": case "internal": case "interface": case "tun": case "tap": attrs.icon = "\uf796" attrs.weight = WEIGHT_VIRTUAL break case "veth": attrs.icon = "\uf4d7" attrs.weight = WEIGHT_VIRTUAL break case "switchport": attrs.icon = "\uf0e8" break case "patch": case "port": case "ovsport": attrs.icon = "\uf0e8" attrs.weight = WEIGHT_PORTS break case "netns": attrs.icon = "\uf24d" attrs.weight = WEIGHT_NAMESPACES break case "libvirt": attrs.icon = "\uf109" attrs.weight = WEIGHT_VMS break } if (node.data.Manager === "docker") { attrs.icon = "\uf395" attrs.iconClass = "font-brands" } if (node.data.IPV4 && node.data.IPV4.length) { attrs.weight = WEIGHT_PHYSICAL } var virt = ["tap", "veth", "tun", "openvswitch"] if (node.data.Driver && virt.indexOf(node.data.Driver) < 0) { attrs.weight = WEIGHT_PHYSICAL } if (node.data.Probe === "fabric") { attrs.weight = WEIGHT_FABRIC } if (node.data.Captures) { attrs.badges = ["\uf03d"] } return attrs }, nodeAttrs: function (node: Node): NodeAttrs { switch (node.data.Manager) { case "k8s": return this._nodeAttrsK8s(node) default: return this._nodeAttrsInfra(node) } }, nodeSortFnc: function (a: Node, b: Node) { return a.data.Name.localeCompare(b.data.Name) }, nodeClicked: function (node: Node) { window.App.tc.selectNode(node.id) }, nodeDblClicked: function (node: Node) { window.App.tc.expand(node) }, nodeMenu: function (node: Node) { return [ { class: "", text: "Capture", disabled: false, callback: () => { var api = new window.API.CapturesApi(window.App.apiConf) api.createCapture({ GremlinQuery: `G.V('${node.id}')` }).then(result => { console.log(result) }) } }, { class: "", text: "Capture all", disabled: true, callback: () => { console.log("Capture all") } }, { class: "", text: "Injection", disabled: false, callback: () => { console.log("Injection") } }, { class: "", text: "Flows", disabled: false, callback: () => { console.log("Flows") } }, { class: "", text: "Filter NS(demo)", disabled: false, callback: () => { window.App.loadExtraConfig("/assets/nsconfig.js") } } ] }, nodeTags: function (data) { if (data.Manager && data.Manager === "k8s") { return ["kubernetes"] } else { return ["infrastructure"] } }, defaultNodeTag: "infrastructure", nodeTabTitle: function (node: Node): string { return node.data.Name.substring(0, 8) }, groupSize: 3, groupType: function (node: Node): string | undefined { var nodeType = node.data.Type if (!nodeType) { return } switch (nodeType) { case "configmap": case "cronjob": case "daemonset": case "deployment": case "endpoints": case "ingress": case "job": case "persistentvolume": case "persistentvolumeclaim": case "pod": case "networkpolicy": case "replicaset": case "replicationcontroller": case "secret": case "service": case "statefulset": return "app" default: return nodeType } }, groupName: function (node: Node): string | undefined { if (node.data.K8s) { var labels = node.data.K8s.Labels if (!labels) { return name } var app = labels["k8s-app"] || labels["app"] if (!app) { return "default" } return app } var nodeType = this.groupType(node) if (!nodeType) { return } return nodeType + "(s)" }, weightTitles: function () { return { [WEIGHT_NONE]: "Not classified", [WEIGHT_SUBMARINER_BROKER]: "Broker", [WEIGHT_SUBMARINER_CLUSTER]: "Cluster", [WEIGHT_SUBMARINER_NODE]: "Node", [WEIGHT_SUBMARINER_POD]: "Pod", [WEIGHT_FABRIC]: "Fabric", [WEIGHT_PHYSICAL]: "Physical", [WEIGHT_BRIDGES]: "Bridges", [WEIGHT_PORTS]: "Ports", [WEIGHT_VIRTUAL]: "Virtual", [WEIGHT_NAMESPACES]: "Namespaces", [WEIGHT_VMS]: "VMs", [WEIGHT_K8S_FEDERATION]: "Federations", [WEIGHT_K8S_CLUSTER]: "Clusters", [WEIGHT_K8S_NODE]: "Nodes", [WEIGHT_K8S_POD]: "Pods" } }, suggestions: [ "data.IPV4", "data.MAC", "data.Name", "data.Rule", "data.Node", "data.vxlan" ], nodeDataFields: [ { field: "", title: "General", expanded: true, icon: "\uf05a", sortKeys: function (data) { return ['Name', 'Type', 'MAC', 'Driver', 'State'] }, filterKeys: function (data) { switch (data.Type) { case "host": return ['Name'] default: return ['Name', 'Type', 'MAC', 'Driver', 'State'] } } }, { field: "Sockets", expanded: false, icon: "\uf1e6" }, { field: "Captures", expanded: false, icon: "\uf51f", normalizer: function (data) { for (let capture of data) { capture.ID = capture.ID.split('-')[0] } return data } }, { field: "Injections", expanded: false, icon: "\uf48e" }, { field: "Docker", expanded: false, icon: "\uf395", iconClass: "font-brands" }, { field: "IPV4", expanded: true, icon: "\uf1fa" }, { field: "IPV6", expanded: true, icon: "\uf1fa" }, { field: "LastUpdateMetric", title: "Last metrics", expanded: false, icon: "\uf201", normalizer: function (data) { return { RxPackets: data.RxPackets ? data.RxPackets.toLocaleString() : 0, RxBytes: data.RxBytes ? Tools.prettyBytes(data.RxBytes) : 0, TxPackets: data.TxPackets ? data.TxPackets.toLocaleString() : 0, TxBytes: data.TxPackets ? Tools.prettyBytes(data.TxBytes) : 0, Start: data.Start ? new Date(data.Start).toLocaleString() : 0, Last: data.Last ? new Date(data.Last).toLocaleString() : 0 } }, graph: function (data) { return { type: "LineChart", data: [ [ { type: "datetime", label: "time" }, "RxBytes", "TxBytes" ], [new Date(data.Last || 0), data.RxBytes || 0, data.TxBytes || 0] ] } } }, { field: "Metric", title: "Total metrics", expanded: false, icon: "\uf201", normalizer: function (data) { return { RxPackets: data.RxPackets ? data.RxPackets.toLocaleString() : 0, RxBytes: data.RxBytes ? Tools.prettyBytes(data.RxBytes) : 0, TxPackets: data.TxPackets ? data.TxPackets.toLocaleString() : 0, TxBytes: data.TxPackets ? Tools.prettyBytes(data.TxBytes) : 0, Last: data.Last ? new Date(data.Last).toLocaleString() : 0 } } }, { field: "Features", expanded: false, icon: "\uf022" }, { field: "FDB", expanded: false, icon: "\uf0ce" }, { field: "Neighbors", expanded: false, icon: "\uf0ce" }, { field: "RoutingTables", title: "Routing tables", expanded: false, icon: "\uf0ce", normalizer: function (data) { var rows = new Array<any>() for (let table of data) { if (!table.Routes) { continue } for (let route of table.Routes) { if (!route.NextHops) { continue } for (let nh of route.NextHops) { rows.push({ ID: table.ID, Src: table.Src, Protocol: route["Protocol"], Prefix: route["Prefix"], Priority: nh["Priority"], IP: nh["IP"], IfIndex: nh["IfIndex"] }) } } } return rows } } ], linkAttrs: function (link: Link) { var metric = link.source.data.LastUpdateMetric var bandwidth = 0 if (metric) { bandwidth = (metric.RxBytes + metric.TxBytes) * 8 bandwidth /= (metric.Last - metric.Start) / 1000 } var attrs = { classes: [link.data.RelationType], icon: "\uf362", directed: false, href: '', iconClass: '', label: bandwidth ? Tools.prettyBandwidth(bandwidth) : "" } if (bandwidth > 0) { attrs.classes.push('traffic') } if (link.data.RelationType === "layer2") { attrs.classes.push("traffic") } if (link.data.Directed) { attrs.directed = true } switch (link.data.RelationType) { case "ipsec": attrs.label = link.data.RelationType attrs.classes.push("traffic") attrs.classes.push('ipsec_traffic') break case "vxlan": attrs.label = link.data.RelationType attrs.classes.push("traffic") attrs.classes.push('vxlan_traffic') break } return attrs }, linkTabTitle: function (link: Link) { var src = link.source.data.Name var dst = link.target.data.Name if (src && dst) { return src.substring(0, 8) + " / " + dst.substring(0, 8) } return link.id.split("-")[0] }, linkDataFields: [ { field: "", title: "General", expanded: true, icon: "\uf05a", }, { field: "NSM", title: "Network Service Mesh", expanded: true, icon: "\uf542", }, { field: "NSM.Source", title: "Source", expanded: false, icon: "\uf018", }, { field: "NSM.Via", title: "Via", expanded: false, icon: "\uf018", }, { field: "NSM.Destination", title: "Destination", expanded: false, icon: "\uf018", } ], defaultLinkTagMode: function (tag: string): number { return 2 } } export default DefaultConfig