From b1ef4cd65e3f9f3bf3a812774327ee0ab654e742 Mon Sep 17 00:00:00 2001 From: John Swanke Date: Fri, 8 Apr 2022 10:17:09 -0400 Subject: [PATCH 01/11] fix statuses Signed-off-by: John Swanke --- .../helpers/diagram-helpers-utils.js | 4 +- .../helpers/diagram-helpers.js | 5 +- .../model/computeRelated.js | 96 ++---- .../model/computeStatuses.js | 273 +++++------------- .../ApplicationTopology/model/topology.js | 4 +- .../model/topologyAppSet.js | 5 +- .../ApplicationTopology/model/topologyArgo.js | 3 +- .../model/topologySubscription.js | 71 +++-- .../ApplicationTopology/model/utils.js | 28 +- .../ApplicationTopology/model/utils.test.js | 2 +- 10 files changed, 169 insertions(+), 322 deletions(-) diff --git a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/helpers/diagram-helpers-utils.js b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/helpers/diagram-helpers-utils.js index 1ea02b06d4a..921cc223b19 100644 --- a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/helpers/diagram-helpers-utils.js +++ b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/helpers/diagram-helpers-utils.js @@ -192,8 +192,7 @@ export const namespaceMatchTargetServer = (relatedKind, resourceMapForObject) => // try to match app destination clusters with hub clusters using search data export const updateAppClustersMatchingSearch = (node, searchClusters) => { - const nodeId = _.get(node, 'id', '') - if (nodeId !== 'member--clusters--') { + if (node.type !== 'cluster') { //acm cluster node _.set(node, 'specs.clusters', searchClusters) return node @@ -243,7 +242,6 @@ export const updateAppClustersMatchingSearch = (node, searchClusters) => { } }) _.set(node, 'specs.appClusters', _.sortBy(appClusters)) - _.set(node, 'specs.clusters', searchClusters) return node } diff --git a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/helpers/diagram-helpers.js b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/helpers/diagram-helpers.js index 87a93d4646e..997ff9ff323 100644 --- a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/helpers/diagram-helpers.js +++ b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/helpers/diagram-helpers.js @@ -400,6 +400,7 @@ export const getNameWithoutPodHash = (relatedKind) => { //openshift.io/deployment-config.name deployableName = values[1].trim() nameNoHash = deployableName + podTemplateHashLabelFound = true } } }) @@ -580,7 +581,7 @@ export const addIngressNodeInfo = (node, details, t) => { //for service export const addNodeServiceLocation = (node, clusterName, targetNS, details, t) => { - if (R.pathOr('', ['specs', 'raw', 'kind'])(node) === 'Service') { + if (node.type === 'service') { return addNodeInfoPerCluster(node, clusterName, targetNS, details, addNodeServiceLocationForCluster, t) //process only services } return details @@ -588,7 +589,7 @@ export const addNodeServiceLocation = (node, clusterName, targetNS, details, t) //generic function to write location info export const addNodeInfoPerCluster = (node, clusterName, targetNS, details, getDetailsFunction, t) => { - const resourceName = _.get(node, 'namespace', '') + const resourceName = _.get(node, 'name', '') const resourceMap = _.get(node, `specs.${node.type}Model`, {}) const locationDetails = [] diff --git a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/computeRelated.js b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/computeRelated.js index 0b387c704f3..523552beaa4 100644 --- a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/computeRelated.js +++ b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/computeRelated.js @@ -44,28 +44,16 @@ export const addDiagramDetails = (resourceStatuses, resourceMap, isClusterGroupe const hasMultipleSubs = _.get(appNode, 'specs.allSubscriptions', []).length > 1 topology.nodes.forEach((node) => { - const nodeId = _.get(node, 'id', '') - if (nodeId.startsWith('member--clusters--')) { + if (node.type === 'cluster') { // only do this for Argo clusters //cluster node, set search found clusters objects here updateAppClustersMatchingSearch(node, clustersObjects) } - const nodeClusters = nodeId.startsWith('member--subscription') - ? clusterNamesList - : getClusterName(nodeId).split(',') - _.set( - node, - 'specs.clustersNames', - hasMultipleSubs - ? nodeClusters - : nodeId.includes('clusters----') || nodeId === 'member--clusters--' - ? clusterNamesList - : _.sortBy(_.uniq(_.union(nodeClusters, clusterNamesList))) - ) + const nodeClusters = node.type === 'subscription' ? clusterNamesList : _.get(node, 'specs.clustersNames') _.set( node, 'specs.searchClusters', - hasMultipleSubs && !nodeId.startsWith('application--') + hasMultipleSubs && node.type === 'application' ? _.filter(clustersObjects, (cls) => _.includes(nodeClusters, _.get(cls, 'name', ''))) : clustersObjects // get all search clusters when one cluster node or this is the main app node ) @@ -96,7 +84,7 @@ export const addDiagramDetails = (resourceStatuses, resourceMap, isClusterGroupe const { kind, cluster } = relatedKind //look for pod template hash and remove it from the name if there - const { nameNoHash, deployableName, podHash } = getNameWithoutPodHash(relatedKind) + const { nameNoHash, deployableName } = getNameWithoutPodHash(relatedKind) //for routes generated by Ingress, remove route name hash const nameNoHashIngressPod = getRouteNameWithoutIngressHash(relatedKind, nameNoHash) @@ -107,71 +95,45 @@ export const addDiagramDetails = (resourceStatuses, resourceMap, isClusterGroupe hasHelmReleases ) - let name = computeResourceName(relatedKind, deployableName, nameWithoutChartRelease, isClusterGrouped) + let resourceName = computeResourceName( + relatedKind, + deployableName, + nameWithoutChartRelease, + isClusterGrouped + ) if ( kind === 'subscription' && cluster === 'local-cluster' && _.get(relatedKind, 'localPlacement', '') === 'true' && - _.endsWith(name, '-local') + _.endsWith(resourceName, '-local') ) { //match local hub subscription after removing -local suffix - name = _.trimEnd(name, '-local') + resourceName = _.trimEnd(resourceName, '-local') } - const existingResourceMapKey = getExistingResourceMapKey(resourceMap, name, relatedKind) - if (checkAndObjects(podHash, existingResourceMapKey)) { - //update resource map key with podHash if the resource has a pod hash ( deployment, replicaset, deploymentconig, etc ) - //this is going to be used to link pods with this parent resource - resourceMap[`pod-${podHash}-${cluster}`] = resourceMap[existingResourceMapKey] - } else if (checkAndObjects(deployableName, existingResourceMapKey)) { - resourceMap[`pod-deploymentconfig-${deployableName}`] = resourceMap[existingResourceMapKey] - } - - let ownerUID - let resourceMapForObject = - resourceMap[name] || (existingResourceMapKey && resourceMap[existingResourceMapKey]) - if (!resourceMapForObject && kind === 'pod') { - if (podHash) { - //just found a pod object, try to map it to the parent resource using the podHash - resourceMapForObject = resourceMap[`pod-${podHash}-${cluster}`] - } else if (deployableName) { - resourceMapForObject = resourceMap[`pod-deploymentconfig-${deployableName}`] + const resourceMapForObject = Object.values(resourceMap).find(({ name, namespace, type, specs = {} }) => { + if (specs.resourceCount) { + if (type === relatedKind.kind && (specs.clustersNames || []).includes(relatedKind.cluster)) { + return ( + (specs.resources || []).findIndex((spec) => { + return spec.name === nameNoHash && spec.namespace === relatedKind.namespace + }) !== -1 + ) } else { - ownerUID = relatedKind._ownerUID + return false } - } - - if (ownerUID) { - findParentForOwnerID( - resourceMap, - ownerUID, - kind, - relatedKind, - nameWithoutChartRelease, - addResourceToModel - ) - } else if (resourceMapForObject) { - addResourceToModel(resourceMapForObject, kind, relatedKind, nameWithoutChartRelease) } else { - //get resource by looking at the cluster grouping - Object.keys(resourceMap).forEach((key) => { - resourceMapForObject = resourceMap[key] - if ( - _.startsWith(key, name) && - (_.includes( - _.get( - resourceMapForObject, - 'clusters.specs.clustersNames', - ['local-cluster'] // if no cluster found for this resource, this could be a local deployment - ), - _.get(relatedKind, 'cluster') - ) || - namespaceMatchTargetServer(relatedKind, resourceMapForObject)) - ) { - addResourceToModel(resourceMapForObject, kind, relatedKind, nameWithoutChartRelease) + return ( + (kind === 'subscription' ? name === resourceName : name === nameNoHash) && + namespace === relatedKind.namespace && + type === relatedKind.kind && + (specs.clustersNames || []).includes(relatedKind.cluster) + ) } }) + if (resourceMapForObject) { + addResourceToModel(resourceMapForObject, kind, relatedKind, nameWithoutChartRelease) } }) }) diff --git a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/computeStatuses.js b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/computeStatuses.js index fde6b876f5e..2810f3ca582 100644 --- a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/computeStatuses.js +++ b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/computeStatuses.js @@ -18,11 +18,9 @@ import { getClusterName, getActiveFilterCodes, filterSubscriptionObject, - fixMissingStateOptions, showMissingClusterDetails, getTargetNsForNode, nodesWithNoNS, - allClustersAreOnline, } from '../helpers/diagram-helpers-utils' import { isSearchAvailable } from '../helpers/search-helper' import { showAnsibleJobDetails, getPulseStatusForAnsibleNode } from '../helpers/ansible-task' @@ -66,14 +64,6 @@ export const computeNodeStatus = (node, isSearchingStatusComplete, t) => { return 'spinner' } - // pod status - if (nodeMustHavePods(node)) { - pulse = getPulseForNodeWithPodStatus(node, t) - _.set(node, specPulse, pulse) - _.set(node, specShapeType, shapeType) - return pulse - } - const isDeployable = isDeployableResource(node) switch (node.type) { case 'application': @@ -137,7 +127,7 @@ export const getPulseStatusForSubscription = (node) => { const resourceMap = _.get(node, `specs.${node.type}Model`) if (!resourceMap) { - pulse = 'orange' //resource not available + pulse = node.type === 'subscription' ? 'red' : 'orange' //resource not available return pulse } let isPlaced = false @@ -148,7 +138,7 @@ export const getPulseStatusForSubscription = (node) => { if (R.includes('Failed', subscriptionItem.status)) { pulse = 'red' } - if (subscriptionItem.status === 'Subscribed') { + if (subscriptionItem.status === 'Subscribed' || subscriptionItem.status === 'Propagated') { isPlaced = true // at least one cluster placed } if ( @@ -285,8 +275,12 @@ export const getPulseStatusForCluster = (node) => { clusterName = 'local-cluster' } if (!clustersNames || clustersNames.includes(clusterName)) { - const status = cluster.status || calculateArgoClusterStatus(cluster) || '' - if (status.toLowerCase() === 'ok' || _.get(cluster, 'ManagedClusterConditionAvailable', '') === 'True') { + const status = (cluster.status || calculateArgoClusterStatus(cluster) || '').toLowerCase() + if ( + status === 'ok' || + status === 'ready' || + _.get(cluster, 'ManagedClusterConditionAvailable', '') === 'True' + ) { okCount++ } else if (status === 'pendingimport') { pendingCount++ @@ -295,7 +289,7 @@ export const getPulseStatusForCluster = (node) => { } } }) - if (offlineCount > 0) { + if (offlineCount > 0 || (pendingCount === clusters.length && pendingCount === 0)) { return 'red' } if (pendingCount === clusters.length) { @@ -327,7 +321,7 @@ export const calculateArgoClusterStatus = (clusterData) => { } export const getOnlineClusters = (node) => { - const clusterNames = R.split(',', getClusterName(_.get(node, 'id', ''), node)) + const clusterNames = _.get(node, 'specs.clustersNames', []) const prClusters = _.get(node, 'clusters.specs.clusters', []) const searchClusters = _.get(node, 'specs.searchClusters', []) const clusterObjs = prClusters.length > searchClusters.length ? prClusters : searchClusters @@ -355,108 +349,78 @@ export const getOnlineClusters = (node) => { } ///////////////////////////////////////////////////////////////// -///////////////// POD /////////////////////////////////////////// +///////////////// GENERIC /////////////////////////////////////// ///////////////////////////////////////////////////////////////// +const getPulseStatusForGenericNode = (node, t) => { + const { deployedStr, resNotDeployedStates } = getStateNames(t) -export const getPulseForNodeWithPodStatus = (node, t) => { - const { resSuccessStates } = getStateNames(t) - - let pulse = 'green' - const resourceMap = _.get(node, `specs.${node.type}Model`) - let desired = 1 - if (resourceMap && Object.keys(resourceMap).length > 0) { - desired = resourceMap[Object.keys(resourceMap)[0]][0].desired - ? resourceMap[Object.keys(resourceMap)[0]][0].desired - : 'NA' + //ansible job status + const nodeType = _.get(node, 'type', '') + if (nodeType === 'ansiblejob' && _.get(node, 'specs.raw.hookType')) { + // process here only ansible hooks + return getPulseStatusForAnsibleNode(node) } + let pulse = 'green' const namespace = _.get(node, 'namespace', '') + const resourceMap = _.get(node, `specs.${node.type}Model`) const clusterNames = R.split(',', getClusterName(node.id, node, true)) const onlineClusters = getOnlineClusters(node) - const onlineClustersIncludeClusterNames = onlineClusters.some((cls) => clusterNames.includes(cls)) - if (!resourceMap || onlineClusters.length === 0 || !onlineClustersIncludeClusterNames) { - pulse = 'orange' //resource not available + + // if no resourceMap from search query, show '?' + if (!resourceMap || onlineClusters.length === 0) { + pulse = 'orange' + if (nodeType === 'placement') { + pulse = 'green' + } return pulse } - //must have pods, set the pods status here - const podStatusMap = {} - const podList = _.get(node, 'specs.podModel', []) - - // list of target namespaces per cluster - const targetNamespaces = _.get(node, 'clusters.specs.targetNamespaces', {}) //go through all clusters to make sure all pods are counted, even if they are not deployed there let highestPulse = 3 clusterNames.forEach((clusterName) => { clusterName = R.trim(clusterName) + //get target cluster namespaces + const resourceNSString = _.includes(nodesWithNoNS, nodeType) ? 'name' : 'namespace' const resourcesForCluster = _.filter( _.flatten(Object.values(resourceMap)), (obj) => _.get(obj, 'cluster', '') === clusterName ) - const resourceItems = fixMissingStateOptions(resourcesForCluster || []) - - //get cluster target namespaces - const targetNSList = targetNamespaces[clusterName] - ? _.union(targetNamespaces[clusterName], _.uniq(_.map(resourceItems, 'namespace'))) - : resourceItems.length > 0 - ? _.uniq(_.map(resourceItems, 'namespace')) - : [namespace] + const targetNSList = getTargetNsForNode(node, resourcesForCluster, clusterName, namespace) targetNSList.forEach((targetNS) => { - const resourceItemsForNS = _.filter(resourceItems, (obj) => _.get(obj, 'namespace', '') === targetNS) - if (resourceItemsForNS.length === 0) { - //one namespace has no deployments + const resourceItems = _.filter(resourcesForCluster, (obj) => _.get(obj, resourceNSString, '') === targetNS) + if (resourceItems.length === 0) { pulse = 'yellow' - } - const podObjects = _.filter( - _.flatten(Object.values(podList)), - (obj) => _.get(obj, 'namespace', '') === targetNS && _.get(obj, 'cluster', '') === clusterName - ) - resourceItemsForNS.forEach((resourceItem) => { - //process item if there are no pods in the same ns - cluster as resource item - const processItem = resourceItem && podObjects.length === 0 - if (resourceItem && resourceItem.kind === 'daemonset') { - desired = resourceItem.desired - } - - let podsReady = 0 - let podsUnavailable = 0 - //find pods status and pulse from pods model, if available - podObjects.forEach((podItem) => { - podsUnavailable = podsUnavailable + getPodState(podItem, clusterName, resErrorStates) //podsUnavailable + 1 - podsReady = podsReady + getPodState(podItem, clusterName, resSuccessStates) - }) - - podStatusMap[`${clusterName}-${targetNS}-${node.type}-${resourceItem.name}`] = { - available: 0, - current: 0, - desired: desired, - ready: podsReady, - unavailable: podsUnavailable, - } - - pulse = getPulseForData(podsReady, desired, podsUnavailable) - if (processItem) { - //no pods linked to the resource, check if we have enough information on the actual resource - podStatusMap[`${clusterName}-${targetNS}-${node.type}-${resourceItem.name}`] = { - available: resourceItem.available || 0, - current: resourceItem.current || 0, - desired: resourceItem.desired || 0, - ready: resourceItem.ready || 0, + } else { + resourceItems.forEach((resourceItem) => { + // does resource have a desired resource count? + if (resourceItem.desired !== undefined) { + pulse = getPulseForData( + resourceItem.available || resourceItem.current || 0, + resourceItem.desired, + 0 + ) + resourceItem.resStatus = `${resourceItem.available || resourceItem.current || 0}/${ + resourceItem.desired + }` + } else { + const resStatus = _.get(resourceItem, 'status', deployedStr).toLowerCase() + resourceItem.resStatus = resStatus + if (_.includes(resErrorStates, resStatus)) { + pulse = 'red' + } + if (_.includes(_.union(resWarningStates, resNotDeployedStates), resStatus)) { + // resource not created on this cluster for the required target namespace + pulse = 'yellow' + } } - - pulse = getPulseForData( - resourceItem.available ? resourceItem.available : 0, - resourceItem.desired, - 0 - ) - resourceItem.resStatus = `${resourceItem.available || 0}/${resourceItem.desired}` - } - resourceItem.pulse = pulse - const index = pulseValueArr.indexOf(pulse) - if (index < highestPulse) { - highestPulse = index - } - }) + resourceItem.pulse = pulse + const index = pulseValueArr.indexOf(pulse) + if (index < highestPulse) { + highestPulse = index + } + }) + } const index = pulseValueArr.indexOf(pulse) if (index < highestPulse) { highestPulse = index @@ -467,11 +431,19 @@ export const getPulseForNodeWithPodStatus = (node, t) => { highestPulse = index } }) - _.set(node, 'podStatusMap', podStatusMap) - return pulseValueArr[highestPulse] } +const getStateNames = (t) => { + const notDeployedStr = t('Not Deployed') + const notDeployedNSStr = t('Not Created') + const deployedStr = t('Deployed') + const deployedNSStr = t('Created') + const resNotDeployedStates = [notDeployedStr.toLowerCase(), notDeployedNSStr.toLowerCase()] + const resSuccessStates = ['run', 'bound', deployedStr.toLowerCase(), deployedNSStr.toLowerCase(), 'propagated'] + return { notDeployedStr, notDeployedNSStr, deployedStr, deployedNSStr, resNotDeployedStates, resSuccessStates } +} + //count pod state export const getPodState = (podItem, clusterName, types) => { const podStatus = R.toLower(R.pathOr('unknown', ['status'])(podItem)) @@ -511,97 +483,6 @@ export const getPulseForData = (available, desired, podsUnavailable) => { return 'green' } -///////////////////////////////////////////////////////////////// -///////////////// GENERIC /////////////////////////////////////// -///////////////////////////////////////////////////////////////// -const getPulseStatusForGenericNode = (node, t) => { - const { deployedStr, resNotDeployedStates } = getStateNames(t) - - //ansible job status - const nodeType = _.get(node, 'type', '') - if (nodeType === 'ansiblejob' && _.get(node, 'specs.raw.hookType')) { - // process here only ansible hooks - return getPulseStatusForAnsibleNode(node) - } - let pulse = _.get(node, specPulse, 'green') - - if (pulse === 'red') { - return pulse //no need to check anything else, return red - } - const namespace = _.get(node, 'namespace', '') - const resourceMap = _.get(node, `specs.${node.type}Model`) - const clusterNames = R.split(',', getClusterName(node.id, node, true)) - const onlineClusters = getOnlineClusters(node) - - if (!resourceMap || onlineClusters.length === 0) { - pulse = 'orange' //resource not available - if (nodeType === 'placement') { - pulse = 'green' - } - return pulse - } - if (!allClustersAreOnline(clusterNames, onlineClusters)) { - pulse = 'yellow' - return pulse - } - //go through all clusters to make sure all pods are counted, even if they are not deployed there - let highestPulse = 3 - clusterNames.forEach((clusterName) => { - clusterName = R.trim(clusterName) - //get target cluster namespaces - const resourceNSString = _.includes(nodesWithNoNS, nodeType) ? 'name' : 'namespace' - const resourcesForCluster = _.filter( - _.flatten(Object.values(resourceMap)), - (obj) => _.get(obj, 'cluster', '') === clusterName - ) - - const targetNSList = getTargetNsForNode(node, resourcesForCluster, clusterName, namespace) - targetNSList.forEach((targetNS) => { - const resObjects = _.filter(resourcesForCluster, (obj) => _.get(obj, resourceNSString, '') === targetNS) - if (resObjects.length === 0) { - pulse = 'yellow' - } else { - resObjects.forEach((resObject) => { - const resStatus = _.get(resObject, 'status', deployedStr).toLowerCase() - resObject.resStatus = resStatus - if (_.includes(resErrorStates, resStatus)) { - pulse = 'red' - } - if (_.includes(_.union(resWarningStates, resNotDeployedStates), resStatus)) { - // resource not created on this cluster for the required target namespace - pulse = 'yellow' - } - resObject.pulse = pulse - const index = pulseValueArr.indexOf(pulse) - if (index < highestPulse) { - highestPulse = index - } - }) - } - const index = pulseValueArr.indexOf(pulse) - if (index < highestPulse) { - highestPulse = index - } - }) - const index = pulseValueArr.indexOf(pulse) - if (index < highestPulse) { - highestPulse = index - } - }) - - return pulseValueArr[highestPulse] -} - -const getStateNames = (t) => { - const notDeployedStr = t('Not Deployed') - const notDeployedNSStr = t('Not Created') - const deployedStr = t('Deployed') - const deployedNSStr = t('Created') - const resNotDeployedStates = [notDeployedStr.toLowerCase(), notDeployedNSStr.toLowerCase()] - const resSuccessStates = ['run', 'bound', deployedStr.toLowerCase(), deployedNSStr.toLowerCase(), 'propagated'] - return { notDeployedStr, notDeployedNSStr, deployedStr, deployedNSStr, resNotDeployedStates, resSuccessStates } -} - /////////////////////////////////////////////////////////////////////////////////////// //////////////////////// SET STATUS IN DETAILS TAB /////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////// @@ -1162,7 +1043,6 @@ export const setPodDeployStatus = (node, updatedNode, details, activeFilters, t) const podModel = _.get(node, 'specs.podModel', []) const podObjects = _.flatten(Object.values(podModel)) - const podStatusModel = _.get(updatedNode, 'podStatusMap', {}) const podDataPerCluster = {} //pod details list for each cluster name // list of target namespaces per cluster const targetNamespaces = _.get(node, 'clusters.specs.targetNamespaces', {}) @@ -1197,14 +1077,15 @@ export const setPodDeployStatus = (node, updatedNode, details, activeFilters, t) : resourcesForCluster.length > 0 ? _.uniq(_.map(resourcesForCluster, 'namespace')) : [resourceNamespace] + const resourceNSString = _.includes(nodesWithNoNS, 'pod') ? 'name' : 'namespace' targetNSList.forEach((targetNS) => { - const res = podStatusModel[`${clusterName}-${targetNS}-${node.type}-${resourceName}`] + const res = _.find(resourcesForCluster, (obj) => _.get(obj, resourceNSString, '') === targetNS) let pulse = 'orange' + let valueStr = notDeployedStr if (res) { - pulse = getPulseForData(res.ready, res.desired, res.unavailable) + pulse = res.status === 'Running' ? 'green' : 'yellow' + valueStr = res.resStatus } - const valueStr = res ? `${res.ready}/${res.desired}` : notDeployedStr - let statusStr switch (pulse) { case 'red': @@ -1481,7 +1362,7 @@ export const setResourceDeployStatus = (node, details, activeFilters, t) => { if (addItemToDetails) { details.push({ labelValue: targetNS, - value: deployedKey, + value: `${deployedKey} ${res && res.desired !== undefined ? res.resStatus : ''}`, status: statusStr, }) } else { diff --git a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/topology.js b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/topology.js index 3c7cdf4b27e..a898d4cdf04 100644 --- a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/topology.js +++ b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/topology.js @@ -105,9 +105,7 @@ export const processNodeData = (node, topoResourceMap, isClusterGrouped, hasHelm // if this node represents multiple resources, create an entry for each resource in the map const resources = _.get(node, 'specs.resources') if (resources) { - resources.forEach(({ name }) => { - topoResourceMap[`${type}-${name}-${clusterName}`] = node - }) + topoResourceMap[`${type}-${clusterName}`] = node } else { topoResourceMap[`${type}-${keyName}-${clusterName}`] = node } diff --git a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/topologyAppSet.js b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/topologyAppSet.js index c11d12ae453..0cbc40b644b 100644 --- a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/topologyAppSet.js +++ b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/topologyAppSet.js @@ -79,7 +79,7 @@ export function getAppSetTopology(application) { const clusterParentId = placement ? placementId : appId const source = get(application, 'app.spec.template.spec.source.path', '') - const clusterId = addClusters(clusterParentId, null, source, clusterNames, clusterNames, links, nodes) + const clusterId = addClusters(clusterParentId, null, source, clusterNames, appSetClusters, links, nodes) const resources = appSetApps.length > 0 ? get(appSetApps[0], 'status.resources', []) : [] // what if first app doesn't have resources? resources.forEach((deployable) => { @@ -115,6 +115,7 @@ export function getAppSetTopology(application) { specs: { isDesign: false, raw, + clustersNames: clusterNames, parent: { clusterId, }, @@ -130,7 +131,7 @@ export function getAppSetTopology(application) { const template = { metadata: {} } // create replica subobject, if this object defines a replicas - createReplicaChild(deployableObj, template, links, nodes) + createReplicaChild(deployableObj, clusterNames, template, links, nodes) }) return { nodes: uniqBy(nodes, 'uid'), links } diff --git a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/topologyArgo.js b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/topologyArgo.js index 4a729e85af1..14a67027a48 100644 --- a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/topologyArgo.js +++ b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/topologyArgo.js @@ -120,6 +120,7 @@ export function getArgoTopology(application, argoData) { specs: { isDesign: false, raw, + clustersNames: clusterNames, parent: { clusterId, }, @@ -135,7 +136,7 @@ export function getArgoTopology(application, argoData) { const template = { metadata: {} } // create replica subobject, if this object defines a replicas - createReplicaChild(deployableObj, template, links, nodes) + createReplicaChild(deployableObj, clusterNames, template, links, nodes) }) return { nodes: uniqBy(nodes, 'uid'), links } diff --git a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/topologySubscription.js b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/topologySubscription.js index cb52b90c616..1bd926afcb5 100644 --- a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/topologySubscription.js +++ b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/topologySubscription.js @@ -85,12 +85,20 @@ export const getSubscriptionTopology = (application, managedClusters, relatedRes source = source.split('/').pop() // add cluster nodes - clusterId = addClusters(appId, subscription, source, ruleClusterNames, managedClusterNames, links, nodes) + const filteredClusters = managedClusters.filter((cluster) => { + return ruleClusterNames.includes(cluster.name) + }) + clusterId = addClusters(appId, subscription, source, ruleClusterNames, filteredClusters, links, nodes) const isRulePlaced = ruleClusterNames.length > 0 + // get clusters it was deployed to + const clustersNames = get(subscription, 'report.results', []).map((result) => { + return result.source + }) + // add subscription node - const subscriptionId = addSubscription(clusterId, subscription, isRulePlaced, links, nodes) + const subscriptionId = addSubscription(clusterId, clustersNames, subscription, isRulePlaced, links, nodes) // add rules node if (subscription.rules) { @@ -107,7 +115,7 @@ export const getSubscriptionTopology = (application, managedClusters, relatedRes // add deployed resource nodes using subscription report if (subscription.report) { - processReport(subscription.report, subscriptionId, links, nodes, relatedResources) + processReport(subscription.report, clustersNames, subscriptionId, links, nodes, relatedResources) } }) } @@ -115,7 +123,7 @@ export const getSubscriptionTopology = (application, managedClusters, relatedRes return { nodes: uniqBy(nodes, 'uid'), links } } -const addSubscription = (appId, subscription, isPlaced, links, nodes) => { +const addSubscription = (appId, clustersNames, subscription, isPlaced, links, nodes) => { const { metadata: { namespace, name }, } = subscription @@ -132,6 +140,7 @@ const addSubscription = (appId, subscription, isPlaced, links, nodes) => { hasRules: !!rule, isPlaced, raw: subscription, + clustersNames, }, }) @@ -195,7 +204,7 @@ const addSubscriptionHooks = (parentId, subscription, links, nodes, isPreHook) = }) } -const processReport = (report, clusterId, links, nodes, relatedResources) => { +const processReport = (report, clustersNames, clusterId, links, nodes, relatedResources) => { // for each resource, add what it's related to report = cloneDeep(report) const resources = report.resources || [] @@ -206,13 +215,14 @@ const processReport = (report, clusterId, links, nodes, relatedResources) => { }) } + // get elements which services belong to const serviceOwners = filter(resources, (obj) => { const kind = get(obj, 'kind', '') return includes(['Route', 'Ingress', 'StatefulSet'], kind) }) // process route and service first - const serviceMap = processServiceOwner(clusterId, serviceOwners, links, nodes, relatedResources) + const serviceMap = processServiceOwner(clusterId, clustersNames, serviceOwners, links, nodes, relatedResources) const services = filter(resources, (obj) => { const kind = get(obj, 'kind', '') @@ -220,7 +230,7 @@ const processReport = (report, clusterId, links, nodes, relatedResources) => { }) // then service - processServices(clusterId, services, links, nodes, serviceMap) + processServices(clusterId, clustersNames, services, links, nodes, serviceMap) // then the rest const others = filter(resources, (obj) => { @@ -229,7 +239,7 @@ const processReport = (report, clusterId, links, nodes, relatedResources) => { }) processMultiples(others).forEach((resource) => { - addSubscriptionDeployedResource(clusterId, resource, links, nodes) + addSubscriptionDeployedResource(clusterId, clustersNames, resource, links, nodes) }) } @@ -250,10 +260,10 @@ const processMultiples = (resources) => { } // Route, Ingress, StatefulSet -const processServiceOwner = (clusterId, serviceOwners, links, nodes, relatedResources) => { +const processServiceOwner = (clusterId, clustersNames, serviceOwners, links, nodes, relatedResources) => { const servicesMap = {} serviceOwners.forEach((serviceOwner, inx) => { - const node = addSubscriptionDeployedResource(clusterId, serviceOwner, links, nodes) + const node = addSubscriptionDeployedResource(clusterId, clustersNames, serviceOwner, links, nodes) if (relatedResources) { // get service info and map it to the object id @@ -293,7 +303,7 @@ const processServiceOwner = (clusterId, serviceOwners, links, nodes, relatedReso return servicesMap } -const processServices = (clusterId, services, links, nodes, servicesMap) => { +const processServices = (clusterId, clustersNames, services, links, nodes, servicesMap) => { services.forEach((service, inx) => { const serviceName = service.name let parentId = servicesMap[serviceName] @@ -304,11 +314,11 @@ const processServices = (clusterId, services, links, nodes, servicesMap) => { parentId = clusterId } - addSubscriptionDeployedResource(parentId, service, links, nodes) + addSubscriptionDeployedResource(parentId, clustersNames, service, links, nodes) }) } -const addSubscriptionDeployedResource = (parentId, resource, links, nodes) => { +const addSubscriptionDeployedResource = (parentId, clustersNames, resource, links, nodes) => { const parentNode = nodes.find((n) => n.id === parentId) const parentObject = parentNode ? { @@ -331,6 +341,7 @@ const addSubscriptionDeployedResource = (parentId, resource, links, nodes) => { uid: memberId, specs: { parent: parentObject, + clustersNames, template, resources, resourceCount, @@ -345,61 +356,61 @@ const addSubscriptionDeployedResource = (parentId, resource, links, nodes) => { }) // create replica subobject, if this object defines a replicas - createReplicaChild(node, template, links, nodes) + createReplicaChild(node, clustersNames, template, links, nodes) // create controllerrevision subobject, if this object is a daemonset - createControllerRevisionChild(node, links, nodes) + createControllerRevisionChild(node, clustersNames, links, nodes) // create route subobject, if this object is an ingress - createIngressRouteChild(node, links, nodes) + createIngressRouteChild(node, clustersNames, links, nodes) // for replicaset and replicationcontroller - createPodChild(node, links, nodes) + createPodChild(node, clustersNames, links, nodes) return node } -export const createReplicaChild = (parentObject, template, links, nodes) => { +export const createReplicaChild = (parentObject, clustersNames, template, links, nodes) => { const parentType = get(parentObject, 'type', '') if (parentType === 'deploymentconfig' || parentType === 'deployment') { const type = parentType === 'deploymentconfig' ? 'replicationcontroller' : 'replicaset' if (template && template.related) { const relatedMap = keyBy(template.related, 'kind') if (relatedMap['replicaset'] || relatedMap['replicationcontroller']) { - const pNode = createChildNode(parentObject, type, links, nodes) - return createChildNode(pNode, 'pod', links, nodes) + const pNode = createChildNode(parentObject, clustersNames, type, links, nodes) + return createChildNode(pNode, clustersNames, 'pod', links, nodes) } else if (relatedMap['pod']) { - return createChildNode(parentObject, 'pod', links, nodes) + return createChildNode(parentObject, clustersNames, 'pod', links, nodes) } } else { - const pNode = createChildNode(parentObject, type, links, nodes) + const pNode = createChildNode(parentObject, clustersNames, type, links, nodes) if (typesWithPods.includes(type)) { - return createChildNode(pNode, 'pod', links, nodes) + return createChildNode(pNode, clustersNames, 'pod', links, nodes) } } } } -const createIngressRouteChild = (parentObject, links, nodes) => { +const createIngressRouteChild = (parentObject, clustersNames, links, nodes) => { const parentType = get(parentObject, 'type', '') if (parentType === 'ingress') { const type = 'route' - return createChildNode(parentObject, type, links, nodes) + return createChildNode(parentObject, clustersNames, type, links, nodes) } } -const createControllerRevisionChild = (parentObject, links, nodes) => { +const createControllerRevisionChild = (parentObject, clustersNames, links, nodes) => { const parentType = get(parentObject, 'type', '') if (parentType === 'daemonset' || parentType === 'statefulset') { // create only for daemonset or statefulset types - const pNode = createChildNode(parentObject, 'controllerrevision', links, nodes) - return createChildNode(pNode, 'pod', links, nodes) + const pNode = createChildNode(parentObject, clustersNames, 'controllerrevision', links, nodes) + return createChildNode(pNode, clustersNames, 'pod', links, nodes) } } -const createPodChild = (parentObject, links, nodes) => { +const createPodChild = (parentObject, clustersNames, links, nodes) => { const parentType = get(parentObject, 'type', '') if (parentType === 'replicaset' || parentType === 'replicationcontroller') { - return createChildNode(parentObject, 'pod', links, nodes) + return createChildNode(parentObject, clustersNames, 'pod', links, nodes) } } diff --git a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/utils.js b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/utils.js index 3d2acf20e40..13e2ca4e497 100644 --- a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/utils.js +++ b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/utils.js @@ -21,7 +21,7 @@ export const getClusterName = (nodeId) => { return localClusterName } -export const createChildNode = (parentObject, type, links, nodes) => { +export const createChildNode = (parentObject, clustersNames, type, links, nodes) => { const parentType = _.get(parentObject, 'type', '') const { name, namespace, id, specs = {} } = parentObject const parentId = id @@ -41,6 +41,7 @@ export const createChildNode = (parentObject, type, links, nodes) => { specs: { resourceCount: specs.resourceCount, resources, + clustersNames, parent: { parentId, parentName: name, @@ -60,16 +61,7 @@ export const createChildNode = (parentObject, type, links, nodes) => { } // add cluster node to RHCAM application -export const addClusters = ( - parentId, - subscription, - source, - clusterNames, - managedClusterNames, - links, - nodes, - topology -) => { +export const addClusters = (parentId, subscription, source, clusterNames, managedClusters, links, nodes, topology) => { // create element if not already created const sortedClusterNames = _.sortBy(clusterNames) let clusterId = 'member--clusters' @@ -86,10 +78,10 @@ export const addClusters = ( id: 'member--clusters', }) : undefined - const filteredClusters = managedClusterNames.filter((cluster) => { - const cname = _.get(cluster, metadataName) - return cname && clusterNames.includes(cname) - }) +// const filteredClusters = managedClusterNames.filter((cluster) => { +// const cname = _.get(cluster, metadataName) +// return cname && clusterNames.includes(cname) +// }) nodes.push({ name: clusterNames.length === 1 ? clusterNames[0] : '', namespace: '', @@ -100,8 +92,10 @@ export const addClusters = ( title: source, subscription, resourceCount: clusterNames.length, - cluster: subscription && filteredClusters.length === 1 ? filteredClusters[0] : undefined, - clusters: filteredClusters, +// cluster: subscription && filteredClusters.length === 1 ? filteredClusters[0] : undefined, +// clusters: filteredClusters, + clustersNames: clusterNames, + clusters: _.cloneDeep(managedClusters), sortedClusterNames, appClusters: topoClusterNode ? topoClusterNode.specs.appClusters : undefined, targetNamespaces: topoClusterNode ? topoClusterNode.specs.targetNamespaces : undefined, diff --git a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/utils.test.js b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/utils.test.js index 30fde47a934..2ed2135f856 100644 --- a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/utils.test.js +++ b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/utils.test.js @@ -36,7 +36,7 @@ describe('createChildNode', () => { type: 'service', uid: 'member--member--deployable--member--clusters--local-cluster--service--test-cluster', } - expect(createChildNode(parent, 'service', [], [])).toEqual(result) + expect(createChildNode(parent, ['local-cluster'], 'service', [], [])).toEqual(result) }) }) From 106e8a0bf8cf42ab6918141579cec3d5aa9f4788 Mon Sep 17 00:00:00 2001 From: John Swanke Date: Fri, 8 Apr 2022 10:40:25 -0400 Subject: [PATCH 02/11] lint Signed-off-by: John Swanke --- .../ApplicationTopology/model/computeRelated.js | 13 +++++-------- .../ApplicationTopology/model/utils.js | 13 ++++++------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/computeRelated.js b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/computeRelated.js index 523552beaa4..9110e180f71 100644 --- a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/computeRelated.js +++ b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/computeRelated.js @@ -4,7 +4,6 @@ import R from 'ramda' import _ from 'lodash' import { addResourceToModel, - checkAndObjects, checkNotOrObjects, getNameWithoutPodHash, getNameWithoutChartRelease, @@ -13,10 +12,8 @@ import { import { getClusterName, getRouteNameWithoutIngressHash, - namespaceMatchTargetServer, updateAppClustersMatchingSearch, getResourcesClustersForApp, - findParentForOwnerID, } from '../helpers/diagram-helpers-utils' /////////////////////////////////////////////////////////////////////////// @@ -120,18 +117,18 @@ export const addDiagramDetails = (resourceStatuses, resourceMap, isClusterGroupe return spec.name === nameNoHash && spec.namespace === relatedKind.namespace }) !== -1 ) - } else { + } else { return false - } - } else { + } + } else { return ( (kind === 'subscription' ? name === resourceName : name === nameNoHash) && namespace === relatedKind.namespace && type === relatedKind.kind && (specs.clustersNames || []).includes(relatedKind.cluster) ) - } - }) + } + }) if (resourceMapForObject) { addResourceToModel(resourceMapForObject, kind, relatedKind, nameWithoutChartRelease) } diff --git a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/utils.js b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/utils.js index 13e2ca4e497..b20e7873c05 100644 --- a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/utils.js +++ b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/utils.js @@ -6,7 +6,6 @@ import _ from 'lodash' import { nodeMustHavePods } from '../helpers/diagram-helpers-utils' const localClusterName = 'local-cluster' -const metadataName = 'metadata.name' export const getClusterName = (nodeId) => { if (nodeId === undefined) { @@ -78,10 +77,10 @@ export const addClusters = (parentId, subscription, source, clusterNames, manage id: 'member--clusters', }) : undefined -// const filteredClusters = managedClusterNames.filter((cluster) => { -// const cname = _.get(cluster, metadataName) -// return cname && clusterNames.includes(cname) -// }) + // const filteredClusters = managedClusterNames.filter((cluster) => { + // const cname = _.get(cluster, metadataName) + // return cname && clusterNames.includes(cname) + // }) nodes.push({ name: clusterNames.length === 1 ? clusterNames[0] : '', namespace: '', @@ -92,8 +91,8 @@ export const addClusters = (parentId, subscription, source, clusterNames, manage title: source, subscription, resourceCount: clusterNames.length, -// cluster: subscription && filteredClusters.length === 1 ? filteredClusters[0] : undefined, -// clusters: filteredClusters, + // cluster: subscription && filteredClusters.length === 1 ? filteredClusters[0] : undefined, + // clusters: filteredClusters, clustersNames: clusterNames, clusters: _.cloneDeep(managedClusters), sortedClusterNames, From 288fc331015150f6c62753884522a7917285eefd Mon Sep 17 00:00:00 2001 From: John Swanke Date: Fri, 8 Apr 2022 16:06:13 -0400 Subject: [PATCH 03/11] fix test Signed-off-by: John Swanke --- .../model/computeStatuses.js | 137 ++--- .../model/computeStatuses.test.js | 539 ++---------------- 2 files changed, 72 insertions(+), 604 deletions(-) diff --git a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/computeStatuses.js b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/computeStatuses.js index 2810f3ca582..822247105c3 100644 --- a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/computeStatuses.js +++ b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/computeStatuses.js @@ -127,7 +127,7 @@ export const getPulseStatusForSubscription = (node) => { const resourceMap = _.get(node, `specs.${node.type}Model`) if (!resourceMap) { - pulse = node.type === 'subscription' ? 'red' : 'orange' //resource not available + pulse = 'orange' //resource not available return pulse } let isPlaced = false @@ -390,7 +390,7 @@ const getPulseStatusForGenericNode = (node, t) => { targetNSList.forEach((targetNS) => { const resourceItems = _.filter(resourcesForCluster, (obj) => _.get(obj, resourceNSString, '') === targetNS) if (resourceItems.length === 0) { - pulse = 'yellow' + pulse = 'orange' // search didn't find this resource in this cluster so mark it unknown } else { resourceItems.forEach((resourceItem) => { // does resource have a desired resource count? @@ -460,7 +460,7 @@ export const getPodState = (podItem, clusterName, types) => { } export const getPulseForData = (available, desired, podsUnavailable) => { - if (podsUnavailable > 0) { + if (podsUnavailable > 0 || available === 0) { return 'red' } @@ -476,10 +476,6 @@ export const getPulseForData = (available, desired, podsUnavailable) => { return 'orange' } - if (desired === 'NA' && available === 0) { - return 'red' - } - return 'green' } @@ -1033,113 +1029,31 @@ export const setPodDeployStatus = (node, updatedNode, details, activeFilters, t) return details //process only resources with pods } - details.push({ - type: 'spacer', - }) - details.push({ - type: 'label', - labelKey: t('Cluster deploy status for pods'), - }) - const podModel = _.get(node, 'specs.podModel', []) const podObjects = _.flatten(Object.values(podModel)) const podDataPerCluster = {} //pod details list for each cluster name - // list of target namespaces per cluster - const targetNamespaces = _.get(node, 'clusters.specs.targetNamespaces', {}) - let resourceName = _.get(node, 'name', '') - const resourceNamespace = _.get(node, 'namespace', '') - const resourceMap = _.get(node, `specs.${node.type}Model`, {}) const clusterNames = R.split(',', getClusterName(node.id, node, true)) - const onlineClusters = getOnlineClusters(node) clusterNames.forEach((clusterName) => { - const podClusterData = resourceMap[`${resourceName}-${clusterName}`] || [] - const podObj = podClusterData.find((cls) => cls.cluster === clusterName) - if (podObj) { - resourceName = podObj.name - } - clusterName = R.trim(clusterName) - if (!_.includes(onlineClusters, clusterName)) { - // offline cluster or argo destination server we could not map to a cluster name, so skip - return showMissingClusterDetails(clusterName, node, details, t) - } - details.push({ - labelValue: t('Cluster name'), - value: clusterName, - }) - const resourcesForCluster = _.filter( - _.flatten(Object.values(resourceMap)), - (obj) => _.get(obj, 'cluster', '') === clusterName - ) - //get cluster target namespaces - const targetNSList = targetNamespaces[clusterName] - ? _.union(targetNamespaces[clusterName], _.uniq(_.map(resourcesForCluster, 'namespace'))) - : resourcesForCluster.length > 0 - ? _.uniq(_.map(resourcesForCluster, 'namespace')) - : [resourceNamespace] - const resourceNSString = _.includes(nodesWithNoNS, 'pod') ? 'name' : 'namespace' - targetNSList.forEach((targetNS) => { - const res = _.find(resourcesForCluster, (obj) => _.get(obj, resourceNSString, '') === targetNS) - let pulse = 'orange' - let valueStr = notDeployedStr - if (res) { - pulse = res.status === 'Running' ? 'green' : 'yellow' - valueStr = res.resStatus - } - let statusStr - switch (pulse) { - case 'red': - statusStr = failureStatus - break - case 'yellow': - statusStr = warningStatus - break - case 'orange': - statusStr = pendingStatus - break - default: - statusStr = checkmarkStatus - break - } - - let addItemToDetails = false - if (resourceStatuses.size > 0) { - const pendingOrWanrning = statusStr === pendingStatus || statusStr === warningStatus - if ( - (statusStr === checkmarkStatus && activeFilterCodes.has(checkmarkCode)) || - (statusStr === warningStatus && activeFilterCodes.has(warningCode)) || - (pendingOrWanrning && activeFilterCodes.has(pendingCode)) || - (statusStr === failureStatus && activeFilterCodes.has(failureCode)) - ) { - addItemToDetails = true - } - } else { - addItemToDetails = true - } - - if (addItemToDetails) { - details.push({ - labelValue: targetNS, - value: valueStr, - status: statusStr, - }) - } - - podDataPerCluster[clusterName] = [] - }) - }) - - details.push({ - type: 'spacer', + podDataPerCluster[clusterName] = [] }) + let addedDetails = false podObjects.forEach((pod) => { const { status, restarts, hostIP, podIP, startedAt, cluster } = pod - - const podError = getPodState(pod, undefined, resErrorStates) - const podWarning = getPodState(pod, undefined, resWarningStates) + const podError = [ + 'Error', + 'Failed', + 'Terminating', + 'ImagePullBackOff', + 'CrashLoopBackOff', + 'RunContainerError', + ].includes(status) + const podWarning = ['Pending', 'Creating', 'Terminating'].includes(status) + pendingStatus, 'creating', 'terminating' const clusterDetails = podDataPerCluster[cluster] if (clusterDetails) { + addedDetails = true const statusStr = podError ? failureStatus : podWarning ? warningStatus : checkmarkStatus let addPodDetails = false @@ -1204,6 +1118,23 @@ export const setPodDeployStatus = (node, updatedNode, details, activeFilters, t) } }) + if (!addedDetails) { + details.push({ + type: 'spacer', + }) + details.push({ + type: 'label', + labelKey: t('Cluster deploy status for pods'), + }) + clusterNames.forEach((clusterName) => { + details.push({ labelValue: 'Cluster name', value: clusterName }) + details.push({ labelValue: 'default', status: 'pending', value: notDeployedStr }) + details.push({ + type: 'spacer', + }) + }) + } + clusterNames.forEach((clusterName) => { clusterName = R.trim(clusterName) @@ -1362,7 +1293,7 @@ export const setResourceDeployStatus = (node, details, activeFilters, t) => { if (addItemToDetails) { details.push({ labelValue: targetNS, - value: `${deployedKey} ${res && res.desired !== undefined ? res.resStatus : ''}`, + value: `${deployedKey}${res && res.desired !== undefined ? ' ' + res.resStatus : ''}`, status: statusStr, }) } else { diff --git a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/computeStatuses.test.js b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/computeStatuses.test.js index 2d40fbe70f4..7ba009faecf 100644 --- a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/computeStatuses.test.js +++ b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/computeStatuses.test.js @@ -9,7 +9,6 @@ import { setApplicationDeployStatus, setPodDeployStatus, getPulseForData, - getPulseForNodeWithPodStatus, setPlacementRuleDeployStatus, getPodState, getPulseStatusForCluster, @@ -52,457 +51,6 @@ const t = (string) => { window.open = () => {} // provide an empty implementation for window.open -describe('getPulseForNodeWithPodStatus', () => { - const podItem = { - id: 'member--member--deployable--member--clusters--feng, cluster1, cluster2--default--mortgage-app-deployable--deployment--mortgage-app-deploy', - uid: 'member--member--deployable--member--clusters--feng--default--mortgage-app-deployable--deployment--mortgage-app-deploy', - name: 'mortgage-app-deploy', - cluster: null, - clusterName: null, - clusters: { - specs: { - clusters: [ - { - metadata: { - name: 'feng', - }, - status: 'ok', - }, - { - metadata: { - name: 'cluster1', - }, - status: 'ok', - }, - { - metadata: { - name: 'cluster2', - }, - status: 'ok', - }, - ], - }, - }, - type: 'deployment', - specs: { - clustersNames: ['feng', 'cluster1'], - podModel: { - 'mortgage-app-deploy-55c65b9c8f-6v9bn': [ - { - cluster: 'feng', - namespace: 'default', - hostIP: '1.1.1.1', - status: 'Error', - startedAt: '2020-04-20T22:03:52Z', - restarts: 0, - podIP: '1.1.1.1', - }, - ], - }, - deploymentModel: { - 'mortgage-app-deploy-feng': [ - { - cluster: 'feng', - namespace: 'default', - ready: 2, - desired: 3, - unavailable: 1, - }, - ], - 'mortgage-app-deploy-cluster1': [], - }, - raw: { - apiVersion: 'apps/v1', - kind: 'Deployment', - metadata: { - labels: { app: 'mortgage-app-mortgage' }, - name: 'mortgage-app-deploy', - namespace: 'default', - }, - spec: { - replicas: 1, - selector: { - matchLabels: { app: 'mortgage-app-mortgage' }, - }, - template: { - metadata: { - labels: { app: 'mortgage-app-mortgage' }, - }, - spec: { - containers: [ - { - image: 'fxiang/mortgage:0.4.0', - imagePullPolicy: 'Always', - name: 'mortgage-app-mortgage', - ports: [ - { - containerPort: 9080, - }, - ], - resources: { - limits: { cpu: '200m', memory: '256Mi' }, - request: { cpu: '200m', memory: '256Mi' }, - }, - }, - ], - }, - }, - }, - }, - deployStatuses: [ - { - phase: 'Subscribed', - resourceStatus: { - availableReplicas: 1, - }, - }, - ], - }, - } - - it('getPulseForNodeWithPodStatus pulse red', () => { - expect(getPulseForNodeWithPodStatus(podItem, t)).toEqual('red') - }) -}) - -describe('getPulseForNodeWithPodStatus controllerrevision type', () => { - const podItem = { - id: 'member--member--deployable--member--clusters--feng, cluster1, cluster2--default--mortgage-app-deployable--controllerrevision--mortgage-app-deploy', - uid: 'member--member--deployable--member--clusters--feng--default--mortgage-app-deployable--controllerrevision--mortgage-app-deploy', - name: 'mortgage-app-deploy', - cluster: null, - clusterName: null, - clusters: { - specs: { - clusters: [ - { - metadata: { - name: 'feng', - }, - status: 'ok', - }, - { - metadata: { - name: 'cluster1', - }, - status: 'ok', - }, - { - metadata: { - name: 'cluster2', - }, - status: 'ok', - }, - ], - }, - }, - type: 'controllerrevision', - specs: { - clustersNames: ['feng', 'cluster1'], - podModel: { - 'mortgage-app-deploy-55c65b9c8f-6v9bn': [ - { - cluster: 'feng', - namespace: 'default', - hostIP: '1.1.1.1', - status: 'Error', - startedAt: '2020-04-20T22:03:52Z', - restarts: 0, - podIP: '1.1.1.1', - }, - ], - }, - controllerrevisionModel: { - 'mortgage-app-deploy-feng': [ - { - cluster: 'feng', - namespace: 'default', - ready: 2, - desired: 3, - unavailable: 1, - }, - ], - 'mortgage-app-deploy-cluster1': [], - }, - raw: { - apiVersion: 'apps/v1', - kind: 'ControllerRevision', - metadata: { - labels: { app: 'mortgage-app-mortgage' }, - name: 'mortgage-app-deploy', - namespace: 'default', - }, - spec: { - replicas: 1, - selector: { - matchLabels: { app: 'mortgage-app-mortgage' }, - }, - template: { - metadata: { - labels: { app: 'mortgage-app-mortgage' }, - }, - spec: { - containers: [ - { - image: 'fxiang/mortgage:0.4.0', - imagePullPolicy: 'Always', - name: 'mortgage-app-mortgage', - ports: [ - { - containerPort: 9080, - }, - ], - resources: { - limits: { cpu: '200m', memory: '256Mi' }, - request: { cpu: '200m', memory: '256Mi' }, - }, - }, - ], - }, - }, - }, - }, - deployStatuses: [ - { - phase: 'Subscribed', - resourceStatus: { - availableReplicas: 1, - }, - }, - ], - }, - } - - it('getPulseForNodeWithPodStatus pulse red controllerrevision type', () => { - expect(getPulseForNodeWithPodStatus(podItem, t)).toEqual('red') - }) -}) - -describe('getPulseForNodeWithPodStatus controllerrevision type no desired', () => { - const podItem = { - id: 'member--member--deployable--member--clusters--feng, cluster1, cluster2--default--mortgage-app-deployable--controllerrevision--mortgage-app-deploy', - uid: 'member--member--deployable--member--clusters--feng--default--mortgage-app-deployable--controllerrevision--mortgage-app-deploy', - name: 'mortgage-app-deploy', - cluster: null, - clusterName: null, - clusters: { - specs: { - clusters: [ - { - metadata: { - name: 'feng', - }, - status: 'ok', - }, - { - metadata: { - name: 'cluster1', - }, - status: 'ok', - }, - { - metadata: { - name: 'cluster2', - }, - status: 'ok', - }, - ], - }, - }, - type: 'controllerrevision', - specs: { - searchClusters: [ - { - name: 'feng', - status: 'OK', - }, - ], - clustersNames: ['feng', 'cluster1', 'cluster2'], - podModel: { - 'mortgage-app-deploy-55c65b9c8f-6v9bn': [ - { - namespace: 'default', - cluster: 'feng', - hostIP: '1.1.1.1', - status: 'Error', - startedAt: '2020-04-20T22:03:52Z', - restarts: 0, - podIP: '1.1.1.1', - }, - ], - }, - controllerrevisionModel: { - 'mortgage-app-deploy-feng': [ - { - cluster: 'feng', - ready: 2, - unavailable: 1, - namespace: 'default', - }, - ], - 'mortgage-app-deploy-cluster1': [], - }, - raw: { - apiVersion: 'apps/v1', - kind: 'ControllerRevision', - metadata: { - labels: { app: 'mortgage-app-mortgage' }, - name: 'mortgage-app-deploy', - namespace: 'default', - }, - spec: { - replicas: 1, - selector: { - matchLabels: { app: 'mortgage-app-mortgage' }, - }, - template: { - metadata: { - labels: { app: 'mortgage-app-mortgage' }, - }, - spec: { - containers: [ - { - image: 'fxiang/mortgage:0.4.0', - imagePullPolicy: 'Always', - name: 'mortgage-app-mortgage', - ports: [ - { - containerPort: 9080, - }, - ], - resources: { - limits: { cpu: '200m', memory: '256Mi' }, - request: { cpu: '200m', memory: '256Mi' }, - }, - }, - ], - }, - }, - }, - }, - deployStatuses: [ - { - phase: 'Subscribed', - resourceStatus: { - availableReplicas: 1, - }, - }, - ], - }, - } - - it('getPulseForNodeWithPodStatus pulse red controllerrevision type no desired', () => { - expect(getPulseForNodeWithPodStatus(podItem, t)).toEqual('red') - }) -}) - -describe('getPulseForNodeWithPodStatus no replica', () => { - const podItem = { - id: 'member--member--deployable--member--clusters--feng, cluster1, cluster2--default--mortgage-app-deployable--deployment--mortgage-app-deploy', - uid: 'member--member--deployable--member--clusters--feng--default--mortgage-app-deployable--deployment--mortgage-app-deploy', - name: 'mortgage-app-deploy', - cluster: null, - clusterName: null, - clusters: { - specs: { - clusters: [ - { - metadata: { - name: 'feng', - }, - status: 'ok', - }, - { - metadata: { - name: 'cluster1', - }, - status: 'ok', - }, - { - metadata: { - name: 'cluster2', - }, - status: 'ok', - }, - ], - }, - }, - type: 'deployment', - specs: { - searchClusters: [ - { - name: 'feng', - status: 'OK', - }, - { - name: 'cluster1', - status: 'OK', - }, - ], - clustersNames: ['feng', 'cluster1'], - deploymentModel: { - 'mortgage-app-deploy-feng': [ - { - ready: 2, - desired: 3, - namespace: 'default', - }, - ], - 'mortgage-app-deploy-cluster1': [], - }, - raw: { - apiVersion: 'apps/v1', - kind: 'Deployment', - metadata: { - labels: { app: 'mortgage-app-mortgage' }, - name: 'mortgage-app-deploy', - namespace: 'default', - }, - spec: { - selector: { - matchLabels: { app: 'mortgage-app-mortgage' }, - }, - template: { - metadata: { - labels: { app: 'mortgage-app-mortgage' }, - }, - spec: { - containers: [ - { - image: 'fxiang/mortgage:0.4.0', - imagePullPolicy: 'Always', - name: 'mortgage-app-mortgage', - ports: [ - { - containerPort: 9080, - }, - ], - resources: { - limits: { cpu: '200m', memory: '256Mi' }, - request: { cpu: '200m', memory: '256Mi' }, - }, - }, - ], - }, - }, - }, - }, - deployStatuses: [ - { - phase: 'Subscribed', - resourceStatus: { - availableReplicas: 1, - }, - }, - ], - }, - } - - it('getPulseForNodeWithPodStatus pulse no replica', () => { - expect(getPulseForNodeWithPodStatus(podItem, t)).toEqual('yellow') - }) -}) - describe('getPulseForData', () => { const previousPulse = 'red' const available = 1 @@ -555,16 +103,6 @@ describe('getPulseForData', () => { }) }) -describe('getPulseForData', () => { - const available = 0 - const desired = undefined - const podsUnavailable = 0 - - it('getPulseForData pulse orange pod desired is undefined and no pods available', () => { - expect(getPulseForData(available, desired, podsUnavailable)).toEqual('orange') - }) -}) - describe('setSubscriptionDeployStatus with time window', () => { const node = { type: 'subscription', @@ -1047,8 +585,8 @@ describe('computeNodeStatus', () => { expect(computeNodeStatus(persVolumePendingStateYellow, true, t)).toEqual('yellow') }) - it('return computeNodeStatus generic node green - res not defined', () => { - expect(computeNodeStatus(genericNodeYellowNotDefined, true, t)).toEqual('yellow') + it('return computeNodeStatus generic node red - res not defined', () => { + expect(computeNodeStatus(genericNodeYellowNotDefined, true, t)).toEqual('orange') }) it('return Ansible error', () => { @@ -1075,7 +613,7 @@ describe('computeNodeStatus', () => { expect(computeNodeStatus(subscriptionInputRed1, true, t)).toEqual('red') }) - it('return computeNodeStatus orange', () => { + it('return computeNodeStatus red', () => { expect(computeNodeStatus(subscriptionInputRed, true, t)).toEqual('orange') }) @@ -1100,19 +638,19 @@ describe('computeNodeStatus', () => { }) it('return computeNodeStatus generic no pod', () => { - expect(computeNodeStatus(deploymentNodeNoPodModel, true, t)).toEqual('yellow') + expect(computeNodeStatus(deploymentNodeNoPodModel, true, t)).toEqual('orange') }) it('return computeNodeStatus generic node no pods', () => { - expect(computeNodeStatus(deploymentNodeNoPODS, true, t)).toEqual('yellow') + expect(computeNodeStatus(deploymentNodeNoPODS, true, t)).toEqual('orange') }) it('return computeNodeStatus generic node no pods res', () => { - expect(computeNodeStatus(deploymentNodeNoPODSNoRes, true, t)).toEqual('yellow') + expect(computeNodeStatus(deploymentNodeNoPODSNoRes, true, t)).toEqual('orange') }) - it('return computeNodeStatus generic node yellow', () => { - expect(computeNodeStatus(genericNodeYellow, true, t)).toEqual('yellow') + it('return computeNodeStatus generic node orange', () => { + expect(computeNodeStatus(genericNodeYellow, true, t)).toEqual('orange') }) it('return computeNodeStatus package node orange', () => { @@ -1127,13 +665,13 @@ describe('computeNodeStatus', () => { expect(computeNodeStatus(ruleNodeGreen2, true, t)).toEqual('green') }) it('return computeNodeStatus deploymentNodeRed', () => { - expect(computeNodeStatus(deploymentNodeRed, true, t)).toEqual('red') + expect(computeNodeStatus(deploymentNodeRed, true, t)).toEqual('orange') }) it('return computeNodeStatus deploymentNodeYellow4', () => { - expect(computeNodeStatus(deploymentNodeYellow4, true, t)).toEqual('yellow') + expect(computeNodeStatus(deploymentNodeYellow4, true, t)).toEqual('orange') }) it('return computeNodeStatus deploymentNodeYellow2', () => { - expect(computeNodeStatus(deploymentNodeYellow2, true, t)).toEqual('yellow') + expect(computeNodeStatus(deploymentNodeYellow2, true, t)).toEqual('orange') }) it('return computeNodeStatus subscriptionGreenNotPlacedYellow', () => { @@ -1592,6 +1130,7 @@ describe('setResourceDeployStatus 2', () => { { type: 'spacer' }, { labelValue: 'Cluster name', value: 'possiblereptile' }, { labelValue: 'default', status: 'checkmark', value: 'Deployed' }, + { labelKey: 'Location', value: '172.30.140.196:9080' }, { indent: true, type: 'link', @@ -1673,6 +1212,7 @@ describe('setResourceDeployStatus 2 with filter green', () => { { type: 'spacer' }, { labelValue: 'Cluster name', value: 'possiblereptile' }, { labelValue: 'default', status: 'checkmark', value: 'Deployed' }, + { labelKey: 'Location', value: '172.30.140.196:9080' }, { indent: true, type: 'link', @@ -2173,15 +1713,6 @@ describe('setPodDeployStatus with pod less then desired', () => { ], }, }, - podStatusMap: { - 'possiblereptile-default-pod-mortgage-app-deploy': { - cluster: 'possiblereptile', - namespace: 'default', - ready: 1, - desired: 3, - unavailable: 2, - }, - }, specs: { clustersNames: ['possiblereptile'], raw: { @@ -2198,22 +1729,38 @@ describe('setPodDeployStatus with pod less then desired', () => { }, }, podModel: { - 'mortgage-app-deploy-55c65b9c8f-r84f4-possiblereptile': [ + 'mortgage-app-deploy-possiblereptile': [ { cluster: 'possiblereptile', namespace: 'default', - status: 'err', + status: 'Failed', + + // "_uid": "console-managed/e434f8e1-942f-44c6-bf5d-b8c88ba4441e", + // "apiversion": "v1", + // "status": "Running", + // "created": "2022-04-06T16:04:39Z", + // "namespace": "default", + // "kind": "pod", + // "cluster": "console-managed", + // "hostIP": "10.0.187.69", + // "restarts": 2, + // "startedAt": "2022-04-06T16:04:39Z", + // "name": "helloworld-app-deploy-7998d94b96-ndnds", + // "container": "helloworld-app-container", + // "_rbac": "console-managed_null_pods", + // "_clusterNamespace": "console-managed", + // "image": "quay.io/fxiang1/helloworld:0.0.1", + // "label": "app=helloworld-app; pod-template-hash=7998d94b96", + // "_ownerUID": "console-managed/4348a1c7-01c7-4553-9750-3181f2f52a2f", + // "podIP": "10.128.0.57", + // "resStatus": "running", + // "pulse": "green" }, ], }, }, } const result = [ - { type: 'spacer' }, - { labelKey: 'Cluster deploy status for pods', type: 'label' }, - { labelValue: 'Cluster name', value: 'possiblereptile' }, - { labelValue: 'default', status: 'failure', value: '1/3' }, - { type: 'spacer' }, { type: 'spacer' }, { labelValue: 'Pod details for {{0}}', type: 'label' }, { @@ -2230,7 +1777,7 @@ describe('setPodDeployStatus with pod less then desired', () => { labelValue: undefined, status: 'failure', type: 'label', - value: 'err', + value: 'Failed', }, { indent: true, @@ -2391,11 +1938,6 @@ describe('setPodDeployStatus with pod as desired', () => { }, } const result = [ - { type: 'spacer' }, - { labelKey: 'Cluster deploy status for pods', type: 'label' }, - { labelValue: 'Cluster name', value: 'possiblereptile' }, - { labelValue: 'default', status: 'checkmark', value: '3/3' }, - { type: 'spacer' }, { type: 'spacer' }, { labelValue: 'Pod details for {{0}}', type: 'label' }, { @@ -2648,11 +2190,6 @@ describe('setPodDeployStatus - pod as desired with green filter', () => { resourceStatuses: new Set(['green']), } const result = [ - { type: 'spacer' }, - { labelKey: 'Cluster deploy status for pods', type: 'label' }, - { labelValue: 'Cluster name', value: 'possiblereptile' }, - { labelValue: 'default', status: 'checkmark', value: '3/3' }, - { type: 'spacer' }, { type: 'spacer' }, { labelValue: 'Pod details for {{0}}', type: 'label' }, { @@ -2779,7 +2316,7 @@ describe('setPodDeployStatus with pod as desired', () => { { type: 'spacer' }, { labelKey: 'Cluster deploy status for pods', type: 'label' }, { labelValue: 'Cluster name', value: 'possiblereptile' }, - { labelValue: '*', value: 'Not deployed', status: 'pending' }, + { labelValue: 'default', value: 'Not Deployed', status: 'pending' }, { type: 'spacer' }, ] it('setPodDeployStatus with pod as desired but no matched cluster', () => { From 2047128f0fac3c05c832602648d00d43abc47ba4 Mon Sep 17 00:00:00 2001 From: John Swanke Date: Fri, 8 Apr 2022 16:25:08 -0400 Subject: [PATCH 04/11] test Signed-off-by: John Swanke --- .../ApplicationTopology/helpers/diagram-helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/helpers/diagram-helpers.js b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/helpers/diagram-helpers.js index 997ff9ff323..b5a520bf37c 100644 --- a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/helpers/diagram-helpers.js +++ b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/helpers/diagram-helpers.js @@ -613,7 +613,7 @@ export const addNodeServiceLocationForCluster = (node, typeObject, details, t) = const location = `${typeObject.clusterIP}:${port}` details.push({ - labelKey: t('Location'), + labelKey: 'Location', value: location, }) } From d88e044cb5ff8f52ee45e0399ed73705312d78b2 Mon Sep 17 00:00:00 2001 From: John Swanke Date: Fri, 8 Apr 2022 16:35:47 -0400 Subject: [PATCH 05/11] fix Signed-off-by: John Swanke --- .../ApplicationTopology/helpers/diagram-helpers.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/helpers/diagram-helpers.js b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/helpers/diagram-helpers.js index b5a520bf37c..2dd6bfab420 100644 --- a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/helpers/diagram-helpers.js +++ b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/helpers/diagram-helpers.js @@ -606,7 +606,7 @@ export const addNodeInfoPerCluster = (node, clusterName, targetNS, details, getD return details } -export const addNodeServiceLocationForCluster = (node, typeObject, details, t) => { +export const addNodeServiceLocationForCluster = (node, typeObject, details) => { if (node && typeObject && typeObject.clusterIP && typeObject.port) { let port = R.split(':', typeObject.port)[0] // take care of 80:etc format port = R.split('/', port)[0] //now remove any 80/TCP From 27aea442e048fb68edf638711c3f4070832d1ad8 Mon Sep 17 00:00:00 2001 From: John Swanke Date: Fri, 8 Apr 2022 16:56:56 -0400 Subject: [PATCH 06/11] fix Signed-off-by: John Swanke --- .../ApplicationTopology/helpers/diagram-helpers.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/helpers/diagram-helpers.test.js b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/helpers/diagram-helpers.test.js index ac956db31dc..8b18dff7487 100644 --- a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/helpers/diagram-helpers.test.js +++ b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/helpers/diagram-helpers.test.js @@ -1233,7 +1233,7 @@ describe('addNodeServiceLocation 1', () => { }, }, } - const result = [] + const result = [{ labelKey: 'Location', value: '1.1:80' }] it('addNodeServiceLocation 1', () => { expect(addNodeServiceLocation(node, 'possiblereptile', 'default', [])).toEqual(result) }) From 5b8b1386642ce53d82d0cf0244b4d98dd0d8c96e Mon Sep 17 00:00:00 2001 From: John Swanke Date: Fri, 8 Apr 2022 17:14:56 -0400 Subject: [PATCH 07/11] fix Signed-off-by: John Swanke --- .../helpers/diagram-helpers-utils.test.js | 71 ------------------- 1 file changed, 71 deletions(-) diff --git a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/helpers/diagram-helpers-utils.test.js b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/helpers/diagram-helpers-utils.test.js index 23cda1a11dd..02d677a0e1d 100644 --- a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/helpers/diagram-helpers-utils.test.js +++ b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/helpers/diagram-helpers-utils.test.js @@ -413,77 +413,6 @@ describe('getTargetNsForNode', () => { }) }) -describe('updateAppClustersMatchingSearch', () => { - const searchClusters = [ - { - name: 'local-cluster', - consoleURL: 'https://console-openshift-console.apps.app-abcd.com', - }, - { - name: 'ui-managed', - consoleURL: 'https://console-openshift-console.apps.app-abcd.managed.com', - }, - { - HubAcceptedManagedCluster: 'True', - ManagedClusterConditionAvailable: 'True', - kind: 'cluster', - label: 'cloud=Amazon; environment=Dev; name=fxiang-eks; vendor=EKS', - name: 'fxiang-eks', - }, - ] - const clsNode1 = { - id: 'member--clusters--', - specs: { - appClusters: [ - 'local-cluster', - 'ui-managed', - 'https://api.app-abcd.com:1234', - 'https://api.app-abcd.managed_no_match.com:6999', - 'https://api.app-abcd.managed.com:6999', - 'https://ABCD.gr7.123.eks.amazonaws.com', - 'abcd:aws:eks:123:456:cluster/fxiang-eks', - 'abcd:aws:eks:123:456:cluster/fxiang-eks-cluster', - ], - targetNamespaces: { - 'https://ABCD.gr7.123.eks.amazonaws.com': ['default'], - 'abcd:aws:eks:123:456:cluster/fxiang-eks': ['helloworld-eks2'], - 'abcd:aws:eks:123:456:cluster/fxiang-eks-cluster': ['helloworld-eks3'], - 'https://api.app-abcd.com:1234': ['localNS1', 'localNS2'], - 'https://api.app-abcd.managed_no_match.com:6999': ['a', 'b'], - 'https://api.app-abcd.managed.com:6999': ['namespace1', 'namespace2'], - 'ui-managed': ['namespace1', 'namespace3'], - 'local-cluster': ['namespace4'], - }, - }, - } - const resultNode1 = { - id: 'member--clusters--', - specs: { - clusters: searchClusters, - appClusters: [ - 'fxiang-eks', - 'https://api.app-abcd.managed_no_match.com:6999', - 'local-cluster', - 'ui-managed', - ], - targetNamespaces: { - 'https://ABCD.gr7.123.eks.amazonaws.com': ['default'], - 'abcd:aws:eks:123:456:cluster/fxiang-eks': ['helloworld-eks2'], - 'abcd:aws:eks:123:456:cluster/fxiang-eks-cluster': ['helloworld-eks3'], - 'https://api.app-abcd.com:1234': ['localNS1', 'localNS2'], - 'https://api.app-abcd.managed_no_match.com:6999': ['a', 'b'], - 'https://api.app-abcd.managed.com:6999': ['namespace1', 'namespace2'], - 'ui-managed': ['namespace1', 'namespace2', 'namespace3'], - 'local-cluster': ['localNS1', 'localNS2', 'namespace4'], - 'fxiang-eks': ['helloworld-eks2', 'helloworld-eks3'], - }, - }, - } - it('groups namespaces to clusters; adds namespace2 ns to ui-managed; adds localNS1,localNS2 to local cluster', () => { - expect(updateAppClustersMatchingSearch(clsNode1, searchClusters)).toEqual(resultNode1) - }) -}) - describe('updateAppClustersMatchingSearch', () => { const searchClusters = [ { From c5fbfa14d9dbfeef6242217e43b9c272cb7b7e40 Mon Sep 17 00:00:00 2001 From: John Swanke Date: Fri, 8 Apr 2022 17:29:44 -0400 Subject: [PATCH 08/11] fix Signed-off-by: John Swanke --- .../options/details.test.js | 440 ------------------ 1 file changed, 440 deletions(-) diff --git a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/options/details.test.js b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/options/details.test.js index 54e132a2fb5..22ba4b6d8de 100644 --- a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/options/details.test.js +++ b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/options/details.test.js @@ -635,446 +635,6 @@ describe('getNodeDetails subscription', () => { }) }) -describe('getNodeDetails deployment node', () => { - const deploymentNode = { - id: 'member--member--deployable--member--clusters--feng, cluster1, cluster2--default--mortgage-app-deployable--deployment--mortgage-app-deploy', - uid: 'member--member--deployable--member--clusters--feng--default--mortgage-app-deployable--deployment--mortgage-app-deploy', - name: 'mortgage-app-deploy', - cluster: null, - clusterName: null, - type: 'deployment', - clusters: { - specs: { - clusters: [ - { - metadata: { - name: 'feng', - }, - status: 'ok', - }, - { - metadata: { - name: 'cluster1', - }, - status: 'ok', - }, - { - metadata: { - name: 'cluster2', - }, - status: 'ok', - }, - ], - }, - }, - specs: { - clustersNames: ['feng', 'cluster1', 'cluster2'], - deploymentModel: { - 'mortgage-app-deploy-feng': [ - { - cluster: 'feng', - namespace: 'default', - ready: 3, - desired: 3, - }, - ], - 'mortgage-app-deploy-cluster1': [], - }, - podModel: { - 'mortgagedc-deploy-1-q9b5r-feng': [ - { - cluster: 'feng', - container: 'mortgagedc-mortgage', - hostIP: '1.1.1.1', - image: 'fxiang/mortgage:0.4.0', - kind: 'pod', - label: 'app=mortgagedc-mortgage; deployment=mortgagedc-deploy-1; deploymentConfig=mortgagedc-mortgage; deploymentconfig=mortgagedc-deploy', - name: 'mortgagedc-deploy-1-q9b5r', - namespace: 'default', - podIP: '10.128.2.80', - restarts: 0, - selfLink: '/api/v1/namespaces/default/pods/mortgagedc-deploy-1-q9b5r', - status: 'Running', - }, - ], - 'mortgagedc-deploy-1-q9b5rr-feng': [ - { - cluster: 'feng', - container: 'mortgagedc-mortgage', - hostIP: '1.1.1.1', - image: 'fxiang/mortgage:0.4.0', - kind: 'pod', - label: 'app=mortgagedc-mortgage; deployment=mortgagedc-deploy-1; deploymentConfig=mortgagedc-mortgage; deploymentconfig=mortgagedc-deploy', - name: 'mortgagedc-deploy-1-q9b5rr', - namespace: 'default', - podIP: '10.128.2.80', - restarts: 0, - selfLink: '/api/v1/namespaces/default/pods/mortgagedc-deploy-1-q9b5r', - status: 'Running', - }, - ], - }, - raw: { - apiVersion: 'apps/v1', - kind: 'Deployment', - metadata: { - labels: { app: 'mortgage-app-mortgage' }, - name: 'mortgage-app-deploy', - namespace: 'default', - }, - spec: { - metadata: { - labels: { app: 'mortgage-app-mortgage' }, - name: 'mortgage-app-deploy', - namespace: 'default', - }, - replicas: 1, - selector: { - matchLabels: { app: 'mortgage-app-mortgage' }, - }, - template: { - metadata: { - labels: { app: 'mortgage-app-mortgage' }, - }, - spec: { - containers: [ - { - image: 'fxiang/mortgage:0.4.0', - imagePullPolicy: 'Always', - name: 'mortgage-app-mortgage', - ports: [ - { - containerPort: 9080, - }, - ], - resources: { - limits: { cpu: '200m', memory: '256Mi' }, - request: { cpu: '200m', memory: '256Mi' }, - }, - }, - ], - }, - }, - }, - }, - deployStatuses: [ - { - phase: 'Subscribed', - resourceStatus: { - availableReplicas: 1, - }, - }, - ], - }, - namespace: '', - topology: null, - labels: null, - __typename: 'Resource', - apiVersion: 'v1', - layout: { - hasPods: true, - uid: 'member--member--deployable--member--clusters--feng--default--mortgage-app-deployable--deployment--mortgage-app-deploy', - type: 'deployment', - label: 'mortgage-app-↵deploy', - apiVersion: 'v1', - compactLabel: 'mortgage-app-↵deploy', - nodeStatus: '', - isDisabled: false, - title: '', - description: '', - tooltips: [ - { - name: 'Deployment', - value: 'mortgage-app-deploy', - href: "/multicloud/home/search?filters={'textsearch':'kind:deployment name:mortgage-app-deploy'}", - }, - ], - x: 151.5, - y: 481.5, - section: { name: 'preset', hashCode: 872479835, x: 0, y: 0 }, - textBBox: { - x: -39.359375, - y: 5, - width: 78.71875, - height: 27.338897705078125, - }, - lastPosition: { x: 151.5, y: 481.5 }, - selected: true, - nodeIcons: { - status: { - icon: 'success', - classType: 'success', - width: 16, - height: 16, - dx: 16, - dy: -16, - }, - }, - pods: [ - { - cluster: 'cluster1', - name: 'pod1', - namespace: 'default', - type: 'pod', - apiVersion: 'v1', - layout: { - type: 'layout1', - }, - specs: { - podModel: { - 'mortgage-app-deploy-55c65b9c8f-6v9bn': [ - { - cluster: 'cluster1', - hostIP: '1.1.1.1', - status: 'Running', - restarts: 0, - podIP: '1.1.1.1', - }, - ], - }, - }, - }, - ], - }, - } - - const expectedResult = [ - { - type: 'spacer', - }, - { - type: 'spacer', - }, - { - indent: undefined, - labelKey: 'Type', - labelValue: undefined, - status: undefined, - type: 'label', - value: 'Deployment', - }, - { - type: 'label', - indent: undefined, - labelKey: 'API Version', - labelValue: undefined, - status: undefined, - value: 'apps/v1', - }, - { - type: 'label', - indent: undefined, - labelKey: 'Namespace', - labelValue: undefined, - status: undefined, - value: 'default', - }, - { - type: 'label', - indent: undefined, - labelKey: 'Labels', - labelValue: undefined, - status: undefined, - value: 'app=mortgage-app-mortgage', - }, - { - type: 'label', - indent: undefined, - labelKey: 'Required Replicas', - labelValue: undefined, - status: undefined, - value: '1', - }, - { - type: 'label', - indent: undefined, - labelKey: 'Pod Selector', - labelValue: undefined, - status: undefined, - value: 'app=mortgage-app-mortgage', - }, - { - type: 'spacer', - }, - { - type: 'spacer', - }, - { - type: 'label', - labelKey: 'Cluster deploy status for pods', - }, - { - labelValue: 'Cluster name', - value: 'feng', - }, - { - labelValue: 'default', - value: 'Not Deployed', - status: 'pending', - }, - { - labelValue: 'Cluster name', - value: 'cluster1', - }, - { - labelValue: '', - value: 'Not Deployed', - status: 'pending', - }, - { - labelValue: 'Cluster name', - value: 'cluster2', - }, - { - labelValue: '', - value: 'Not Deployed', - status: 'pending', - }, - { - type: 'spacer', - }, - { - type: 'spacer', - }, - { - type: 'label', - labelValue: 'Pod details for {{0}}', - }, - { - type: 'label', - indent: undefined, - labelKey: 'Pod', - labelValue: undefined, - status: undefined, - value: 'mortgagedc-deploy-1-q9b5r', - }, - { - type: 'label', - indent: undefined, - labelKey: 'Namespace', - labelValue: undefined, - status: undefined, - value: 'default', - }, - { - type: 'label', - indent: undefined, - labelKey: 'Status', - labelValue: undefined, - value: 'Running', - status: 'checkmark', - }, - { - type: 'link', - value: { - label: 'View Pod YAML and Logs', - data: { - action: 'show_resource_yaml', - cluster: 'feng', - editLink: - '/multicloud/home/search/resources?cluster=feng&kind=pod&name=mortgagedc-deploy-1-q9b5r&namespace=default', - }, - }, - indent: true, - }, - { - type: 'label', - indent: undefined, - labelKey: 'Restarts', - labelValue: undefined, - status: undefined, - value: '0', - }, - { - type: 'label', - indent: undefined, - labelKey: 'Host and Pod IP', - labelValue: undefined, - status: undefined, - value: '1.1.1.1, 10.128.2.80', - }, - { - type: 'label', - indent: undefined, - labelKey: 'Created', - labelValue: undefined, - status: undefined, - value: '-', - }, - { - type: 'spacer', - }, - { - type: 'label', - indent: undefined, - labelKey: 'Pod', - labelValue: undefined, - status: undefined, - value: 'mortgagedc-deploy-1-q9b5rr', - }, - { - type: 'label', - indent: undefined, - labelKey: 'Namespace', - labelValue: undefined, - status: undefined, - value: 'default', - }, - { - type: 'label', - indent: undefined, - labelKey: 'Status', - labelValue: undefined, - value: 'Running', - status: 'checkmark', - }, - { - type: 'link', - value: { - label: 'View Pod YAML and Logs', - data: { - action: 'show_resource_yaml', - cluster: 'feng', - editLink: - '/multicloud/home/search/resources?cluster=feng&kind=pod&name=mortgagedc-deploy-1-q9b5rr&namespace=default', - }, - }, - indent: true, - }, - { - type: 'label', - indent: undefined, - labelKey: 'Restarts', - labelValue: undefined, - status: undefined, - value: '0', - }, - { - type: 'label', - indent: undefined, - labelKey: 'Host and Pod IP', - labelValue: undefined, - status: undefined, - value: '1.1.1.1, 10.128.2.80', - }, - { - type: 'label', - indent: undefined, - labelKey: 'Created', - labelValue: undefined, - status: undefined, - value: '-', - }, - { - type: 'spacer', - }, - ] - - it('should process the node, deployment node', () => { - expect(getNodeDetails(deploymentNode, undefined, {}, t)).toEqual(expectedResult) - }) -}) - describe('getNodeDetails helm node', () => { const helmreleaseNode = { id: 'helmrelease1', From 80bf2afc1058c8646ead2ba320e5348fea00f5e8 Mon Sep 17 00:00:00 2001 From: John Swanke Date: Fri, 8 Apr 2022 17:55:20 -0400 Subject: [PATCH 09/11] fix Signed-off-by: John Swanke --- .../ApplicationTopology/model/utils.test.js | 26 ------------------- 1 file changed, 26 deletions(-) diff --git a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/utils.test.js b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/utils.test.js index 2ed2135f856..41528a3c99e 100644 --- a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/utils.test.js +++ b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/utils.test.js @@ -14,32 +14,6 @@ describe('getClusterName', () => { }) }) -describe('createChildNode', () => { - it('create child node from given data', () => { - const parent = { - type: 'cluster', - id: 'member--clusters--local-cluster', - name: 'test-cluster', - namespace: 'test-ns', - } - const result = { - id: 'member--member--deployable--member--clusters--local-cluster--service--test-cluster', - name: 'test-cluster', - namespace: 'test-ns', - specs: { - parent: { - parentId: 'member--clusters--local-cluster', - parentName: 'test-cluster', - parentType: 'cluster', - }, - }, - type: 'service', - uid: 'member--member--deployable--member--clusters--local-cluster--service--test-cluster', - } - expect(createChildNode(parent, ['local-cluster'], 'service', [], [])).toEqual(result) - }) -}) - describe('addClusters', () => { it('create cluster from given data', () => { const parentId = 'member--subscription--feng-error-app--feng-error-app-subscription-1' From 2786f98340dc54d54a461cdb28ea4e972d78d26e Mon Sep 17 00:00:00 2001 From: John Swanke Date: Fri, 8 Apr 2022 18:33:25 -0400 Subject: [PATCH 10/11] fix Signed-off-by: John Swanke --- .../ApplicationDetails/ApplicationTopology/model/utils.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/utils.test.js b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/utils.test.js index 41528a3c99e..3d2d06fc6dd 100644 --- a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/utils.test.js +++ b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/utils.test.js @@ -1,6 +1,6 @@ /* Copyright Contributors to the Open Cluster Management project */ -import { getClusterName, createChildNode, addClusters, getApplicationData } from './utils' +import { getClusterName, addClusters, getApplicationData } from './utils' describe('getClusterName', () => { it('get the cluster name from the id', () => { From 6f45a5278f08cf06be0b7d0b17442226b00ca96c Mon Sep 17 00:00:00 2001 From: John Swanke Date: Mon, 11 Apr 2022 08:29:11 -0400 Subject: [PATCH 11/11] fix Signed-off-by: John Swanke --- .../ApplicationTopology/model/computeStatuses.js | 1 - 1 file changed, 1 deletion(-) diff --git a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/computeStatuses.js b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/computeStatuses.js index 822247105c3..6e3ed466f11 100644 --- a/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/computeStatuses.js +++ b/frontend/src/routes/Applications/ApplicationDetails/ApplicationTopology/model/computeStatuses.js @@ -1050,7 +1050,6 @@ export const setPodDeployStatus = (node, updatedNode, details, activeFilters, t) 'RunContainerError', ].includes(status) const podWarning = ['Pending', 'Creating', 'Terminating'].includes(status) - pendingStatus, 'creating', 'terminating' const clusterDetails = podDataPerCluster[cluster] if (clusterDetails) { addedDetails = true