From 98dd8ba3f05c6a92a50fbbcdba94ead865f8994a Mon Sep 17 00:00:00 2001 From: Amir Blum Date: Tue, 2 Jul 2024 14:15:03 +0300 Subject: [PATCH] feat(frontend): add sources number of instances (#1318) --- frontend/endpoints/sources.go | 25 +++++++++++-------- .../manage.source.header.tsx | 4 +-- .../sources.table.row.tsx | 4 +-- .../main/sources/edit.source/index.tsx | 5 +--- frontend/webapp/types/sources.ts | 1 + .../utils/constants/programming.languages.ts | 25 +++++++++++++------ 6 files changed, 36 insertions(+), 28 deletions(-) diff --git a/frontend/endpoints/sources.go b/frontend/endpoints/sources.go index 6033bcedb..84cf0a367 100644 --- a/frontend/endpoints/sources.go +++ b/frontend/endpoints/sources.go @@ -28,7 +28,8 @@ type InstrumentedApplicationDetails struct { // this object contains only part of the source fields. It is used to display the sources in the frontend type ThinSource struct { SourceID - IaDetails *InstrumentedApplicationDetails `json:"instrumented_application_details"` + NumberOfRunningInstances int `json:"number_of_running_instances"` + IaDetails *InstrumentedApplicationDetails `json:"instrumented_application_details"` } type SourceID struct { @@ -88,7 +89,8 @@ func GetSources(c *gin.Context, odigosns string) { if item.nsItem.InstrumentationEffective { id := SourceID{Namespace: item.namespace, Kind: string(item.nsItem.Kind), Name: item.nsItem.Name} effectiveInstrumentedSources[id] = ThinSource{ - SourceID: id, + NumberOfRunningInstances: item.nsItem.Instances, + SourceID: id, } } } @@ -119,7 +121,7 @@ func GetSource(c *gin.Context) { name := c.Param("name") k8sObjectName := workload.GetRuntimeObjectName(name, kind) - owner := getK8sObject(c, ns, kind, name) + owner, numberOfRunningInstances := getWorkloadObject(c, ns, kind, name) if owner == nil { c.JSON(500, gin.H{ "message": "could not find owner of instrumented application", @@ -138,6 +140,7 @@ func GetSource(c *gin.Context) { Kind: kind, Name: name, }, + NumberOfRunningInstances: numberOfRunningInstances, } instrumentedApplication, err := kube.DefaultClient.OdigosClient.InstrumentedApplications(ns).Get(c, k8sObjectName, metav1.GetOptions{}) @@ -319,28 +322,28 @@ func addHealthyInstrumentationInstancesCondition(ctx context.Context, app *v1alp return nil } -func getK8sObject(c *gin.Context, ns string, kind string, name string) metav1.Object { +func getWorkloadObject(c *gin.Context, ns string, kind string, name string) (metav1.Object, int) { switch kind { case "Deployment": deployment, err := kube.DefaultClient.AppsV1().Deployments(ns).Get(c, name, metav1.GetOptions{}) if err != nil { - return nil + return nil, 0 } - return deployment + return deployment, int(deployment.Status.AvailableReplicas) case "StatefulSet": statefulSet, err := kube.DefaultClient.AppsV1().StatefulSets(ns).Get(c, name, metav1.GetOptions{}) if err != nil { - return nil + return nil, 0 } - return statefulSet + return statefulSet, int(statefulSet.Status.ReadyReplicas) case "DaemonSet": daemonSet, err := kube.DefaultClient.AppsV1().DaemonSets(ns).Get(c, name, metav1.GetOptions{}) if err != nil { - return nil + return nil, 0 } - return daemonSet + return daemonSet, int(daemonSet.Status.NumberReady) default: - return nil + return nil, 0 } } diff --git a/frontend/webapp/components/overview/sources/manage.source.header/manage.source.header.tsx b/frontend/webapp/components/overview/sources/manage.source.header/manage.source.header.tsx index 07428cd6d..0c4a0d5c6 100644 --- a/frontend/webapp/components/overview/sources/manage.source.header/manage.source.header.tsx +++ b/frontend/webapp/components/overview/sources/manage.source.header/manage.source.header.tsx @@ -28,9 +28,7 @@ const IMAGE_STYLE: React.CSSProperties = { }; export function ManageSourceHeader({ source }: { source: ManagedSource }) { - const mainLanguage = getMainContainerLanguage( - source?.instrumented_application_details?.languages || undefined - ); + const mainLanguage = getMainContainerLanguage(source); const imageUrl = LANGUAGES_LOGOS[mainLanguage]; return ( diff --git a/frontend/webapp/components/overview/sources/managed.sources.table/sources.table.row.tsx b/frontend/webapp/components/overview/sources/managed.sources.table/sources.table.row.tsx index a016ab95a..3f3a2da9b 100644 --- a/frontend/webapp/components/overview/sources/managed.sources.table/sources.table.row.tsx +++ b/frontend/webapp/components/overview/sources/managed.sources.table/sources.table.row.tsx @@ -105,9 +105,7 @@ export function SourcesTableRow({ onSelectedCheckboxChange: (id: string) => void; onRowClick: (source: ManagedSource) => void; }) { - const workloadProgrammingLanguage = getMainContainerLanguage( - item?.instrumented_application_details?.languages || undefined - ); + const workloadProgrammingLanguage = getMainContainerLanguage(item); const containerName = item?.instrumented_application_details?.languages?.[0].container_name || ''; diff --git a/frontend/webapp/containers/main/sources/edit.source/index.tsx b/frontend/webapp/containers/main/sources/edit.source/index.tsx index 0d4c60e7f..f5237d5fe 100644 --- a/frontend/webapp/containers/main/sources/edit.source/index.tsx +++ b/frontend/webapp/containers/main/sources/edit.source/index.tsx @@ -125,10 +125,7 @@ export function EditSourceForm() { name={currentSource?.name} image_url={ LANGUAGES_LOGOS[ - getMainContainerLanguage( - currentSource?.instrumented_application_details?.languages || - undefined - ) + getMainContainerLanguage(currentSource) ] } /> diff --git a/frontend/webapp/types/sources.ts b/frontend/webapp/types/sources.ts index 1c3629465..43eeb90dc 100644 --- a/frontend/webapp/types/sources.ts +++ b/frontend/webapp/types/sources.ts @@ -18,6 +18,7 @@ export interface ManagedSource { name: string; namespace: string; reported_name?: string; + number_of_running_instances: number; instrumented_application_details: { conditions: Array; languages: Array<{ diff --git a/frontend/webapp/utils/constants/programming.languages.ts b/frontend/webapp/utils/constants/programming.languages.ts index 506699d9d..29bdd6ef4 100644 --- a/frontend/webapp/utils/constants/programming.languages.ts +++ b/frontend/webapp/utils/constants/programming.languages.ts @@ -1,3 +1,5 @@ +import { ManagedSource } from "@/types/sources"; + const BASE_URL = 'https://d1n7d4xz7fr8b4.cloudfront.net/'; // while odigos lists language per container, we want to aggregate one single language for the workload. @@ -13,6 +15,7 @@ export enum WORKLOAD_PROGRAMMING_LANGUAGES { UNKNOWN = 'unknown', // language detection completed but could not find a supported language PROCESSING = 'processing', // language detection is not yet complotted, data is not available NO_CONTAINERS = 'no containers', // language detection completed but no containers found or they are ignored + NO_RUNNING_PODS = 'no running pods', // no running pods are available for language detection } export const LANGUAGES_LOGOS: Record = { @@ -25,6 +28,7 @@ export const LANGUAGES_LOGOS: Record = { [WORKLOAD_PROGRAMMING_LANGUAGES.UNKNOWN]: `${BASE_URL}default.svg`, // TODO: good icon [WORKLOAD_PROGRAMMING_LANGUAGES.PROCESSING]: `${BASE_URL}default.svg`, // TODO: good icon [WORKLOAD_PROGRAMMING_LANGUAGES.NO_CONTAINERS]: `${BASE_URL}default.svg`, // TODO: good icon + [WORKLOAD_PROGRAMMING_LANGUAGES.NO_RUNNING_PODS]: `${BASE_URL}default.svg`, // TODO: good icon }; export const LANGUAGES_COLORS: Record = @@ -37,17 +41,24 @@ export const LANGUAGES_COLORS: Record = [WORKLOAD_PROGRAMMING_LANGUAGES.MYSQL]: '#00758F', [WORKLOAD_PROGRAMMING_LANGUAGES.UNKNOWN]: '#8b92a6', [WORKLOAD_PROGRAMMING_LANGUAGES.PROCESSING]: '#3367d9', - [WORKLOAD_PROGRAMMING_LANGUAGES.NO_CONTAINERS]: '#000000', + [WORKLOAD_PROGRAMMING_LANGUAGES.NO_CONTAINERS]: '#111111', + [WORKLOAD_PROGRAMMING_LANGUAGES.NO_RUNNING_PODS]: '#666666', }; export const getMainContainerLanguage = ( - languages: - | Array<{ - container_name: string; - language: string; - }> - | undefined + source: ManagedSource ): WORKLOAD_PROGRAMMING_LANGUAGES => { + + const ia = source?.instrumented_application_details; + if(!ia) { + if(source?.number_of_running_instances > 0) { + return WORKLOAD_PROGRAMMING_LANGUAGES.PROCESSING; + } else { + return WORKLOAD_PROGRAMMING_LANGUAGES.NO_RUNNING_PODS; + } + } + + const { languages } = ia; if (!languages) { return WORKLOAD_PROGRAMMING_LANGUAGES.PROCESSING; }