Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(platform): deployment scenario tree view #492

Merged
merged 67 commits into from
Aug 24, 2021

Conversation

Alexjsenn
Copy link
Contributor

@Alexjsenn Alexjsenn commented Jun 3, 2021

Continuing from #463

Depends on #573
Fixes #421
Related to #495

@andrewazores
Copy link
Member

Rebased.

@andrewazores andrewazores force-pushed the tree-struct-api-handler branch 3 times, most recently from b0085f6 to cbc8433 Compare July 1, 2021 13:58
@andrewazores
Copy link
Member

Got this kinda, more or less working. Here's how it looks right now (`$ http --verify=false https://cryostat-sample-myproject.apps-crc.testing/api/v2/targetEnvironment Authorization:"Bearer $(oc whoami -t)" | jq) with only Cryostat deployed:

{
  "meta": {
    "type": "application/json",
    "status": "OK"
  },
  "data": {
    "result": {
      "children": [
        {
          "children": [],
          "name": "Custom Targets",
          "nodeType": "NAMESPACE",
          "labels": {}
        },
        {
          "children": [
            {
              "children": [
                {
                  "children": [
                    {
                      "children": [
                        {
                          "target": {
                            "connectUrl": "service:jmx:rmi:///jndi/rmi://10.217.0.118:9091/jmxrmi",
                            "alias": "cryostat-sample-7f6cf9846f-sdm4v"
                          },
                          "name": "cryostat-sample-7f6cf9846f-sdm4v",
                          "nodeType": "ENDPOINT",
                          "labels": {}
                        }
                      ],
                      "name": "cryostat-sample-7f6cf9846f-sdm4v",
                      "nodeType": "POD",
                      "labels": {}
                    }
                  ],
                  "name": "cryostat-sample-7f6cf9846f",
                  "nodeType": "REPLICASET",
                  "labels": {}
                }
              ],
              "name": "cryostat-sample",
              "nodeType": "DEPLOYMENT",
              "labels": {}
            }
          ],
          "name": "myproject",
          "nodeType": "NAMESPACE",
          "labels": {}
        }
      ],
      "name": "Universe",
      "nodeType": "UNIVERSE",
      "labels": {}
    }
  }
}

It currently fails to list anything in the OpenShift namespace if other sample apps are deployed:

io.fabric8.kubernetes.client.KubernetesClientException: Failure executing: GET at: https://10.217.4.1/api/v1/namespaces/myproject/replicationcontrollers. Message: Forbidden!Configured service account doesn't have access. Service account may have been revoked. replicationcontrollers is forbidden: User "system:serviceaccount:myproject:cryostat-operator-service-account" cannot list resource "replicationcontrollers" in API group "" in the namespace "myproject".
	at io.fabric8.kubernetes.client.dsl.base.OperationSupport.requestFailure(OperationSupport.java:583)
	at io.fabric8.kubernetes.client.dsl.base.OperationSupport.assertResponseCode(OperationSupport.java:520)
	at io.fabric8.kubernetes.client.dsl.base.OperationSupport.handleResponse(OperationSupport.java:487)
	at io.fabric8.kubernetes.client.dsl.base.OperationSupport.handleResponse(OperationSupport.java:448)
	at io.fabric8.kubernetes.client.dsl.base.OperationSupport.handleResponse(OperationSupport.java:431)
	at io.fabric8.kubernetes.client.dsl.base.BaseOperation.listRequestHelper(BaseOperation.java:161)
	at io.fabric8.kubernetes.client.dsl.base.BaseOperation.list(BaseOperation.java:664)
	at io.fabric8.kubernetes.client.dsl.base.BaseOperation.list(BaseOperation.java:86)
	at io.cryostat.platform.internal.KubeApiPlatformClient.createOwnerNode(KubeApiPlatformClient.java:237)
	at io.cryostat.platform.internal.KubeApiPlatformClient.buildSubsetOwnerChain(KubeApiPlatformClient.java:207)
	at io.cryostat.platform.internal.KubeApiPlatformClient.lambda$getTargetEnvironment$1(KubeApiPlatformClient.java:176)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
	at io.cryostat.platform.internal.KubeApiPlatformClient.lambda$getTargetEnvironment$2(KubeApiPlatformClient.java:174)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:177)
	at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1655)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
	at io.cryostat.platform.internal.KubeApiPlatformClient.lambda$getTargetEnvironment$3(KubeApiPlatformClient.java:171)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
	at io.cryostat.platform.internal.KubeApiPlatformClient.getTargetEnvironment(KubeApiPlatformClient.java:167)
	at io.cryostat.platform.internal.MergingPlatformClient.lambda$getTargetEnvironment$4(MergingPlatformClient.java:124)
	at java.base/java.util.Arrays$ArrayList.forEach(Arrays.java:4390)
	at io.cryostat.platform.internal.MergingPlatformClient.getTargetEnvironment(MergingPlatformClient.java:124)
	at io.cryostat.net.web.http.api.v2.TargetEnvironmentGetHandler.handle(TargetEnvironmentGetHandler.java:94)
	at io.cryostat.net.web.http.api.v2.AbstractV2RequestHandler.handle(AbstractV2RequestHandler.java:96)
	at io.cryostat.net.web.http.api.v2.AbstractV2RequestHandler.handle(AbstractV2RequestHandler.java:65)
	at io.vertx.ext.web.impl.BlockingHandlerDecorator.lambda$handle$0(BlockingHandlerDecorator.java:48)
	at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$2(ContextImpl.java:313)
	at io.vertx.core.impl.TaskQueue.run(TaskQueue.java:76)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:829)

@andrewazores
Copy link
Member

I edited the cryostat-operator-role to give the service account the ability to list replication controllers, and now the output is like this after $ make sample_app sample_app_quarkus:

{
  "meta": {
    "type": "application/json",
    "status": "OK"
  },
  "data": {
    "result": {
      "children": [
        {
          "children": [],
          "name": "Custom Targets",
          "nodeType": "NAMESPACE",
          "labels": {}
        },
        {
          "children": [
            {
              "children": [
                {
                  "children": [
                    {
                      "children": [
                        {
                          "target": {
                            "connectUrl": "service:jmx:rmi:///jndi/rmi://10.217.0.118:9091/jmxrmi",
                            "alias": "cryostat-sample-7f6cf9846f-sdm4v"
                          },
                          "name": "cryostat-sample-7f6cf9846f-sdm4v",
                          "nodeType": "ENDPOINT",
                          "labels": {}
                        }
                      ],
                      "name": "cryostat-sample-7f6cf9846f-sdm4v",
                      "nodeType": "POD",
                      "labels": {}
                    }
                  ],
                  "name": "cryostat-sample-7f6cf9846f",
                  "nodeType": "REPLICASET",
                  "labels": {}
                }
              ],
              "name": "cryostat-sample",
              "nodeType": "DEPLOYMENT",
              "labels": {}
            },
            {
              "children": [
                {
                  "children": [
                    {
                      "children": [
                        {
                          "target": {
                            "connectUrl": "service:jmx:rmi:///jndi/rmi://10.217.0.124:9096/jmxrmi",
                            "alias": "quarkus-test-1-b6qlj"
                          },
                          "name": "quarkus-test-1-b6qlj",
                          "nodeType": "ENDPOINT",
                          "labels": {}
                        }
                      ],
                      "name": "quarkus-test-1-b6qlj",
                      "nodeType": "POD",
                      "labels": {}
                    }
                  ],
                  "name": "quarkus-test-1",
                  "nodeType": "REPLICATIONCONTROLLER",
                  "labels": {}
                }
              ],
              "name": "quarkus-test",
              "nodeType": "DEPLOYMENTCONFIG",
              "labels": {}
            },
            {
              "children": [
                {
                  "children": [
                    {
                      "children": [
                        {
                          "target": {
                            "connectUrl": "service:jmx:rmi:///jndi/rmi://10.217.0.123:9091/jmxrmi",
                            "alias": "vertx-fib-demo-1-5sfj6"
                          },
                          "name": "vertx-fib-demo-1-5sfj6",
                          "nodeType": "ENDPOINT",
                          "labels": {}
                        }
                      ],
                      "name": "vertx-fib-demo-1-5sfj6",
                      "nodeType": "POD",
                      "labels": {}
                    }
                  ],
                  "name": "vertx-fib-demo-1",
                  "nodeType": "REPLICATIONCONTROLLER",
                  "labels": {}
                }
              ],
              "name": "vertx-fib-demo",
              "nodeType": "DEPLOYMENTCONFIG",
              "labels": {}
            }
          ],
          "name": "myproject",
          "nodeType": "NAMESPACE",
          "labels": {}
        }
      ],
      "name": "Universe",
      "nodeType": "UNIVERSE",
      "labels": {}
    }
  }
}

@andrewazores
Copy link
Member

{
  "meta": {
    "type": "application/json",
    "status": "OK"
  },
  "data": {
    "result": {
      "children": [
        {
          "children": [],
          "name": "Custom Targets",
          "kind": "Realm",
          "labels": {}
        },
        {
          "children": [
            {
              "children": [
                {
                  "children": [
                    {
                      "children": [
                        {
                          "children": [
                            {
                              "target": {
                                "connectUrl": "service:jmx:rmi:///jndi/rmi://10.217.0.65:9091/jmxrmi",
                                "alias": "cryostat-sample-584fdd4d-nk9kc"
                              },
                              "name": "service:jmx:rmi:///jndi/rmi://10.217.0.65:9091/jmxrmi",
                              "kind": "Endpoint",
                              "labels": {}
                            }
                          ],
                          "name": "cryostat-sample-584fdd4d-nk9kc",
                          "kind": "Pod",
                          "labels": {}
                        }
                      ],
                      "name": "cryostat-sample-584fdd4d",
                      "kind": "ReplicaSet",
                      "labels": {}
                    }
                  ],
                  "name": "cryostat-sample",
                  "kind": "Deployment",
                  "labels": {}
                },
                {
                  "children": [
                    {
                      "children": [
                        {
                          "children": [
                            {
                              "target": {
                                "connectUrl": "service:jmx:rmi:///jndi/rmi://10.217.0.49:9096/jmxrmi",
                                "alias": "quarkus-test-1-b6qlj"
                              },
                              "name": "service:jmx:rmi:///jndi/rmi://10.217.0.49:9096/jmxrmi",
                              "kind": "Endpoint",
                              "labels": {}
                            }
                          ],
                          "name": "quarkus-test-1-b6qlj",
                          "kind": "Pod",
                          "labels": {}
                        }
                      ],
                      "name": "quarkus-test-1",
                      "kind": "ReplicationController",
                      "labels": {}
                    }
                  ],
                  "name": "quarkus-test",
                  "kind": "DeploymentConfig",
                  "labels": {}
                },
                {
                  "children": [
                    {
                      "children": [
                        {
                          "children": [
                            {
                              "target": {
                                "connectUrl": "service:jmx:rmi:///jndi/rmi://10.217.0.36:9091/jmxrmi",
                                "alias": "vertx-fib-demo-1-5sfj6"
                              },
                              "name": "service:jmx:rmi:///jndi/rmi://10.217.0.36:9091/jmxrmi",
                              "kind": "Endpoint",
                              "labels": {}
                            }
                          ],
                          "name": "vertx-fib-demo-1-5sfj6",
                          "kind": "Pod",
                          "labels": {}
                        }
                      ],
                      "name": "vertx-fib-demo-1",
                      "kind": "ReplicationController",
                      "labels": {}
                    }
                  ],
                  "name": "vertx-fib-demo",
                  "kind": "DeploymentConfig",
                  "labels": {}
                }
              ],
              "name": "myproject",
              "kind": "Namespace",
              "labels": {}
            }
          ],
          "name": "KubernetesApi",
          "kind": "Realm",
          "labels": {}
        }
      ],
      "name": "Universe",
      "kind": "",
      "labels": {}
    }
  }
}

Getting into a shape I'm pretty happy with.

@andrewazores andrewazores requested a review from ebaron July 2, 2021 14:46
@andrewazores
Copy link
Member

@ebaron this is nearing readiness for proper review, but I'd like to get your feedback first on the general shape of the API response etc. before I start solidifying the implementation and adding unit tests.

This can also be rebased on top of #523, in which case the target field of the leaf nodes will automatically gain all those additional details.

@andrewazores
Copy link
Member

The latest version is in quay.io/andrewazores/cryostat:tree-10, if you'd like to try it out yourself.

@ebaron
Copy link
Member

ebaron commented Jul 2, 2021

Is there value in having Endpoints represented in these responses? They're more of an implementation detail than anything.

@andrewazores
Copy link
Member

Yea, I was wondering about that. I considered just merging them into the Pod they target, but that seemed to only make sense if there would only ever be one Endpoint for a given Pod, which I don't think is necessarily the case - a Pod could have two compatible containers within it on different ports, so two different Endpoints. I guess this could be resolved by changing the leaf node from Endpoint to Pod and also giving the leaf node type a list of ServiceRefs, instead of a single ServiceRef?

@ebaron
Copy link
Member

ebaron commented Jul 2, 2021

I think ideally the leaf node should be "Container", but we might not have the information for which container(s) are Cryostat-compatible. There's the container.ports in the pod spec, but that's like the EXPOSE command in that it's informational [1]. Maybe just listing port numbers for the leaves?

[1] https://v1-20.docs.kubernetes.io/docs/reference/generated/kubernetes-api/v1.20/#container-v1-core

@andrewazores
Copy link
Member

andrewazores commented Jul 2, 2021

I'm not seeing an obvious way to query for Containers using the KubernetesClient, either. For now I think querying Endpoints but perhaps displaying it some other way in the tree is the best we can do. I could make it so that the Endpoint enum value is replaced by Container easily enough so that the output makes it look like the leaves are Containers, even though we actually query for Endpoints to determine this.

Maybe just listing port numbers for the leaves?

What would this mean - not including whole ServiceRefs, and having the leaf simply be a Pod with a list of port numbers?

FWIW, if/when this is rebased on top of #523, each of those ServiceRefs within a leaf node will have the port number (determined by the Endpoint) included in its annotations.

@ebaron
Copy link
Member

ebaron commented Jul 2, 2021

No I think the ServiceRef is good to have. I think I may have misinterpreted the Endpoint type. It doesn't really refer to the Kubernetes Endpoints object used for discovery, does it? I was thinking the user would be presented with a hierarchy like Deployment (foo) -> ReplicaSet (foo-abc) -> Pod (foo-abc-xyz) -> Endpoints (foo, or some unrelated name), which would be weird.

@andrewazores
Copy link
Member

It doesn't really refer to the Kubernetes Endpoints object used for discovery, does it?

Not directly, no. The Endpoints are queried and filtered for ones with compatible ports (9091 or jfr-jmx). Each of those ports is paired up with the EndpointAddress to form a <host, port> tuple, which is then converted into a ServiceRef and packaged into the leaf node with the "Endpoint" type.

@ebaron
Copy link
Member

ebaron commented Jul 2, 2021

That sounds reasonable to me.

@andrewazores
Copy link
Member

That's actually the same thing (same method call internally) that the existing GET /api/v1/targets does for Kubernetes. Just that here, rather than directly returning the list of those ServiceRefs, they're put in the Endpoint nodes, and then the owner references are chased up to form the tree structure - so the tree is built bottom-up starting from identical logic to how we normally do target discovery.

@andrewazores andrewazores changed the title Tree struct api handler feat(platform): deployment scenario tree view Jul 6, 2021
@andrewazores andrewazores added the feat New feature or request label Jul 6, 2021
@andrewazores andrewazores force-pushed the tree-struct-api-handler branch 2 times, most recently from 214bcb9 to 3ae7967 Compare July 7, 2021 14:55
@andrewazores
Copy link
Member

$ http --verify=false https://cryostat-sample-myproject.apps-crc.testing/api/v2/targetEnvironment Authorization:"Bearer $(oc whoami -t)" | jq

{
  "meta": {
    "type": "application/json",
    "status": "OK"
  },
  "data": {
    "result": {
      "children": [
        {
          "children": [],
          "name": "Custom Targets",
          "kind": "Realm",
          "labels": {}
        },
        {
          "children": [
            {
              "children": [
                {
                  "children": [
                    {
                      "children": [
                        {
                          "children": [
                            {
                              "target": {
                                "connectUrl": "service:jmx:rmi:///jndi/rmi://10.217.0.67:9091/jmxrmi",
                                "alias": "cryostat-sample-694bc6f9b4-mwrh2",
                                "labels": {
                                  "app": "cryostat-sample",
                                  "pod-template-hash": "694bc6f9b4",
                                  "kind": "cryostat"
                                },
                                "annotations": {
                                  "platform": {
                                    "k8s.v1.cni.cncf.io/networks-status": "[{\n    \"name\": \"\",\n    \"interface\": \"eth0\",\n    \"ips\": [\n        \"10.217.0.67\"\n    ],\n    \"default\": true,\n    \"dns\": {}\n}]",
                                    "openshift.io/scc": "restricted",
                                    "k8s.v1.cni.cncf.io/network-status": "[{\n    \"name\": \"\",\n    \"interface\": \"eth0\",\n    \"ips\": [\n        \"10.217.0.67\"\n    ],\n    \"default\": true,\n    \"dns\": {}\n}]"
                                  },
                                  "cryostat": {
                                    "HOST": "10.217.0.67",
                                    "PORT": "9091",
                                    "NAMESPACE": "myproject",
                                    "POD_NAME": "cryostat-sample-694bc6f9b4-mwrh2"
                                  }
                                }
                              },
                              "name": "service:jmx:rmi:///jndi/rmi://10.217.0.67:9091/jmxrmi",
                              "kind": "Endpoint",
                              "labels": {}
                            }
                          ],
                          "name": "cryostat-sample-694bc6f9b4-mwrh2",
                          "kind": "Pod",
                          "labels": {
                            "app": "cryostat-sample",
                            "kind": "cryostat",
                            "pod-template-hash": "694bc6f9b4"
                          }
                        }
                      ],
                      "name": "cryostat-sample-694bc6f9b4",
                      "kind": "ReplicaSet",
                      "labels": {
                        "app": "cryostat-sample",
                        "kind": "cryostat",
                        "pod-template-hash": "694bc6f9b4"
                      }
                    }
                  ],
                  "name": "cryostat-sample",
                  "kind": "Deployment",
                  "labels": {
                    "app": "cryostat-sample",
                    "app.kubernetes.io/name": "cryostat",
                    "kind": "cryostat"
                  }
                },
                {
                  "children": [
                    {
                      "children": [
                        {
                          "children": [
                            {
                              "target": {
                                "connectUrl": "service:jmx:rmi:///jndi/rmi://10.217.0.20:9096/jmxrmi",
                                "alias": "quarkus-test-1-b6qlj",
                                "labels": {
                                  "app": "quarkus-test",
                                  "deploymentconfig": "quarkus-test",
                                  "deployment": "quarkus-test-1"
                                },
                                "annotations": {
                                  "platform": {
                                    "k8s.v1.cni.cncf.io/networks-status": "[{\n    \"name\": \"\",\n    \"interface\": \"eth0\",\n    \"ips\": [\n        \"10.217.0.20\"\n    ],\n    \"default\": true,\n    \"dns\": {}\n}]",
                                    "openshift.io/deployment-config.latest-version": "1",
                                    "openshift.io/generated-by": "OpenShiftNewApp",
                                    "openshift.io/deployment-config.name": "quarkus-test",
                                    "openshift.io/deployment.name": "quarkus-test-1",
                                    "openshift.io/scc": "restricted",
                                    "k8s.v1.cni.cncf.io/network-status": "[{\n    \"name\": \"\",\n    \"interface\": \"eth0\",\n    \"ips\": [\n        \"10.217.0.20\"\n    ],\n    \"default\": true,\n    \"dns\": {}\n}]"
                                  },
                                  "cryostat": {
                                    "HOST": "10.217.0.20",
                                    "PORT": "9096",
                                    "NAMESPACE": "myproject",
                                    "POD_NAME": "quarkus-test-1-b6qlj"
                                  }
                                }
                              },
                              "name": "service:jmx:rmi:///jndi/rmi://10.217.0.20:9096/jmxrmi",
                              "kind": "Endpoint",
                              "labels": {}
                            }
                          ],
                          "name": "quarkus-test-1-b6qlj",
                          "kind": "Pod",
                          "labels": {
                            "app": "quarkus-test",
                            "deployment": "quarkus-test-1",
                            "deploymentconfig": "quarkus-test"
                          }
                        }
                      ],
                      "name": "quarkus-test-1",
                      "kind": "ReplicationController",
                      "labels": {
                        "app": "quarkus-test",
                        "openshift.io/deployment-config.name": "quarkus-test"
                      }
                    }
                  ],
                  "name": "quarkus-test",
                  "kind": "DeploymentConfig",
                  "labels": {}
                },
                {
                  "children": [
                    {
                      "children": [
                        {
                          "children": [
                            {
                              "target": {
                                "connectUrl": "service:jmx:rmi:///jndi/rmi://10.217.0.15:9091/jmxrmi",
                                "alias": "vertx-fib-demo-1-5sfj6",
                                "labels": {
                                  "app": "vertx-fib-demo",
                                  "deploymentconfig": "vertx-fib-demo",
                                  "deployment": "vertx-fib-demo-1"
                                },
                                "annotations": {
                                  "platform": {
                                    "k8s.v1.cni.cncf.io/networks-status": "[{\n    \"name\": \"\",\n    \"interface\": \"eth0\",\n    \"ips\": [\n        \"10.217.0.15\"\n    ],\n    \"default\": true,\n    \"dns\": {}\n}]",
                                    "openshift.io/deployment-config.latest-version": "1",
                                    "openshift.io/generated-by": "OpenShiftNewApp",
                                    "openshift.io/deployment-config.name": "vertx-fib-demo",
                                    "openshift.io/deployment.name": "vertx-fib-demo-1",
                                    "openshift.io/scc": "restricted",
                                    "k8s.v1.cni.cncf.io/network-status": "[{\n    \"name\": \"\",\n    \"interface\": \"eth0\",\n    \"ips\": [\n        \"10.217.0.15\"\n    ],\n    \"default\": true,\n    \"dns\": {}\n}]"
                                  },
                                  "cryostat": {
                                    "HOST": "10.217.0.15",
                                    "PORT": "9091",
                                    "NAMESPACE": "myproject",
                                    "POD_NAME": "vertx-fib-demo-1-5sfj6"
                                  }
                                }
                              },
                              "name": "service:jmx:rmi:///jndi/rmi://10.217.0.15:9091/jmxrmi",
                              "kind": "Endpoint",
                              "labels": {}
                            }
                          ],
                          "name": "vertx-fib-demo-1-5sfj6",
                          "kind": "Pod",
                          "labels": {
                            "app": "vertx-fib-demo",
                            "deployment": "vertx-fib-demo-1",
                            "deploymentconfig": "vertx-fib-demo"
                          }
                        }
                      ],
                      "name": "vertx-fib-demo-1",
                      "kind": "ReplicationController",
                      "labels": {
                        "app": "vertx-fib-demo",
                        "openshift.io/deployment-config.name": "vertx-fib-demo"
                      }
                    }
                  ],
                  "name": "vertx-fib-demo",
                  "kind": "DeploymentConfig",
                  "labels": {}
                }
              ],
              "name": "myproject",
              "kind": "Namespace",
              "labels": {}
            }
          ],
          "name": "KubernetesApi",
          "kind": "Realm",
          "labels": {}
        }
      ],
      "name": "Universe",
      "kind": "",
      "labels": {}
    }
  }
}

and

http --verify=false https://cryostat-sample-myproject.apps-crc.testing/api/v1/targets Authorization:"Bearer $(oc whoami -t)" | jq

[
  {
    "connectUrl": "service:jmx:rmi:///jndi/rmi://10.217.0.67:9091/jmxrmi",
    "alias": "cryostat-sample-694bc6f9b4-mwrh2",
    "labels": {
      "app": "cryostat-sample",
      "pod-template-hash": "694bc6f9b4",
      "kind": "cryostat"
    },
    "annotations": {
      "platform": {
        "k8s.v1.cni.cncf.io/networks-status": "[{\n    \"name\": \"\",\n    \"interface\": \"eth0\",\n    \"ips\": [\n        \"10.217.0.67\"\n    ],\n    \"default\": true,\n    \"dns\": {}\n}]",
        "openshift.io/scc": "restricted",
        "k8s.v1.cni.cncf.io/network-status": "[{\n    \"name\": \"\",\n    \"interface\": \"eth0\",\n    \"ips\": [\n        \"10.217.0.67\"\n    ],\n    \"default\": true,\n    \"dns\": {}\n}]"
      },
      "cryostat": {
        "HOST": "10.217.0.67",
        "PORT": "9091",
        "NAMESPACE": "myproject",
        "POD_NAME": "cryostat-sample-694bc6f9b4-mwrh2"
      }
    }
  },
  {
    "connectUrl": "service:jmx:rmi:///jndi/rmi://10.217.0.20:9096/jmxrmi",
    "alias": "quarkus-test-1-b6qlj",
    "labels": {
      "app": "quarkus-test",
      "deploymentconfig": "quarkus-test",
      "deployment": "quarkus-test-1"
    },
    "annotations": {
      "platform": {
        "k8s.v1.cni.cncf.io/networks-status": "[{\n    \"name\": \"\",\n    \"interface\": \"eth0\",\n    \"ips\": [\n        \"10.217.0.20\"\n    ],\n    \"default\": true,\n    \"dns\": {}\n}]",
        "openshift.io/deployment-config.latest-version": "1",
        "openshift.io/generated-by": "OpenShiftNewApp",
        "openshift.io/deployment-config.name": "quarkus-test",
        "openshift.io/deployment.name": "quarkus-test-1",
        "openshift.io/scc": "restricted",
        "k8s.v1.cni.cncf.io/network-status": "[{\n    \"name\": \"\",\n    \"interface\": \"eth0\",\n    \"ips\": [\n        \"10.217.0.20\"\n    ],\n    \"default\": true,\n    \"dns\": {}\n}]"
      },
      "cryostat": {
        "HOST": "10.217.0.20",
        "PORT": "9096",
        "NAMESPACE": "myproject",
        "POD_NAME": "quarkus-test-1-b6qlj"
      }
    }
  },
  {
    "connectUrl": "service:jmx:rmi:///jndi/rmi://10.217.0.15:9091/jmxrmi",
    "alias": "vertx-fib-demo-1-5sfj6",
    "labels": {
      "app": "vertx-fib-demo",
      "deploymentconfig": "vertx-fib-demo",
      "deployment": "vertx-fib-demo-1"
    },
    "annotations": {
      "platform": {
        "k8s.v1.cni.cncf.io/networks-status": "[{\n    \"name\": \"\",\n    \"interface\": \"eth0\",\n    \"ips\": [\n        \"10.217.0.15\"\n    ],\n    \"default\": true,\n    \"dns\": {}\n}]",
        "openshift.io/deployment-config.latest-version": "1",
        "openshift.io/generated-by": "OpenShiftNewApp",
        "openshift.io/deployment-config.name": "vertx-fib-demo",
        "openshift.io/deployment.name": "vertx-fib-demo-1",
        "openshift.io/scc": "restricted",
        "k8s.v1.cni.cncf.io/network-status": "[{\n    \"name\": \"\",\n    \"interface\": \"eth0\",\n    \"ips\": [\n        \"10.217.0.15\"\n    ],\n    \"default\": true,\n    \"dns\": {}\n}]"
      },
      "cryostat": {
        "HOST": "10.217.0.15",
        "PORT": "9091",
        "NAMESPACE": "myproject",
        "POD_NAME": "vertx-fib-demo-1-5sfj6"
      }
    }
  }
]

@andrewazores
Copy link
Member

The implementation is currently quite ugly/messy, but there's the output anyway. What do you think @ebaron?

@andrewazores
Copy link
Member

I tested it out in CRC with the quarkus and jmx-listener sample apps, and only the Cryostat target is listed in the discovery response. Looking at the Cryostat log I see this exception:

Aug 23, 2021 8:51:53 PM io.cryostat.core.log.Logger warn
WARNING: Exception thrown
java.lang.IndexOutOfBoundsException: Index 0 out of bounds for length 0
	at java.base/jdk.internal.util.Preconditions.outOfBounds(Preconditions.java:64)
	at java.base/jdk.internal.util.Preconditions.outOfBoundsCheckIndex(Preconditions.java:70)
	at java.base/jdk.internal.util.Preconditions.checkIndex(Preconditions.java:248)
	at java.base/java.util.Objects.checkIndex(Objects.java:372)
	at java.base/java.util.ArrayList.get(ArrayList.java:459)
	at io.cryostat.platform.internal.KubeApiPlatformClient.getOrCreateOwnerNode(KubeApiPlatformClient.java:247)
	at io.cryostat.platform.internal.KubeApiPlatformClient.buildOwnerChain(KubeApiPlatformClient.java:214)
	at io.cryostat.platform.internal.KubeApiPlatformClient.lambda$getDiscoveryTree$1(KubeApiPlatformClient.java:178)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
	at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1655)
	at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:658)
	at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:274)
	at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1655)
	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
	at java.base/java.util.stream.ForEachOps$ForEachTask.compute(ForEachOps.java:290)
	at java.base/java.util.concurrent.CountedCompleter.exec(CountedCompleter.java:746)
	at java.base/java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:290)
	at java.base/java.util.concurrent.ForkJoinPool$WorkQueue.helpCC(ForkJoinPool.java:1115)
	at java.base/java.util.concurrent.ForkJoinPool.externalHelpComplete(ForkJoinPool.java:1957)
	at java.base/java.util.concurrent.ForkJoinTask.tryExternalHelp(ForkJoinTask.java:378)
	at java.base/java.util.concurrent.ForkJoinTask.externalAwaitDone(ForkJoinTask.java:323)
	at java.base/java.util.concurrent.ForkJoinTask.doInvoke(ForkJoinTask.java:412)
	at java.base/java.util.concurrent.ForkJoinTask.invoke(ForkJoinTask.java:736)
	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateParallel(ForEachOps.java:159)
	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateParallel(ForEachOps.java:173)
	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:233)
	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:497)
	at io.cryostat.platform.internal.KubeApiPlatformClient.getDiscoveryTree(KubeApiPlatformClient.java:178)
	at io.cryostat.platform.internal.MergingPlatformClient.lambda$getDiscoveryTree$4(MergingPlatformClient.java:124)
	at java.base/java.util.Arrays$ArrayList.forEach(Arrays.java:4390)
	at io.cryostat.platform.internal.MergingPlatformClient.getDiscoveryTree(MergingPlatformClient.java:124)
	at io.cryostat.net.web.http.api.beta.DiscoveryGetHandler.handle(DiscoveryGetHandler.java:105)
	at io.cryostat.net.web.http.api.v2.AbstractV2RequestHandler.handle(AbstractV2RequestHandler.java:115)
	at io.cryostat.net.web.http.api.v2.AbstractV2RequestHandler.handle(AbstractV2RequestHandler.java:68)
	at io.vertx.ext.web.impl.BlockingHandlerDecorator.lambda$handle$0(BlockingHandlerDecorator.java:48)
	at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$2(ContextImpl.java:313)
	at io.vertx.core.impl.TaskQueue.run(TaskQueue.java:76)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:829)

Looks like it's having trouble with objects that have no OwnerReferences. I think maybe what's happening is Cryostat is showing because its deployment is owned by the Cryostat CR, the Quarkus and jmx-listener deployments aren't owned by anything.

Nice, I just added a simple guard against the 0 owners case and it looks like it works for the other targets now:

$ https --verify=false https://cryostat-sample-default.apps-crc.testing/api/beta/discovery Authorization:"Bearer $(oc whoami -t)"
HTTP/1.1 200 OK
cache-control: private
content-encoding: gzip
content-length: 922
content-type: application/json
set-cookie: 78ac16596bb38bd948c8b1020b4f00d8=dbdfe6819b3c07e1fa9caae2c60a2e0b; path=/; HttpOnly; Secure; SameSite=None
{
    "data": {
        "result": {
            "children": [
                {
                    "children": [],
                    "kind": "Realm",
                    "labels": {},
                    "name": "Custom Targets"
                },
                {
                    "children": [
                        {
                            "children": [
                                {
                                    "children": [
                                        {
                                            "children": [
                                                {
                                                    "children": [
                                                        {
                                                            "kind": "Endpoint",
                                                            "labels": {},
                                                            "name": "service:jmx:rmi:///jndi/rmi://10.217.0.65:9091/jmxrmi",
                                                            "target": {
                                                                "alias": "cryostat-sample-5f84dd5fbf-m9285",
                                                                "annotations": {
                                                                    "cryostat": {
                                                                        "HOST": "10.217.0.65",
                                                                        "NAMESPACE": "default",
                                                                        "POD_NAME": "cryostat-sample-5f84dd5fbf-m9285",
                                                                        "PORT": "9091"
                                                                    },
                                                                    "platform": {
                                                                        "k8s.v1.cni.cncf.io/network-status": "[{\n    \"name\": \"openshift-sdn\",\n    \"interface\": \"eth0\",\n    \"ips\": [\n        \"10.217.0.65\"\n    ],\n    \"default\": true,\n    \"dns\": {}\n}]",
                                                                        "k8s.v1.cni.cncf.io/networks-status": "[{\n    \"name\": \"openshift-sdn\",\n    \"interface\": \"eth0\",\n    \"ips\": [\n        \"10.217.0.65\"\n    ],\n    \"default\": true,\n    \"dns\": {}\n}]"
                                                                    }
                                                                },
                                                                "connectUrl": "service:jmx:rmi:///jndi/rmi://10.217.0.65:9091/jmxrmi",
                                                                "labels": {
                                                                    "app": "cryostat-sample",
                                                                    "kind": "cryostat",
                                                                    "pod-template-hash": "5f84dd5fbf"
                                                                }
                                                            }
                                                        }
                                                    ],
                                                    "kind": "Pod",
                                                    "labels": {
                                                        "app": "cryostat-sample",
                                                        "kind": "cryostat",
                                                        "pod-template-hash": "5f84dd5fbf"
                                                    },
                                                    "name": "cryostat-sample-5f84dd5fbf-m9285"
                                                }
                                            ],
                                            "kind": "ReplicaSet",
                                            "labels": {
                                                "app": "cryostat-sample",
                                                "kind": "cryostat",
                                                "pod-template-hash": "5f84dd5fbf"
                                            },
                                            "name": "cryostat-sample-5f84dd5fbf"
                                        }
                                    ],
                                    "kind": "Deployment",
                                    "labels": {
                                        "app": "cryostat-sample",
                                        "app.kubernetes.io/name": "cryostat",
                                        "kind": "cryostat"
                                    },
                                    "name": "cryostat-sample"
                                },
                                {
                                    "children": [
                                        {
                                            "children": [
                                                {
                                                    "children": [
                                                        {
                                                            "kind": "Endpoint",
                                                            "labels": {},
                                                            "name": "service:jmx:rmi:///jndi/rmi://10.217.0.23:9093/jmxrmi",
                                                            "target": {
                                                                "alias": "jmx-listener-1-6klgb",
                                                                "annotations": {
                                                                    "cryostat": {
                                                                        "HOST": "10.217.0.23",
                                                                        "NAMESPACE": "default",
                                                                        "POD_NAME": "jmx-listener-1-6klgb",
                                                                        "PORT": "9093"
                                                                    },
                                                                    "platform": {
                                                                        "k8s.v1.cni.cncf.io/network-status": "[{\n    \"name\": \"openshift-sdn\",\n    \"interface\": \"eth0\",\n    \"ips\": [\n        \"10.217.0.23\"\n    ],\n    \"default\": true,\n    \"dns\": {}\n}]",
                                                                        "k8s.v1.cni.cncf.io/networks-status": "[{\n    \"name\": \"openshift-sdn\",\n    \"interface\": \"eth0\",\n    \"ips\": [\n        \"10.217.0.23\"\n    ],\n    \"default\": true,\n    \"dns\": {}\n}]",
                                                                        "openshift.io/deployment-config.latest-version": "1",
                                                                        "openshift.io/deployment-config.name": "jmx-listener",
                                                                        "openshift.io/deployment.name": "jmx-listener-1",
                                                                        "openshift.io/generated-by": "OpenShiftNewApp"
                                                                    }
                                                                },
                                                                "connectUrl": "service:jmx:rmi:///jndi/rmi://10.217.0.23:9093/jmxrmi",
                                                                "labels": {
                                                                    "app": "jmx-listener",
                                                                    "deployment": "jmx-listener-1",
                                                                    "deploymentconfig": "jmx-listener"
                                                                }
                                                            }
                                                        }
                                                    ],
                                                    "kind": "Pod",
                                                    "labels": {
                                                        "app": "jmx-listener",
                                                        "deployment": "jmx-listener-1",
                                                        "deploymentconfig": "jmx-listener"
                                                    },
                                                    "name": "jmx-listener-1-6klgb"
                                                }
                                            ],
                                            "kind": "ReplicationController",
                                            "labels": {
                                                "app": "jmx-listener",
                                                "openshift.io/deployment-config.name": "jmx-listener"
                                            },
                                            "name": "jmx-listener-1"
                                        }
                                    ],
                                    "kind": "DeploymentConfig",
                                    "labels": {},
                                    "name": "jmx-listener"
                                },
                                {
                                    "children": [
                                        {
                                            "children": [
                                                {
                                                    "children": [
                                                        {
                                                            "kind": "Endpoint",
                                                            "labels": {},
                                                            "name": "service:jmx:rmi:///jndi/rmi://10.217.0.42:9096/jmxrmi",
                                                            "target": {
                                                                "alias": "quarkus-test-1-kqx42",
                                                                "annotations": {
                                                                    "cryostat": {
                                                                        "HOST": "10.217.0.42",
                                                                        "NAMESPACE": "default",
                                                                        "POD_NAME": "quarkus-test-1-kqx42",
                                                                        "PORT": "9096"
                                                                    },
                                                                    "platform": {
                                                                        "k8s.v1.cni.cncf.io/network-status": "[{\n    \"name\": \"openshift-sdn\",\n    \"interface\": \"eth0\",\n    \"ips\": [\n        \"10.217.0.42\"\n    ],\n    \"default\": true,\n    \"dns\": {}\n}]",
                                                                        "k8s.v1.cni.cncf.io/networks-status": "[{\n    \"name\": \"openshift-sdn\",\n    \"interface\": \"eth0\",\n    \"ips\": [\n        \"10.217.0.42\"\n    ],\n    \"default\": true,\n    \"dns\": {}\n}]",
                                                                        "openshift.io/deployment-config.latest-version": "1",
                                                                        "openshift.io/deployment-config.name": "quarkus-test",
                                                                        "openshift.io/deployment.name": "quarkus-test-1",
                                                                        "openshift.io/generated-by": "OpenShiftNewApp"
                                                                    }
                                                                },
                                                                "connectUrl": "service:jmx:rmi:///jndi/rmi://10.217.0.42:9096/jmxrmi",
                                                                "labels": {
                                                                    "app": "quarkus-test",
                                                                    "deployment": "quarkus-test-1",
                                                                    "deploymentconfig": "quarkus-test"
                                                                }
                                                            }
                                                        }
                                                    ],
                                                    "kind": "Pod",
                                                    "labels": {
                                                        "app": "quarkus-test",
                                                        "deployment": "quarkus-test-1",
                                                        "deploymentconfig": "quarkus-test"
                                                    },
                                                    "name": "quarkus-test-1-kqx42"
                                                }
                                            ],
                                            "kind": "ReplicationController",
                                            "labels": {
                                                "app": "quarkus-test",
                                                "openshift.io/deployment-config.name": "quarkus-test"
                                            },
                                            "name": "quarkus-test-1"
                                        }
                                    ],
                                    "kind": "DeploymentConfig",
                                    "labels": {},
                                    "name": "quarkus-test"
                                },
                                {
                                    "children": [
                                        {
                                            "children": [
                                                {
                                                    "children": [
                                                        {
                                                            "kind": "Endpoint",
                                                            "labels": {},
                                                            "name": "service:jmx:rmi:///jndi/rmi://10.217.0.31:9091/jmxrmi",
                                                            "target": {
                                                                "alias": "vertx-fib-demo-1-hbbq6",
                                                                "annotations": {
                                                                    "cryostat": {
                                                                        "HOST": "10.217.0.31",
                                                                        "NAMESPACE": "default",
                                                                        "POD_NAME": "vertx-fib-demo-1-hbbq6",
                                                                        "PORT": "9091"
                                                                    },
                                                                    "platform": {
                                                                        "k8s.v1.cni.cncf.io/network-status": "[{\n    \"name\": \"openshift-sdn\",\n    \"interface\": \"eth0\",\n    \"ips\": [\n        \"10.217.0.31\"\n    ],\n    \"default\": true,\n    \"dns\": {}\n}]",
                                                                        "k8s.v1.cni.cncf.io/networks-status": "[{\n    \"name\": \"openshift-sdn\",\n    \"interface\": \"eth0\",\n    \"ips\": [\n        \"10.217.0.31\"\n    ],\n    \"default\": true,\n    \"dns\": {}\n}]",
                                                                        "openshift.io/deployment-config.latest-version": "1",
                                                                        "openshift.io/deployment-config.name": "vertx-fib-demo",
                                                                        "openshift.io/deployment.name": "vertx-fib-demo-1",
                                                                        "openshift.io/generated-by": "OpenShiftNewApp"
                                                                    }
                                                                },
                                                                "connectUrl": "service:jmx:rmi:///jndi/rmi://10.217.0.31:9091/jmxrmi",
                                                                "labels": {
                                                                    "app": "vertx-fib-demo",
                                                                    "deployment": "vertx-fib-demo-1",
                                                                    "deploymentconfig": "vertx-fib-demo"
                                                                }
                                                            }
                                                        }
                                                    ],
                                                    "kind": "Pod",
                                                    "labels": {
                                                        "app": "vertx-fib-demo",
                                                        "deployment": "vertx-fib-demo-1",
                                                        "deploymentconfig": "vertx-fib-demo"
                                                    },
                                                    "name": "vertx-fib-demo-1-hbbq6"
                                                }
                                            ],
                                            "kind": "ReplicationController",
                                            "labels": {
                                                "app": "vertx-fib-demo",
                                                "openshift.io/deployment-config.name": "vertx-fib-demo"
                                            },
                                            "name": "vertx-fib-demo-1"
                                        }
                                    ],
                                    "kind": "DeploymentConfig",
                                    "labels": {},
                                    "name": "vertx-fib-demo"
                                }
                            ],
                            "kind": "Namespace",
                            "labels": {},
                            "name": "default"
                        }
                    ],
                    "kind": "Realm",
                    "labels": {},
                    "name": "KubernetesApi"
                }
            ],
            "kind": "Universe",
            "labels": {},
            "name": "Universe"
        }
    },
    "meta": {
        "status": "OK",
        "type": "application/json"
    }
}

Copy link
Member

@ebaron ebaron left a comment

Choose a reason for hiding this comment

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

Looks good now!

API v2 automation moved this from In progress to Ready Aug 24, 2021
Batch Operations, Meta-Targets automation moved this from In progress to Ready Aug 24, 2021
@andrewazores andrewazores merged commit b21e46b into main Aug 24, 2021
API v2 automation moved this from Ready to Done Aug 24, 2021
Batch Operations, Meta-Targets automation moved this from Ready to Done Aug 24, 2021
@andrewazores andrewazores deleted the tree-struct-api-handler branch August 24, 2021 16:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feat New feature or request
Projects
No open projects
Development

Successfully merging this pull request may close these issues.

Tree view for Targets
3 participants