linkerd2/web/app/js/components/Debug.jsx

131 lines
3.6 KiB
JavaScript

import BaseTable from './BaseTable.jsx';
import ErrorBanner from './ErrorBanner.jsx';
import { Link } from 'react-router-dom';
import PropTypes from 'prop-types';
import React from 'react';
import Spinner from './util/Spinner.jsx';
import Typography from '@material-ui/core/Typography';
import _each from 'lodash/each';
import _get from 'lodash/get';
import _reduce from 'lodash/reduce';
import { apiErrorPropType } from './util/ApiHelpers.jsx';
import { numericSort } from './util/Utils.js';
import { withContext } from './util/AppContext.jsx';
import withREST from './util/withREST.jsx';
const endpointColumns = [
{
title: "Namespace",
dataIndex: "namespace",
render: d => <Link to={"/namespaces/" + d.namespace}>{d.namespace}</Link>,
sorter: (a, b) => (a.namespace).localeCompare(b.namespace)
},
{
title: "IP",
dataIndex: "ip",
sorter: (a, b) => (a.ip).localeCompare(b.ip)
},
{
title: "Port",
dataIndex: "port",
sorter: (a, b) => numericSort(a.port, b.port)
},
{
title: "Pod",
dataIndex: "name",
sorter: (a, b) => (a.name).localeCompare(b.name),
render: d => <Link to={`/namespaces/${d.namespace}/pods/${d.name}`}>{d.name}</Link>
},
{
title: "Resource Version",
dataIndex: "resourceVersion",
sorter: (a, b) => numericSort(a.resourceVersion, b.resourceVersion)
},
{
title: "Service",
dataIndex: "service",
sorter: (a, b) => (a.service).localeCompare(b.service)
}
];
class Debug extends React.Component {
static defaultProps = {
error: null
}
static propTypes = {
data: PropTypes.arrayOf(PropTypes.shape({})).isRequired,
error: apiErrorPropType,
loading: PropTypes.bool.isRequired,
}
banner = () => {
const { error } = this.props;
if (!error) {
return;
}
return <ErrorBanner message={error} />;
}
loading = () => {
const { loading } = this.props;
if (!loading) {
return;
}
return <Spinner />;
}
render() {
const { data } = this.props;
let results = _get(data, '[0].servicePorts', {});
let rows = _reduce(results, (mem, svc, svcName) => {
let pods = [];
_each(svc.portEndpoints, info => {
info.podAddresses.forEach(podAddress => {
let [podNamespace, podName] = podAddress.pod.name.split("/");
pods.push({
service: svcName,
name: podName,
namespace: podNamespace,
resourceVersion: parseInt(podAddress.pod.resourceVersion, 10),
ip: podAddress.pod.podIP,
port: podAddress.addr.port,
});
});
});
return mem.concat(pods);
}, []);
return (
<React.Fragment>
{this.loading()}
{this.banner()}
<Typography variant="h6">Endpoints</Typography>
<Typography>
This table allows you to see Linkerd&#39;s service discovery state. It
provides debug information about the internal state of the
control-plane&#39;s proxy-api container. Note that this cache of service
discovery information is populated on-demand via linkerd-proxy requests.
No endpoints will be found until a linkerd-proxy begins routing
requests.
</Typography>
<BaseTable
tableRows={rows}
tableColumns={endpointColumns}
tableClassName="metric-table"
defaultOrderBy="namespace"
rowKey={r => r.service + r.name}
padding="dense" />
</React.Fragment>
);
}
}
export default withREST(
withContext(Debug),
({api}) => [api.fetch("/api/endpoints")]
);