@skyhook-io/k8s-ui 1.13.3 → 1.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +4 -4
- package/src/components/applications/AppTooltips.tsx +13 -1
- package/src/components/applications/ApplicationDetail.test.tsx +25 -0
- package/src/components/applications/ApplicationDetail.tsx +39 -7
- package/src/components/applications/ApplicationsView.tsx +18 -3
- package/src/components/applications/ReadyBar.tsx +3 -2
- package/src/components/applications/applications-view.test.tsx +91 -0
- package/src/components/cluster-switcher/ClusterSwitcher.tsx +4 -1
- package/src/components/issues/IssuesView.tsx +40 -31
- package/src/components/issues/ResourceIssuesSection.tsx +3 -2
- package/src/components/issues/index.ts +3 -1
- package/src/components/issues/issue-timing.ts +123 -4
- package/src/components/issues/issues.test.ts +221 -10
- package/src/components/issues/types.ts +31 -5
- package/src/components/namespace-switcher/NamespacePicker.tsx +21 -13
- package/src/components/resources/ResourcesView.tsx +966 -98
- package/src/components/resources/column-settings-key.test.ts +98 -0
- package/src/components/resources/column-visibility-merge.test.ts +64 -0
- package/src/components/resources/curated-column-ownership.test.ts +236 -0
- package/src/components/resources/gateway-policy-status.test.ts +291 -0
- package/src/components/resources/gateway-policy-status.ts +237 -0
- package/src/components/resources/generic-status.test.ts +199 -0
- package/src/components/resources/generic-status.ts +171 -0
- package/src/components/resources/gpu-ecosystem-registry.test.ts +63 -0
- package/src/components/resources/index.ts +9 -1
- package/src/components/resources/istio-gateway-filter.test.ts +97 -0
- package/src/components/resources/kyverno-legacy-action.test.ts +100 -1
- package/src/components/resources/kyverno-modern-posture.test.ts +36 -0
- package/src/components/resources/printer-columns.test.ts +298 -0
- package/src/components/resources/printer-columns.ts +249 -0
- package/src/components/resources/renderers/CNPGBackupRenderer.test.tsx +29 -0
- package/src/components/resources/renderers/CNPGBackupRenderer.tsx +3 -2
- package/src/components/resources/renderers/CNPGClusterRenderer.test.tsx +69 -3
- package/src/components/resources/renderers/CNPGClusterRenderer.tsx +6 -2
- package/src/components/resources/renderers/EventRenderer.test.tsx +50 -1
- package/src/components/resources/renderers/EventRenderer.tsx +3 -5
- package/src/components/resources/renderers/GenericRenderer.tsx +18 -83
- package/src/components/resources/renderers/HPARenderer.test.tsx +28 -0
- package/src/components/resources/renderers/HPARenderer.tsx +6 -1
- package/src/components/resources/renderers/KyvernoPolicyReportRenderer.tsx +12 -7
- package/src/components/resources/renderers/MetricsUnavailableNotice.tsx +2 -1
- package/src/components/resources/renderers/PVCRenderer.test.tsx +44 -0
- package/src/components/resources/renderers/PVCRenderer.tsx +19 -2
- package/src/components/resources/renderers/PolicyCoverageSection.test.tsx +92 -1
- package/src/components/resources/renderers/PolicyCoverageSection.tsx +64 -8
- package/src/components/resources/renderers/RolloutRenderer.test.tsx +35 -0
- package/src/components/resources/renderers/RolloutRenderer.tsx +22 -3
- package/src/components/resources/renderers/VeleroBSLRenderer.test.tsx +47 -0
- package/src/components/resources/renderers/VeleroBSLRenderer.tsx +16 -1
- package/src/components/resources/renderers/VeleroRestoreRenderer.test.tsx +88 -0
- package/src/components/resources/renderers/VeleroRestoreRenderer.tsx +44 -2
- package/src/components/resources/renderers/WorkloadRenderer.test.tsx +83 -0
- package/src/components/resources/renderers/WorkloadRenderer.tsx +25 -65
- package/src/components/resources/renderers/amd-gpu-cells.tsx +36 -0
- package/src/components/resources/renderers/cnpg-cells.tsx +12 -1
- package/src/components/resources/renderers/inference-gateway-cells.tsx +62 -0
- package/src/components/resources/renderers/jobset-lws-cells.tsx +82 -0
- package/src/components/resources/renderers/kai-cells.tsx +67 -0
- package/src/components/resources/renderers/kaito-cells.tsx +62 -0
- package/src/components/resources/renderers/kserve-cells.tsx +145 -0
- package/src/components/resources/renderers/kubeflow-training-cells.tsx +72 -0
- package/src/components/resources/renderers/kueue-cells.tsx +176 -0
- package/src/components/resources/renderers/kyverno-cells.tsx +8 -4
- package/src/components/resources/renderers/nim-cells.tsx +81 -0
- package/src/components/resources/renderers/ray-cells.tsx +124 -0
- package/src/components/resources/renderers/volcano-cells.tsx +140 -0
- package/src/components/resources/resource-utils-amd-gpu.ts +61 -0
- package/src/components/resources/resource-utils-cnpg.golden.test.ts +13 -5
- package/src/components/resources/resource-utils-cnpg.test.ts +142 -2
- package/src/components/resources/resource-utils-cnpg.ts +132 -7
- package/src/components/resources/resource-utils-gpu-ecosystem.test.ts +236 -0
- package/src/components/resources/resource-utils-hpa.test.ts +4 -0
- package/src/components/resources/resource-utils-hpa.ts +6 -2
- package/src/components/resources/resource-utils-inference-gateway.ts +119 -0
- package/src/components/resources/resource-utils-jobset-lws.ts +117 -0
- package/src/components/resources/resource-utils-kai.ts +105 -0
- package/src/components/resources/resource-utils-kaito.ts +114 -0
- package/src/components/resources/resource-utils-kserve.ts +186 -0
- package/src/components/resources/resource-utils-kubeflow-training.ts +121 -0
- package/src/components/resources/resource-utils-kueue.ts +200 -0
- package/src/components/resources/resource-utils-kyverno-modern.ts +3 -1
- package/src/components/resources/resource-utils-kyverno.ts +51 -2
- package/src/components/resources/resource-utils-nim.ts +109 -0
- package/src/components/resources/resource-utils-ray.ts +214 -0
- package/src/components/resources/resource-utils-rollout.test.ts +183 -0
- package/src/components/resources/resource-utils-velero.test.ts +30 -0
- package/src/components/resources/resource-utils-velero.ts +32 -0
- package/src/components/resources/resource-utils-volcano.ts +176 -0
- package/src/components/resources/resource-utils.ts +156 -47
- package/src/components/resources/resources-column-filter.test.ts +27 -1
- package/src/components/resources/workload-rollout-golden.test.ts +55 -0
- package/src/components/shared/CreateResourceDialog.tsx +1 -0
- package/src/components/shared/EditableYamlView.tsx +4 -2
- package/src/components/shared/ResourceActionsBar.tsx +170 -25
- package/src/components/shared/ResourceRendererDispatch.test.tsx +206 -1
- package/src/components/shared/ResourceRendererDispatch.tsx +84 -40
- package/src/components/shared/SetImageDialog.test.ts +129 -0
- package/src/components/shared/SetImageDialog.tsx +577 -0
- package/src/components/shared/index.ts +1 -0
- package/src/components/shared/revision-role-badges.test.ts +56 -4
- package/src/components/timeline/TimelineList.tsx +19 -3
- package/src/components/timeline/TimelineSwimlanes.tsx +11 -3
- package/src/components/trace/ReachabilityView.tsx +1 -1
- package/src/components/ui/SelectMenu.tsx +10 -1
- package/src/components/ui/drawer-components.tsx +12 -0
- package/src/components/workload/WorkloadRolloutNotice.tsx +60 -0
- package/src/components/workload/WorkloadView.tsx +144 -81
- package/src/hooks/useProgressiveRefresh.ts +37 -0
- package/src/source-hygiene.test.ts +28 -0
- package/src/theme/tailwind-theme.css +4 -0
- package/src/types/core.ts +55 -0
- package/src/utils/api-resources.test.ts +40 -1
- package/src/utils/api-resources.ts +11 -1
- package/src/utils/applications.ts +50 -0
- package/src/utils/bulk-workload-actions.test.ts +20 -0
- package/src/utils/bulk-workload-actions.ts +15 -0
- package/src/utils/navigation.test.ts +31 -1
- package/src/utils/navigation.ts +21 -2
- package/src/utils/workload-rollout.ts +292 -0
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { clsx } from 'clsx'
|
|
2
|
-
import { SEVERITY_BADGE } from '../../utils/badge-colors'
|
|
2
|
+
import { SEVERITY_BADGE, HEALTH_BADGE_COLORS } from '../../utils/badge-colors'
|
|
3
|
+
import { isArgoRolloutResource } from '../../utils/workload-rollout'
|
|
4
|
+
import { getGenericResourceStatus } from '../resources/generic-status'
|
|
3
5
|
import {
|
|
4
6
|
getPodStatus,
|
|
7
|
+
getWorkloadDisplayStatus,
|
|
5
8
|
getWorkloadStatus,
|
|
6
9
|
getJobStatus,
|
|
7
10
|
getCronJobStatus,
|
|
@@ -9,7 +12,6 @@ import {
|
|
|
9
12
|
getServiceStatus,
|
|
10
13
|
getNodeStatus,
|
|
11
14
|
getPVCStatus,
|
|
12
|
-
getRolloutStatus,
|
|
13
15
|
getAnalysisRunStatus,
|
|
14
16
|
getWorkflowStatus,
|
|
15
17
|
getCronWorkflowStatus,
|
|
@@ -65,6 +67,17 @@ import {
|
|
|
65
67
|
} from '../resources/resource-utils-kyverno-exceptions'
|
|
66
68
|
import { getResourceClaimStatus, getResourceClaimTemplateStatus, getDeviceClassStatus, getResourceSliceStatus } from '../resources/resource-utils-dra'
|
|
67
69
|
import { getNvidiaClusterPolicyStatus, getNvidiaDriverStatus } from '../resources/resource-utils-nvidia'
|
|
70
|
+
import { getClusterQueueStatus, getLocalQueueStatus, getKueueWorkloadStatus, getResourceFlavorStatus, getAdmissionCheckStatus, getProvisioningRequestStatus } from '../resources/resource-utils-kueue'
|
|
71
|
+
import { getRayClusterStatus, getRayJobStatus, getRayServiceStatus, getRayCronJobStatus } from '../resources/resource-utils-ray'
|
|
72
|
+
import { getLeaderWorkerSetStatus, getJobSetStatus } from '../resources/resource-utils-jobset-lws'
|
|
73
|
+
import { getInferenceServiceStatus, getServingRuntimeStatus, getInferenceGraphStatus, getTrainedModelStatus, getLLMInferenceServiceStatus } from '../resources/resource-utils-kserve'
|
|
74
|
+
import { getInferencePoolStatus, getInferenceObjectiveStatus } from '../resources/resource-utils-inference-gateway'
|
|
75
|
+
import { getVolcanoJobStatus, getVolcanoQueueStatus, getVolcanoPodGroupStatus, getJobFlowStatus, getJobTemplateStatus } from '../resources/resource-utils-volcano'
|
|
76
|
+
import { getKaiQueueStatus, getKaiPodGroupStatus } from '../resources/resource-utils-kai'
|
|
77
|
+
import { getKaitoWorkspaceStatus, getRAGEngineStatus } from '../resources/resource-utils-kaito'
|
|
78
|
+
import { getNIMServiceStatus, getNIMCacheStatus, getNIMPipelineStatus } from '../resources/resource-utils-nim'
|
|
79
|
+
import { getAMDDeviceConfigStatus } from '../resources/resource-utils-amd-gpu'
|
|
80
|
+
import { getPyTorchJobStatus, getTFJobStatus, getMPIJobStatus, getTrainJobStatus } from '../resources/resource-utils-kubeflow-training'
|
|
68
81
|
import { getBackupStatus, getRestoreStatus, getScheduleStatus, getBSLStatus, getBackupRepositoryStatus, isVeleroResource } from '../resources/resource-utils-velero'
|
|
69
82
|
import {
|
|
70
83
|
getVirtualServiceStatus,
|
|
@@ -272,7 +285,7 @@ import {
|
|
|
272
285
|
isComposite,
|
|
273
286
|
isClaim,
|
|
274
287
|
} from '../resources/resource-utils-crossplane'
|
|
275
|
-
import type { SelectedResource, Relationships, ResourceRef, SecretCertificateInfo, ResolvedEnvFrom, TimelineEvent, HPADiagnosis } from '../../types'
|
|
288
|
+
import type { SelectedResource, Relationships, ResourceRef, SecretCertificateInfo, ResolvedEnvFrom, TimelineEvent, HPADiagnosis, WorkloadPodInfo } from '../../types'
|
|
276
289
|
import type { CopyHandler } from '../ui/drawer-components'
|
|
277
290
|
import { AlertBanner } from '../ui/drawer-components'
|
|
278
291
|
import { replicaScalers } from '../../utils/replica-scalers'
|
|
@@ -310,6 +323,7 @@ export interface RendererOverrides {
|
|
|
310
323
|
relationships?: Relationships
|
|
311
324
|
scaleBlockedBy?: ResourceRef[]
|
|
312
325
|
scalerDiagnostics?: ScalerDiagnosis[]
|
|
326
|
+
workloadPods?: WorkloadPodInfo[]
|
|
313
327
|
}>
|
|
314
328
|
// Optional override for Crossplane Composite / Claim — host wraps the
|
|
315
329
|
// package renderer to fan out per-composed-ref status fetches via React Query.
|
|
@@ -500,6 +514,7 @@ interface ResourceRendererDispatchProps {
|
|
|
500
514
|
certificateInfo?: SecretCertificateInfo
|
|
501
515
|
hpaDiagnosis?: HPADiagnosis
|
|
502
516
|
scalerDiagnostics?: ScalerDiagnosis[]
|
|
517
|
+
workloadPods?: WorkloadPodInfo[]
|
|
503
518
|
onCopy: (text: string, key: string) => void
|
|
504
519
|
copied: string | null
|
|
505
520
|
onNavigate?: (ref: ResourceRef) => void
|
|
@@ -545,6 +560,7 @@ export function ResourceRendererDispatch({
|
|
|
545
560
|
certificateInfo,
|
|
546
561
|
hpaDiagnosis,
|
|
547
562
|
scalerDiagnostics,
|
|
563
|
+
workloadPods,
|
|
548
564
|
onCopy,
|
|
549
565
|
copied,
|
|
550
566
|
onNavigate,
|
|
@@ -646,7 +662,7 @@ export function ResourceRendererDispatch({
|
|
|
646
662
|
kind === 'clusters' || kind === 'backups' || kind === 'scheduledbackups' || kind === 'poolers'
|
|
647
663
|
|| kind === 'objectstores' || kind === 'databases' || kind === 'publications'
|
|
648
664
|
|| kind === 'subscriptions' || kind === 'imagecatalogs' || kind === 'clusterimagecatalogs'
|
|
649
|
-
|| kind === 'policies'
|
|
665
|
+
|| kind === 'policies' || kind === 'rollouts'
|
|
650
666
|
const isCNPGApiVersion = isApiGroup(data?.apiVersion, CNPG_GROUP)
|
|
651
667
|
const groupGatedMatched =
|
|
652
668
|
(kind === 'clusters' && (isCNPGApiVersion || isApiGroup(data?.apiVersion, 'cluster.x-k8s.io')))
|
|
@@ -658,6 +674,7 @@ export function ResourceRendererDispatch({
|
|
|
658
674
|
|| (kind === 'subscriptions'
|
|
659
675
|
&& (isCNPGApiVersion || isApiGroup(data?.apiVersion, 'messaging.knative.dev')))
|
|
660
676
|
|| (kind === 'policies' && isApiGroup(data?.apiVersion, 'kyverno.io'))
|
|
677
|
+
|| (kind === 'rollouts' && isArgoRolloutResource(data))
|
|
661
678
|
const groupGatedFallthrough = isGroupGatedKind && !groupGatedMatched
|
|
662
679
|
|
|
663
680
|
const calicoApiVersionMatched = isCalicoApiVersion(data?.apiVersion)
|
|
@@ -672,6 +689,10 @@ export function ResourceRendererDispatch({
|
|
|
672
689
|
isCalicoPolicyKind(kind) || kind === 'hostendpoints' || kind === 'ippools' || kind === 'tiers'
|
|
673
690
|
) && !isCoreNetworkPolicy && !((isCalicoPolicy || isCalicoHostEndpoint || isCalicoIPPool || isCalicoTier))
|
|
674
691
|
|
|
692
|
+
const nonCoreJobFallthrough = kind === 'jobs'
|
|
693
|
+
&& !!data?.apiVersion
|
|
694
|
+
&& !data.apiVersion.startsWith('batch/')
|
|
695
|
+
|
|
675
696
|
const isKnownKind = KNOWN_KINDS.has(kind) || isCrossplaneMR || isCrossplaneClaim || isCrossplaneXR
|
|
676
697
|
|
|
677
698
|
const PodComp = rendererOverrides?.PodRenderer ?? PodRenderer
|
|
@@ -727,6 +748,7 @@ export function ResourceRendererDispatch({
|
|
|
727
748
|
relationships={relationships}
|
|
728
749
|
scaleBlockedBy={scaleBlockedBy}
|
|
729
750
|
scalerDiagnostics={scalerDiagnostics}
|
|
751
|
+
workloadPods={workloadPods}
|
|
730
752
|
/>
|
|
731
753
|
)}
|
|
732
754
|
{kind === 'replicasets' && <ReplicaSetRenderer data={data} />}
|
|
@@ -735,13 +757,13 @@ export function ResourceRendererDispatch({
|
|
|
735
757
|
{kind === 'ingresses' && !data?.apiVersion?.includes('networking.internal.knative.dev') && <IngressRenderer data={data} onNavigate={onNavigate} />}
|
|
736
758
|
{kind === 'configmaps' && <ConfigMapRenderer data={data} />}
|
|
737
759
|
{kind === 'secrets' && <SecretRenderer data={data} certificateInfo={certificateInfo} resourceData={data} onSaveSecretValue={onSaveSecretValue} isSaving={isSavingSecret} />}
|
|
738
|
-
{kind === 'jobs' && <JobRenderer data={data} />}
|
|
760
|
+
{kind === 'jobs' && !nonCoreJobFallthrough && <JobRenderer data={data} />}
|
|
739
761
|
{kind === 'cronjobs' && <CronJobRenderer data={data} onNavigate={onNavigate} />}
|
|
740
762
|
{kind === 'cronworkflows' && <CronWorkflowRenderer data={data} onNavigate={onNavigate} />}
|
|
741
763
|
{(kind === 'hpas' || kind === 'horizontalpodautoscalers') && <HPAComp data={data} onNavigate={onNavigate} hpaDiagnosis={hpaDiagnosis} />}
|
|
742
764
|
{kind === 'nodes' && <NodeComp data={data} relationships={relationships} />}
|
|
743
765
|
{kind === 'persistentvolumeclaims' && <PVCComp data={data} onNavigate={onNavigate} />}
|
|
744
|
-
{kind === 'rollouts' && <RolloutComp data={data} onNavigate={onNavigate} />}
|
|
766
|
+
{kind === 'rollouts' && isArgoRolloutResource(data) && <RolloutComp data={data} onNavigate={onNavigate} />}
|
|
745
767
|
{kind === 'analysisruns' && <AnalysisRunRenderer data={data} onNavigate={onNavigate} />}
|
|
746
768
|
{kind === 'certificates' && !data?.apiVersion?.includes('networking.internal.knative.dev') && <CertificateRenderer data={data} />}
|
|
747
769
|
{kind === 'workflows' && <WorkflowRenderer data={data} onNavigate={onNavigate} />}
|
|
@@ -934,7 +956,7 @@ export function ResourceRendererDispatch({
|
|
|
934
956
|
for known-plural collisions where no apiVersion-gated renderer
|
|
935
957
|
matched (e.g. a Knative Configuration sharing the `configurations`
|
|
936
958
|
plural with Crossplane Configuration). */}
|
|
937
|
-
{(!isKnownKind || crossplaneCollisionFallthrough || kyvernoCollisionFallthrough || veleroCollisionFallthrough || groupGatedFallthrough || calicoCollisionFallthrough) && <GenericRenderer data={data} />}
|
|
959
|
+
{(!isKnownKind || crossplaneCollisionFallthrough || kyvernoCollisionFallthrough || veleroCollisionFallthrough || groupGatedFallthrough || calicoCollisionFallthrough || nonCoreJobFallthrough) && <GenericRenderer data={data} />}
|
|
938
960
|
|
|
939
961
|
{/* Common sections - can be disabled when parent handles them separately */}
|
|
940
962
|
{showCommonSections && (
|
|
@@ -988,7 +1010,10 @@ export function getResourceStatus(kind: string, data: any): { text: string; colo
|
|
|
988
1010
|
const k = kind.toLowerCase()
|
|
989
1011
|
|
|
990
1012
|
if (k === 'pods') return getPodStatus(data)
|
|
991
|
-
if (['deployments', 'statefulsets', '
|
|
1013
|
+
if (['deployments', 'statefulsets', 'daemonsets', 'rollouts'].includes(k)) {
|
|
1014
|
+
return getWorkloadDisplayStatus(data, k).status
|
|
1015
|
+
}
|
|
1016
|
+
if (k === 'replicasets') return getWorkloadStatus(data, k)
|
|
992
1017
|
if (k === 'services') {
|
|
993
1018
|
if (data.apiVersion?.includes('serving.knative.dev')) {
|
|
994
1019
|
const status = getKnativeConditionStatus(data)
|
|
@@ -1006,12 +1031,59 @@ export function getResourceStatus(kind: string, data: any): { text: string; colo
|
|
|
1006
1031
|
SEVERITY_BADGE.error
|
|
1007
1032
|
return { text, color }
|
|
1008
1033
|
}
|
|
1009
|
-
if (k === 'jobs')
|
|
1034
|
+
if (k === 'jobs') {
|
|
1035
|
+
if (data?.apiVersion?.startsWith('batch.volcano.sh/')) return getVolcanoJobStatus(data)
|
|
1036
|
+
if (!data?.apiVersion || data.apiVersion.startsWith('batch/')) return getJobStatus(data)
|
|
1037
|
+
}
|
|
1038
|
+
if (k === 'queues') {
|
|
1039
|
+
if (data?.apiVersion?.startsWith('scheduling.run.ai/')) return getKaiQueueStatus(data)
|
|
1040
|
+
if (data?.apiVersion?.startsWith('scheduling.volcano.sh/')) return getVolcanoQueueStatus(data)
|
|
1041
|
+
}
|
|
1042
|
+
if (k === 'podgroups') {
|
|
1043
|
+
if (data?.apiVersion?.startsWith('scheduling.run.ai/')) return getKaiPodGroupStatus(data)
|
|
1044
|
+
if (data?.apiVersion?.startsWith('scheduling.volcano.sh/')) return getVolcanoPodGroupStatus(data)
|
|
1045
|
+
}
|
|
1046
|
+
if (k === 'workspaces' && data?.apiVersion?.startsWith('kaito.sh/')) return getKaitoWorkspaceStatus(data)
|
|
1047
|
+
if (k === 'workloads' && data?.apiVersion?.startsWith('kueue.x-k8s.io/')) return getKueueWorkloadStatus(data)
|
|
1048
|
+
if (k === 'clusterqueues' && data?.apiVersion?.startsWith('kueue.x-k8s.io/')) return getClusterQueueStatus(data)
|
|
1049
|
+
if (k === 'localqueues' && data?.apiVersion?.startsWith('kueue.x-k8s.io/')) return getLocalQueueStatus(data)
|
|
1050
|
+
if (k === 'resourceflavors' && data?.apiVersion?.startsWith('kueue.x-k8s.io/')) return getResourceFlavorStatus(data)
|
|
1051
|
+
if (k === 'admissionchecks' && data?.apiVersion?.startsWith('kueue.x-k8s.io/')) return getAdmissionCheckStatus(data)
|
|
1052
|
+
if (k === 'provisioningrequests' && data?.apiVersion?.startsWith('autoscaling.x-k8s.io/')) return getProvisioningRequestStatus(data)
|
|
1053
|
+
if (k === 'rayclusters' && data?.apiVersion?.startsWith('ray.io/')) return getRayClusterStatus(data)
|
|
1054
|
+
if (k === 'rayjobs' && data?.apiVersion?.startsWith('ray.io/')) return getRayJobStatus(data)
|
|
1055
|
+
if (k === 'rayservices' && data?.apiVersion?.startsWith('ray.io/')) return getRayServiceStatus(data)
|
|
1056
|
+
if (k === 'raycronjobs' && data?.apiVersion?.startsWith('ray.io/')) return getRayCronJobStatus(data)
|
|
1057
|
+
if (k === 'leaderworkersets' && data?.apiVersion?.startsWith('leaderworkerset.x-k8s.io/')) return getLeaderWorkerSetStatus(data)
|
|
1058
|
+
if (k === 'jobsets' && data?.apiVersion?.startsWith('jobset.x-k8s.io/')) return getJobSetStatus(data)
|
|
1059
|
+
if (k === 'inferenceservices' && data?.apiVersion?.startsWith('serving.kserve.io/')) return getInferenceServiceStatus(data)
|
|
1060
|
+
if ((k === 'servingruntimes' || k === 'clusterservingruntimes') && data?.apiVersion?.startsWith('serving.kserve.io/')) return getServingRuntimeStatus(data)
|
|
1061
|
+
if (k === 'inferencegraphs' && data?.apiVersion?.startsWith('serving.kserve.io/')) return getInferenceGraphStatus(data)
|
|
1062
|
+
if (k === 'trainedmodels' && data?.apiVersion?.startsWith('serving.kserve.io/')) return getTrainedModelStatus(data)
|
|
1063
|
+
if (k === 'llminferenceservices' && data?.apiVersion?.startsWith('serving.kserve.io/')) return getLLMInferenceServiceStatus(data)
|
|
1064
|
+
if (k === 'inferencepools' && (
|
|
1065
|
+
data?.apiVersion?.startsWith('inference.networking.k8s.io/')
|
|
1066
|
+
|| data?.apiVersion?.startsWith('inference.networking.x-k8s.io/')
|
|
1067
|
+
)) return getInferencePoolStatus(data)
|
|
1068
|
+
if (k === 'inferenceobjectives' && (
|
|
1069
|
+
data?.apiVersion?.startsWith('inference.networking.x-k8s.io/')
|
|
1070
|
+
|| data?.apiVersion?.startsWith('llm-d.ai/')
|
|
1071
|
+
)) return getInferenceObjectiveStatus(data)
|
|
1072
|
+
if (k === 'jobflows' && data?.apiVersion?.startsWith('flow.volcano.sh/')) return getJobFlowStatus(data)
|
|
1073
|
+
if (k === 'jobtemplates' && data?.apiVersion?.startsWith('flow.volcano.sh/')) return getJobTemplateStatus(data)
|
|
1074
|
+
if (k === 'ragengines' && data?.apiVersion?.startsWith('kaito.sh/')) return getRAGEngineStatus(data)
|
|
1075
|
+
if (k === 'nimservices' && data?.apiVersion?.startsWith('apps.nvidia.com/')) return getNIMServiceStatus(data)
|
|
1076
|
+
if (k === 'nimcaches' && data?.apiVersion?.startsWith('apps.nvidia.com/')) return getNIMCacheStatus(data)
|
|
1077
|
+
if (k === 'nimpipelines' && data?.apiVersion?.startsWith('apps.nvidia.com/')) return getNIMPipelineStatus(data)
|
|
1078
|
+
if (k === 'deviceconfigs' && data?.apiVersion?.startsWith('amd.com/')) return getAMDDeviceConfigStatus(data)
|
|
1079
|
+
if (k === 'pytorchjobs' && data?.apiVersion?.startsWith('kubeflow.org/')) return getPyTorchJobStatus(data)
|
|
1080
|
+
if (k === 'tfjobs' && data?.apiVersion?.startsWith('kubeflow.org/')) return getTFJobStatus(data)
|
|
1081
|
+
if (k === 'mpijobs' && data?.apiVersion?.startsWith('kubeflow.org/')) return getMPIJobStatus(data)
|
|
1082
|
+
if (k === 'trainjobs' && data?.apiVersion?.startsWith('trainer.kubeflow.org/')) return getTrainJobStatus(data)
|
|
1010
1083
|
if (k === 'cronjobs') return getCronJobStatus(data)
|
|
1011
1084
|
if (k === 'hpas' || k === 'horizontalpodautoscalers') return getHPAStatus(data)
|
|
1012
1085
|
if (k === 'nodes') return getNodeStatus(data)
|
|
1013
1086
|
if (k === 'persistentvolumeclaims') return getPVCStatus(data)
|
|
1014
|
-
if (k === 'rollouts') return getRolloutStatus(data)
|
|
1015
1087
|
if (k === 'analysisruns') return getAnalysisRunStatus(data)
|
|
1016
1088
|
if (k === 'workflows') return getWorkflowStatus(data)
|
|
1017
1089
|
if (k === 'cronworkflows') return getCronWorkflowStatus(data)
|
|
@@ -1193,36 +1265,8 @@ export function getResourceStatus(kind: string, data: any): { text: string; colo
|
|
|
1193
1265
|
return { text: status.text, color: status.color }
|
|
1194
1266
|
}
|
|
1195
1267
|
|
|
1196
|
-
|
|
1197
|
-
|
|
1198
|
-
if (status) {
|
|
1199
|
-
if (status.phase) {
|
|
1200
|
-
const phase = String(status.phase)
|
|
1201
|
-
const healthyPhases = ['Running', 'Active', 'Succeeded', 'Ready', 'Healthy', 'Available', 'Bound']
|
|
1202
|
-
const warningPhases = ['Pending', 'Progressing', 'Unknown', 'Terminating']
|
|
1203
|
-
const isHealthy = healthyPhases.includes(phase)
|
|
1204
|
-
const isWarning = warningPhases.includes(phase)
|
|
1205
|
-
return {
|
|
1206
|
-
text: phase,
|
|
1207
|
-
color: isHealthy ? SEVERITY_BADGE.success :
|
|
1208
|
-
isWarning ? SEVERITY_BADGE.warning :
|
|
1209
|
-
SEVERITY_BADGE.error
|
|
1210
|
-
}
|
|
1211
|
-
}
|
|
1212
|
-
|
|
1213
|
-
if (status.conditions && Array.isArray(status.conditions)) {
|
|
1214
|
-
const readyCondition = status.conditions.find((c: any) =>
|
|
1215
|
-
c.type === 'Ready' || c.type === 'Available' || c.type === 'Progressing'
|
|
1216
|
-
)
|
|
1217
|
-
if (readyCondition) {
|
|
1218
|
-
const isReady = readyCondition.status === 'True'
|
|
1219
|
-
return {
|
|
1220
|
-
text: isReady ? 'Ready' : 'Not Ready',
|
|
1221
|
-
color: isReady ? SEVERITY_BADGE.success : SEVERITY_BADGE.warning
|
|
1222
|
-
}
|
|
1223
|
-
}
|
|
1224
|
-
}
|
|
1225
|
-
}
|
|
1268
|
+
const derived = getGenericResourceStatus(data)
|
|
1269
|
+
if (derived) return { text: derived.text, color: HEALTH_BADGE_COLORS[derived.tone] }
|
|
1226
1270
|
|
|
1227
1271
|
return null
|
|
1228
1272
|
}
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import type { WorkloadContainerImage } from '../../types/core'
|
|
4
|
+
import {
|
|
5
|
+
canSubmitImageUpdates,
|
|
6
|
+
changedImageUpdates,
|
|
7
|
+
describeImageUpdateBehavior,
|
|
8
|
+
reconcileRefreshedImageDrafts,
|
|
9
|
+
} from './SetImageDialog'
|
|
10
|
+
|
|
11
|
+
const containers: WorkloadContainerImage[] = [
|
|
12
|
+
{ type: 'container', name: 'app', image: 'repo/app:v1' },
|
|
13
|
+
{ type: 'container', name: 'sidecar', image: 'repo/sidecar:v1' },
|
|
14
|
+
{ type: 'initContainer', name: 'migrate', image: 'repo/migrate:v1' },
|
|
15
|
+
]
|
|
16
|
+
|
|
17
|
+
describe('changedImageUpdates', () => {
|
|
18
|
+
it('submits only changed rows with their reviewed previous images', () => {
|
|
19
|
+
expect(
|
|
20
|
+
changedImageUpdates(containers, {
|
|
21
|
+
['container\u0000app']: 'repo/app:v2',
|
|
22
|
+
['container\u0000sidecar']: 'repo/sidecar:v1',
|
|
23
|
+
['initContainer\u0000migrate']: ' repo/migrate:v2 ',
|
|
24
|
+
}),
|
|
25
|
+
).toEqual([
|
|
26
|
+
{
|
|
27
|
+
type: 'container',
|
|
28
|
+
name: 'app',
|
|
29
|
+
previousImage: 'repo/app:v1',
|
|
30
|
+
image: 'repo/app:v2',
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
type: 'initContainer',
|
|
34
|
+
name: 'migrate',
|
|
35
|
+
previousImage: 'repo/migrate:v1',
|
|
36
|
+
image: 'repo/migrate:v2',
|
|
37
|
+
},
|
|
38
|
+
])
|
|
39
|
+
})
|
|
40
|
+
|
|
41
|
+
it('does not turn an empty draft into a mutation', () => {
|
|
42
|
+
expect(
|
|
43
|
+
changedImageUpdates(containers.slice(0, 1), {
|
|
44
|
+
['container\u0000app']: ' ',
|
|
45
|
+
}),
|
|
46
|
+
).toEqual([])
|
|
47
|
+
})
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
describe('describeImageUpdateBehavior', () => {
|
|
51
|
+
it('does not promise an immediate rollout for paused, OnDelete, or partitioned controllers', () => {
|
|
52
|
+
expect(describeImageUpdateBehavior({ type: 'paused' })).toContain(
|
|
53
|
+
'no rollout starts',
|
|
54
|
+
)
|
|
55
|
+
expect(describeImageUpdateBehavior({ type: 'onDelete' })).toContain(
|
|
56
|
+
'until they are deleted',
|
|
57
|
+
)
|
|
58
|
+
expect(
|
|
59
|
+
describeImageUpdateBehavior({ type: 'partitioned', partition: 3 }),
|
|
60
|
+
).toContain('ordinal 3 or higher')
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
it('describes Argo promotion behavior from the Rollout strategy', () => {
|
|
64
|
+
expect(
|
|
65
|
+
describeImageUpdateBehavior({ type: 'canary', gated: true }),
|
|
66
|
+
).toContain('configured steps')
|
|
67
|
+
expect(
|
|
68
|
+
describeImageUpdateBehavior({ type: 'canary', gated: false }),
|
|
69
|
+
).toContain('100% without a pause')
|
|
70
|
+
expect(
|
|
71
|
+
describeImageUpdateBehavior({ type: 'blueGreen', autoPromote: true }),
|
|
72
|
+
).toContain('automatically')
|
|
73
|
+
expect(
|
|
74
|
+
describeImageUpdateBehavior({ type: 'blueGreen', autoPromote: false }),
|
|
75
|
+
).toContain('Promotion remains a separate action')
|
|
76
|
+
})
|
|
77
|
+
})
|
|
78
|
+
|
|
79
|
+
describe('reconcileRefreshedImageDrafts', () => {
|
|
80
|
+
it('preserves proposed images while adopting untouched concurrent changes', () => {
|
|
81
|
+
expect(
|
|
82
|
+
reconcileRefreshedImageDrafts(
|
|
83
|
+
containers,
|
|
84
|
+
[
|
|
85
|
+
{ type: 'container', name: 'app', image: 'repo/app:other' },
|
|
86
|
+
{ type: 'container', name: 'sidecar', image: 'repo/sidecar:other' },
|
|
87
|
+
{ type: 'initContainer', name: 'migrate', image: 'repo/migrate:v1' },
|
|
88
|
+
],
|
|
89
|
+
{
|
|
90
|
+
['container\u0000app']: 'repo/app:proposed',
|
|
91
|
+
['container\u0000sidecar']: 'repo/sidecar:v1',
|
|
92
|
+
['initContainer\u0000migrate']: 'repo/migrate:v1',
|
|
93
|
+
},
|
|
94
|
+
),
|
|
95
|
+
).toEqual({
|
|
96
|
+
drafts: {
|
|
97
|
+
['container\u0000app']: 'repo/app:proposed',
|
|
98
|
+
['container\u0000sidecar']: 'repo/sidecar:other',
|
|
99
|
+
['initContainer\u0000migrate']: 'repo/migrate:v1',
|
|
100
|
+
},
|
|
101
|
+
changedCurrentKeys: ['container\u0000app', 'container\u0000sidecar'],
|
|
102
|
+
})
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
describe('canSubmitImageUpdates', () => {
|
|
107
|
+
const ready = {
|
|
108
|
+
updateCount: 1,
|
|
109
|
+
hasEmptyImage: false,
|
|
110
|
+
managed: false,
|
|
111
|
+
ownershipResolved: true,
|
|
112
|
+
acknowledged: false,
|
|
113
|
+
busy: false,
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
it('requires break-glass acknowledgement for managed resources', () => {
|
|
117
|
+
expect(canSubmitImageUpdates({ ...ready, managed: true })).toBe(false)
|
|
118
|
+
expect(
|
|
119
|
+
canSubmitImageUpdates({ ...ready, managed: true, acknowledged: true }),
|
|
120
|
+
).toBe(true)
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
it('blocks empty images and concurrent submissions', () => {
|
|
124
|
+
expect(canSubmitImageUpdates({ ...ready, hasEmptyImage: true })).toBe(false)
|
|
125
|
+
expect(canSubmitImageUpdates({ ...ready, busy: true })).toBe(false)
|
|
126
|
+
expect(canSubmitImageUpdates({ ...ready, loadFailed: true })).toBe(false)
|
|
127
|
+
expect(canSubmitImageUpdates({ ...ready, ownershipResolved: false })).toBe(false)
|
|
128
|
+
})
|
|
129
|
+
})
|