Skip to content

Add an Endpoints view to the web dashboard#2275

Merged
rmars merged 9 commits intomasterfrom
rmars/endpoints
Feb 21, 2019
Merged

Add an Endpoints view to the web dashboard#2275
rmars merged 9 commits intomasterfrom
rmars/endpoints

Conversation

@rmars
Copy link

@rmars rmars commented Feb 13, 2019

In #2195 we introduced linkerd endpoints on the CLI. I would like similar information to be on the web.

This PR adds an api endpoint at /api/endpoints, and introduces a new page with a table that is the same as the CLI table, available at /endpoints but currently not linked in the nav.

screen shot 2019-02-19 at 4 58 20 pm

@rmars rmars added the area/web label Feb 13, 2019
@rmars rmars self-assigned this Feb 13, 2019
Copy link
Member

@siggy siggy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

awesome! a couple tioli comments but good to go! 🚢 👍


export default withREST(
withContext(Endpoints),
({api}) => [api.fetchMetrics("/api/endpoints")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not a huge deal but this is adding a window=1m param on the URL, which is not needed/used by /api/endpoints.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good catch! I think api.fetch is better here

},
{
title: "Resource Version",
dataIndex: "pod.resourceVersion"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tioli perhaps sorting by resource version could be useful in determining pod age / service discovery staleness?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ohhh that's interesting. I'll add it!

handler struct {
render renderTemplate
apiClient pb.ApiClient
apiClient public.APIClient
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@grampelberg
Copy link
Contributor

Definitely not a blocker for this PR, but would it be possible to have links for pods/resources/services? Pods and services should link to the detail views and the resource could maybe pull the actual YAML?

@rmars
Copy link
Author

rmars commented Feb 13, 2019

@grampelberg oh yeah, that's a good idea, we can easily link to the detail views!

Copy link
Member

@siggy siggy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks great! one nit then 🚢

title: "Resource Version",
dataIndex: "pod.resourceVersion"
dataIndex: "pod.resourceVersion",
sorter: (a, b) => (a.pod.resourceVersion).localeCompare(b.resourceVersion)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

are these numbers stored as strings? will this sort numerically?

screen shot 2019-02-13 at 4 48 42 pm

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah they are, but maybe I should set numeric: true on the localeCompare so that they are sorted as numbers

Copy link
Contributor

@dadjeibaah dadjeibaah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks awesome! Thanks for adding this. What are your thoughts on where this link would reside? Would it be another option in the sidebar? Would it be a link in the Service Mesh page? To me, it feels like this is essentially debug information for the control plane, so it would naturally be somewhere in the Service Mesh page. WDYT?

let pods = [];
_each(svc.portEndpoints, info => {
info.podAddresses.forEach(podAddress => {
podAddress.service = svcName;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIOLI: I think this section here could produce a more "flattened" object. This would forego the need to have nested object traversal in the endpointColumns const.

diff --git a/web/app/js/components/Endpoints.jsx b/web/app/js/components/Endpoints.jsx
index 539f8b09..4f16168d 100644
--- a/web/app/js/components/Endpoints.jsx
+++ b/web/app/js/components/Endpoints.jsx
@@ -21,12 +21,12 @@ const endpointColumns = [
   },
   {
     title: "IP",
-    dataIndex: "pod.podIP"
+    dataIndex: "ip"
   },
   {
     title: "Port",
-    dataIndex: "addr.port",
-    sorter: (a, b) => numericSort(a.addr.port, b.addr.port)
+    dataIndex: "port",
+    sorter: (a, b) => numericSort(a.port, b.port)
   },
   {
     title: "Pod",
@@ -36,8 +36,8 @@ const endpointColumns = [
   },
   {
     title: "Resource Version",
-    dataIndex: "pod.resourceVersion",
-    sorter: (a, b) => numericSort(a.pod.resourceVersion, b.pod.resourceVersion)
+    dataIndex: "resourceVersion",
+    sorter: (a, b) => numericSort(a.resourceVersion, b.resourceVersion)
   },
   {
     title: "Service",
@@ -80,12 +80,18 @@ class Endpoints extends React.Component {
       let pods = [];
       _each(svc.portEndpoints, info => {
         info.podAddresses.forEach(podAddress => {
-          podAddress.service = svcName;
           let [podNamespace, podName] = podAddress.pod.name.split("/");
-          podAddress.name = podName;
-          podAddress.namespace = podNamespace;
-          podAddress.pod.resourceVersion = parseInt(podAddress.pod.resourceVersion, 10);
-          pods.push(podAddress);
+          let resourceVersion = parseInt(podAddress.pod.resourceVersion, 10);
+          let podIP = podAddress.pod.podIP;
+          let port = podAddress.addr.port;
+          pods.push({
+            service: svcName,
+            name: podName,
+            namespace: podNamespace,
+            resourceVersion: resourceVersion,
+            ip: podIP,
+            port: port
+          });
         });
       });
       return mem.concat(pods);
@@ -101,7 +107,7 @@ class Endpoints extends React.Component {
           tableColumns={endpointColumns}
           tableClassName="metric-table"
           defaultOrderBy="namespace"
-          rowKey={r => r.service + r.pod.name}
+          rowKey={r => r.service + r.name}
           padding="dense" />
 
       </React.Fragment>

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great point! updated

@rmars
Copy link
Author

rmars commented Feb 19, 2019

@dadjeibaah Yeah! I think this table could fit in the service mesh page! I think it could also be part of a /debug page, if we have more things to put in that page! I feel like the service mesh page is more "Overviewy" and this is more debug info, but we could also just try this on that page and see how it feels!

@grampelberg
Copy link
Contributor

My preference is for a /debug page. The mesh page needs a big revamp for it to be valuable again.

Copy link
Contributor

@dadjeibaah dadjeibaah left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is awesome! Thanks for making these changes! 📦

Copy link
Contributor

@klingerf klingerf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⭐️ New page looks really great!

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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You have two spaces here between "found" and "until". Might as well move "requests" up a line while you're at it.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reindented this section!

{
title: "IP",
dataIndex: "ip"
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TIOLI, "IP" is the only column that's not sortable. Would it make sense to add a sorter for it? I think it's also totally fine for it to not be sortable, but in that case I'd recommend removing the sorter from the "Port" column, since it feels pretty similar to this column.

{this.banner()}
<Typography variant="h6">Endpoints</Typography>
<Typography>
This table allow you to see Linkerd&#39;s service discovery state. It provides
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Typo here: allow => allows

Copy link
Contributor

@klingerf klingerf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⭐️ Great, thanks for updating!

Copy link
Contributor

@scottcarol scottcarol left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes look great - everything worked when I ran it locally!

@rmars rmars merged commit 3e9c7d2 into master Feb 21, 2019
@rmars rmars deleted the rmars/endpoints branch February 21, 2019 19:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants