From 1ab429427f472f18ddbf20b47bbc2307c46c851b Mon Sep 17 00:00:00 2001 From: Martin Sottnik Date: Wed, 28 Aug 2024 11:54:37 +0200 Subject: [PATCH] update topology and performance monitor apis changes --- codegen-perf-monitoring.yml | 2 +- src/__generated__/perf-monitoring.graphql.ts | 173 ++++++++++-------- .../topology-discovery.graphql.ts | 147 ++++++++++++++- .../performance-monitoring-graphql.ts | 120 ++++-------- 4 files changed, 270 insertions(+), 172 deletions(-) diff --git a/codegen-perf-monitoring.yml b/codegen-perf-monitoring.yml index a41f249d..81d6a033 100644 --- a/codegen-perf-monitoring.yml +++ b/codegen-perf-monitoring.yml @@ -1,5 +1,5 @@ schema: - - 'http://localhost:8082' + - 'http://localhost:8082/api/graphql' documents: - './src/external-api/performance-monitoring-graphql.ts' generates: diff --git a/src/__generated__/perf-monitoring.graphql.ts b/src/__generated__/perf-monitoring.graphql.ts index 37b20ae5..59cbe7bb 100644 --- a/src/__generated__/perf-monitoring.graphql.ts +++ b/src/__generated__/perf-monitoring.graphql.ts @@ -35,125 +35,138 @@ export type BucketWidth = { value: Scalars['Float']; }; -/** Represents the percentage usage value. Includes also device name. */ -export type Percentage = { - __typename?: 'Percentage'; - device: Scalars['String']; - usage: Maybe; -}; - -/** Represents a percentage value at a specific time. */ -export type PercentageInTime = { - __typename?: 'PercentageInTime'; - /** The timestamp indicating when the percentage value was recorded. */ - time: Scalars['Datetime']; - /** The percentage value recorded at the given time. */ - usage: Scalars['Float']; +/** Represents a paginated connection of utilization data for multiple devices. */ +export type BulkUtilizationConnection = { + __typename?: 'BulkUtilizationConnection'; + /** A list of metrics for multiple devices, each with associated cursor information. */ + metrics: Array; + /** Information about the current page of results. */ + pageInfo: PageInfo; }; -/** Represents a series of percentage values over time. Includes also device name. */ -export type PercentageInTimeSeries = { - __typename?: 'PercentageInTimeSeries'; +/** Represents the current sources utilization of a single device. */ +export type CurrentUtilization = { + __typename?: 'CurrentUtilization'; + /** The unique identifier for the device. */ device: Scalars['String']; - usages: Maybe>; + /** The device metrics. */ + deviceMetrics: MetricsNode; }; -export type Query = { - __typename?: 'Query'; - /** Read CPU usages in time range for single device. */ - cpuUsage: PercentageInTimeSeries; - /** Read CPU usages in time range for multiple devices. */ - cpuUsages: Maybe>; - /** Read the current CPU usage for single device. */ - currentCpuUsage: Percentage; - /** Read the current CPU usage for multiple devices. */ - currentCpuUsages: Maybe>; - /** Read the current memory usage for single device. */ - currentMemoryUsage: Percentage; - /** Read the current memory usage for multiple devices. */ - currentMemoryUsages: Maybe>; - /** Read memory usages in time range for single device. */ - memoryUsage: PercentageInTimeSeries; - /** Read memory usages in time range for multiple devices. */ - memoryUsages: Maybe>; -}; - - -export type QueryCpuUsageArgs = { - bucket_width?: InputMaybe; - device: Scalars['String']; - end_time?: InputMaybe; - start_time?: InputMaybe; +/** Represents an edge in a paginated list of device metrics. */ +export type MetricsEdge = { + __typename?: 'MetricsEdge'; + /** A cursor for pagination. */ + cursor: Scalars['String']; + /** A list of device metrics associated with a specific device. */ + deviceMetrics: Array; }; +/** Interface representing device metrics. */ +export type MetricsInterface = { + /** The CPU utilization represented as a percentage. */ + cpu: Maybe; + /** The memory utilization represented as a percentage. */ + memory: Maybe; +}; -export type QueryCpuUsagesArgs = { - bucket_width?: InputMaybe; - devices: Array; - end_time?: InputMaybe; - start_time?: InputMaybe; +/** Base node type for metrics. */ +export type MetricsNode = MetricsInterface & { + __typename?: 'MetricsNode'; + cpu: Maybe; + memory: Maybe; }; +/** Node type for metrics including a cursor. */ +export type MetricsWithCursorNode = MetricsInterface & { + __typename?: 'MetricsWithCursorNode'; + cpu: Maybe; + /** The cursor used for pagination. */ + cursor: Maybe; + memory: Maybe; +}; -export type QueryCurrentCpuUsageArgs = { +/** Node type for metrics a device. */ +export type MetricsWithDeviceNode = MetricsInterface & { + __typename?: 'MetricsWithDeviceNode'; + cpu: Maybe; + /** The device identifier. */ device: Scalars['String']; + memory: Maybe; }; - -export type QueryCurrentCpuUsagesArgs = { - devices: Array; +/** Pagination metadata that is usually coupled to a returned list of objects. */ +export type PageInfo = { + __typename?: 'PageInfo'; + /** Pointer to the last object in the list. */ + endCursor: Maybe; + /** Indicates if there is a next object in the list. */ + hasNextPage: Scalars['Boolean']; }; - -export type QueryCurrentMemoryUsageArgs = { - device: Scalars['String']; +export type Query = { + __typename?: 'Query'; + /** Read current utilization of multiple device sources. */ + bulkCurrentUtilization: Array; + /** Read utilization of multiple device sources. */ + bulkUtilization: BulkUtilizationConnection; + /** Read current utilization of single device sources. */ + currentUtilization: CurrentUtilization; + /** Read utilization of single device device sources. */ + utilization: UtilizationConnection; }; -export type QueryCurrentMemoryUsagesArgs = { +export type QueryBulkCurrentUtilizationArgs = { devices: Array; }; -export type QueryMemoryUsageArgs = { +export type QueryBulkUtilizationArgs = { + after?: InputMaybe; bucket_width?: InputMaybe; - device: Scalars['String']; + devices: Array; end_time?: InputMaybe; + first?: InputMaybe; start_time?: InputMaybe; }; -export type QueryMemoryUsagesArgs = { +export type QueryCurrentUtilizationArgs = { + device: Scalars['String']; +}; + + +export type QueryUtilizationArgs = { + after?: InputMaybe; bucket_width?: InputMaybe; - devices?: InputMaybe>; + device: Scalars['String']; end_time?: InputMaybe; + first?: InputMaybe; start_time?: InputMaybe; }; -export type CurrentMemoryUsagesQueryVariables = Exact<{ - names: Array | Scalars['String']; -}>; - - -export type CurrentMemoryUsagesQuery = { __typename?: 'Query', currentMemoryUsages: Array<{ __typename?: 'Percentage', device: string, usage: number | null }> | null }; - -export type CurrentCpuUsagesQueryVariables = Exact<{ - names: Array | Scalars['String']; -}>; - - -export type CurrentCpuUsagesQuery = { __typename?: 'Query', currentCpuUsages: Array<{ __typename?: 'Percentage', device: string, usage: number | null }> | null }; +/** Represents a paginated connection of utilization data for a single device. */ +export type UtilizationConnection = { + __typename?: 'UtilizationConnection'; + /** The unique identifier for the device. */ + device: Scalars['String']; + /** A list of device metrics with associated cursor information. */ + deviceMetrics: Array; + /** Information about the current page of results. */ + pageInfo: PageInfo; +}; -export type CurrentMemoryUsageQueryVariables = Exact<{ - name: Scalars['String']; +export type BulkDeviceMetricsQueryVariables = Exact<{ + devices: Array | Scalars['String']; }>; -export type CurrentMemoryUsageQuery = { __typename?: 'Query', currentMemoryUsage: { __typename?: 'Percentage', device: string, usage: number | null } }; +export type BulkDeviceMetricsQuery = { __typename?: 'Query', bulkCurrentUtilization: Array<{ __typename?: 'CurrentUtilization', device: string, deviceMetrics: { __typename?: 'MetricsNode', cpu: number | null, memory: number | null } }> }; -export type CurrentCpuUsageQueryVariables = Exact<{ - name: Scalars['String']; +export type DeviceMetricsQueryVariables = Exact<{ + device: Scalars['String']; }>; -export type CurrentCpuUsageQuery = { __typename?: 'Query', currentCpuUsage: { __typename?: 'Percentage', device: string, usage: number | null } }; +export type DeviceMetricsQuery = { __typename?: 'Query', currentUtilization: { __typename?: 'CurrentUtilization', device: string, deviceMetrics: { __typename?: 'MetricsNode', cpu: number | null, memory: number | null } } }; diff --git a/src/__generated__/topology-discovery.graphql.ts b/src/__generated__/topology-discovery.graphql.ts index 4f4158dc..40c13bd6 100644 --- a/src/__generated__/topology-discovery.graphql.ts +++ b/src/__generated__/topology-discovery.graphql.ts @@ -417,7 +417,7 @@ export type MutationEnableRemoteDebugSessionArgs = { export type MutationSyncArgs = { devices?: InputMaybe>>; labels?: InputMaybe>>; - provider_name: Scalars['String']; + topology_type: TopologyType; }; @@ -434,6 +434,15 @@ export type MutationUpdateNodeStatusArgs = { topology_type?: InputMaybe; }; +/** Metadata information about a neighbor device. */ +export type Neighbor = { + __typename?: 'Neighbor'; + /** Identifier of the neighbor device document (for example, MplsDevice/1). */ + device_id: Scalars['String']; + /** Human-readable name of the neighbor device (for example, CPE_01). */ + device_name: Scalars['String']; +}; + /** Representation of the routing entity in the network topology. */ export type NetDevice = Node & { __typename?: 'NetDevice'; @@ -1067,6 +1076,8 @@ export type Query = { * Also return the count of incoming and outcoming tunnels from / to that device. */ mplsLspCount: Maybe>>; + /** Find identifiers of all neighbour devices of the specified device in the specified topology. */ + neighbors: Maybe>; /** Read network devices that match specified filter. */ netDevices: NetDeviceConnection; /** @@ -1084,7 +1095,7 @@ export type Query = { /** Read list of support device types in the specified topology. */ provider: ProviderResponse; /** Read list of available topology providers (e.g. physical, etp, eth_sync, etc.). */ - providers: Array; + providers: Array; /** Read ptp devices that match specified filter. */ ptpDevices: PtpDeviceConnection; /** @@ -1114,6 +1125,13 @@ export type Query = { * Only documents that belong to the specified topology are included in the diff. */ topologyDiff: TopologyResponse; + /** + * Returns an overlay between two topologies. + * The overlay works in such a way that it takes the first topology, and tries to find devices / interfaces + * from the first topology in the second one. + * The first topology can be taken as a reference topology. The second topology is joined to the first one (similar to LEFT JOIN in databases) + */ + topologyOverlay: TopologyOverlayDeviceConnection; }; @@ -1143,6 +1161,12 @@ export type QueryMplsLspCountArgs = { }; +export type QueryNeighborsArgs = { + device_name: Scalars['String']; + topology_type: TopologyType; +}; + + export type QueryNetDevicesArgs = { cursor?: InputMaybe; filters?: InputMaybe; @@ -1170,7 +1194,7 @@ export type QueryPhyDevicesArgs = { export type QueryProviderArgs = { - name: Scalars['String']; + topology_type: TopologyType; }; @@ -1213,6 +1237,15 @@ export type QueryTopologyDiffArgs = { old_db: Scalars['String']; }; + +export type QueryTopologyOverlayArgs = { + cursor?: InputMaybe; + filters?: InputMaybe; + first?: InputMaybe; + firstTopology: TopologyType; + secondTopology: TopologyType; +}; + /** Computed routing path from source to destination device. */ export type RoutingPath = { __typename?: 'RoutingPath'; @@ -1448,6 +1481,114 @@ export type SyncePathOutputCollections = /** Include SynceInterface nodes in the returned path. */ | 'SynceInterface'; +export type TopologyOverlayDevice = { + __typename?: 'TopologyOverlayDevice'; + /** Unique identifier of the object. */ + id: Scalars['ID']; + /** Device name. */ + name: Scalars['String']; + /** Document device ID from the second topology (can be null). */ + secondTopologyId: Maybe; + /** List of ports that are present on the device. */ + topologyOverlayInterfaces: TopologyOverlayInterfaceConnection; +}; + + +export type TopologyOverlayDeviceTopologyOverlayInterfacesArgs = { + cursor?: InputMaybe; + filters?: InputMaybe; + first?: InputMaybe; +}; + +/** Grouped list of TopologyOverlayDevice objects and pagination metadata. */ +export type TopologyOverlayDeviceConnection = { + __typename?: 'TopologyOverlayDeviceConnection'; + /** List of TopologyOverlayDeviceEdge objects. */ + edges: Maybe>>; + /** Pagination metadata. */ + pageInfo: PageInfo; +}; + +/** Grouped TopologyOverlayDeviceEdge object and associated cursor used by pagination. */ +export type TopologyOverlayDeviceEdge = { + __typename?: 'TopologyOverlayDeviceEdge'; + /** Pagination cursor for this edge. */ + cursor: Scalars['String']; + /** The associated TopologyOverlayDevice object. */ + node: Maybe; +}; + +/** Filter for TopologyOverlayDevice type based on device name. */ +export type TopologyOverlayDeviceFilter = { + /** Regex of device name. */ + name?: InputMaybe; +}; + +export type TopologyOverlayInterface = { + __typename?: 'TopologyOverlayInterface'; + /** Document interface ID from the first topology */ + id: Scalars['ID']; + /** Interface name. */ + name: Scalars['String']; + /** Document device ID from the second topology (can be null). */ + secondTopologyId: Maybe; + /** Topology overlay device that owns this interface. */ + topologyOverlayDevice: Maybe; + /** Topology overlay neighbor interface */ + topologyOverlayLinks: Maybe; +}; + +/** Grouped list of TopologyOverlayInterface objects and pagination metadata. */ +export type TopologyOverlayInterfaceConnection = { + __typename?: 'TopologyOverlayInterfaceConnection'; + /** List of TopologyOverlayInterface objects. */ + edges: Maybe>>; + /** Pagination metadata. */ + pageInfo: PageInfo; +}; + +/** Grouped TopologyOverlayInterface object and associated cursor used by pagination. */ +export type TopologyOverlayInterfaceEdge = { + __typename?: 'TopologyOverlayInterfaceEdge'; + /** Pagination cursor for this edge. */ + cursor: Scalars['String']; + /** The associated TopologyOverlayInterface object. */ + node: Maybe; +}; + +/** Filter for TopologyOverlayInterface type based on the name of the device. */ +export type TopologyOverlayInterfaceFilter = { + /** Regex of interface name. */ + name?: InputMaybe; +}; + +/** Grouped list of TopologyOverlayLinks objects and pagination metadata. */ +export type TopologyOverlayLinkConnection = { + __typename?: 'TopologyOverlayLinkConnection'; + /** List of TopologyOverlayInterface objects. */ + edges: Maybe>>; + /** Pagination metadata. */ + pageInfo: PageInfo; +}; + +export type TopologyOverlayLinkEdge = { + __typename?: 'TopologyOverlayLinkEdge'; + /** Pagination cursor for this edge. */ + cursor: Scalars['String']; + /** Identifier of the link that connects this interface to the interface on the remote device */ + link: Maybe; + /** The associated TopologyOverlayInterface object. */ + node: Maybe; +}; + +export type TopologyOverlayLinkIds = { + __typename?: 'TopologyOverlayLinkIds'; + /** Identifier of the link that connects this interface to the interface on the remote device on the first topology. */ + firstTopologyLinkId: Scalars['ID']; + /** Identifier of the link that connects this interface to the interface on the remote device on the second topology. */ + secondTopologyLinkId: Maybe; +}; + /** Response from the topologyDiff query that contains diff between two databases. */ export type TopologyResponse = { __typename?: 'TopologyResponse'; diff --git a/src/external-api/performance-monitoring-graphql.ts b/src/external-api/performance-monitoring-graphql.ts index f48cbecb..b5da5735 100644 --- a/src/external-api/performance-monitoring-graphql.ts +++ b/src/external-api/performance-monitoring-graphql.ts @@ -1,14 +1,10 @@ import { gql, GraphQLClient } from 'graphql-request'; import config from '../config'; import { - CurrentCpuUsageQuery, - CurrentCpuUsageQueryVariables, - CurrentCpuUsagesQuery, - CurrentCpuUsagesQueryVariables, - CurrentMemoryUsageQuery, - CurrentMemoryUsageQueryVariables, - CurrentMemoryUsagesQuery, - CurrentMemoryUsagesQueryVariables, + BulkDeviceMetricsQuery, + BulkDeviceMetricsQueryVariables, + DeviceMetricsQuery, + DeviceMetricsQueryVariables, } from '../__generated__/perf-monitoring.graphql'; export type DeviceLoadUsage = { @@ -20,38 +16,26 @@ export type NodesConnectionStatus = { status: 'complete' | 'fail'; }; -const DEVICE_MEMORY_USAGES = gql` - query CurrentMemoryUsages($names: [String!]!) { - currentMemoryUsages(devices: $names) { +const BULK_DEVICE_METRICS = gql` + query BulkDeviceMetrics($devices: [String!]!) { + bulkCurrentUtilization(devices: $devices) { device - usage - } - } -`; - -const DEVICE_CPU_USAGES = gql` - query CurrentCpuUsages($names: [String!]!) { - currentCpuUsages(devices: $names) { - device - usage - } - } -`; - -const DEVICE_MEMORY_USAGE = gql` - query CurrentMemoryUsage($name: String!) { - currentMemoryUsage(device: $name) { - device - usage + deviceMetrics { + cpu + memory + } } } `; -const DEVICE_CPU_USAGE = gql` - query CurrentCpuUsage($name: String!) { - currentCpuUsage(device: $name) { +const DEVICE_METRICS = gql` + query DeviceMetrics($device: String!) { + currentUtilization(device: $device) { device - usage + deviceMetrics { + cpu + memory + } } } `; @@ -67,75 +51,35 @@ function getPerformanceMonitoringAPI() { } const client = new GraphQLClient(config.performanceMonitoringGraphqlURL); - async function getDeviceCpuUsage(deviceName: string): Promise { - const result = await client.request(DEVICE_CPU_USAGE, { - name: deviceName, + async function getDeviceMetrics(deviceName: string): Promise { + const result = await client.request(DEVICE_METRICS, { + device: deviceName, }); return result; } - async function getDeviceMemoryUsage(deviceName: string): Promise { - const result = await client.request( - DEVICE_MEMORY_USAGE, - { name: deviceName }, - ); - - return result; - } - - async function getDeviceCpuUsages(deviceNames: string[]): Promise { - const result = await client.request(DEVICE_CPU_USAGES, { - names: deviceNames, + async function getBulkDeviceMetrics(deviceNames: string[]): Promise { + const result = await client.request(BULK_DEVICE_METRICS, { + devices: deviceNames, }); return result; } - async function getDeviceMemoryUsages(deviceNames: string[]): Promise { - const result = await client.request( - DEVICE_MEMORY_USAGES, - { names: deviceNames }, - ); - - return result; - } - async function getDeviceLoadUsage(deviceName: string): Promise { - const [cpuUsage, memoryUsage] = await Promise.all([ - getDeviceCpuUsage(deviceName), - getDeviceMemoryUsage(deviceName), - ]); + const { currentUtilization } = await getDeviceMetrics(deviceName); - return { cpuUsage: cpuUsage.currentCpuUsage.usage, memoryUsage: memoryUsage.currentMemoryUsage.usage }; + return { cpuUsage: currentUtilization.deviceMetrics.cpu, memoryUsage: currentUtilization.deviceMetrics.memory }; } async function getDeviceLoadUsages(deviceNames: string[]): Promise<(DeviceLoadUsage & { deviceName: string })[]> { - const [cpuUsages, memoryUsages] = await Promise.all([ - getDeviceCpuUsages(deviceNames), - getDeviceMemoryUsages(deviceNames), - ]); - - const map = new Map(); - - cpuUsages.currentCpuUsages?.forEach((cpuUsage) => { - map.set(cpuUsage.device, { deviceName: cpuUsage.device, cpuUsage: cpuUsage.usage, memoryUsage: null }); - }); - - memoryUsages.currentMemoryUsages?.forEach((memoryUsage) => { - const deviceLoadUsage = map.get(memoryUsage.device); - if (deviceLoadUsage) { - deviceLoadUsage.memoryUsage = memoryUsage.usage; - } else { - map.set(memoryUsage.device, { - deviceName: memoryUsage.device, - cpuUsage: null, - memoryUsage: memoryUsage.usage, - }); - } - }); - - return Array.from(map.values()); + const { bulkCurrentUtilization } = await getBulkDeviceMetrics(deviceNames); + return bulkCurrentUtilization.map((u) => ({ + deviceName: u.device, + cpuUsage: u.deviceMetrics.cpu, + memoryUsage: u.deviceMetrics.memory, + })); } return { getDeviceLoadUsage, getDeviceLoadUsages };