@skyhook-io/k8s-ui 1.0.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 +63 -0
- package/src/components/dock/BottomDock.tsx +204 -0
- package/src/components/dock/DockContext.tsx +212 -0
- package/src/components/dock/TerminalTab.tsx +333 -0
- package/src/components/dock/index.ts +3 -0
- package/src/components/gitops/GitOpsActions.tsx +227 -0
- package/src/components/gitops/GitOpsStatusBadge.tsx +221 -0
- package/src/components/gitops/ManagedResourcesList.tsx +210 -0
- package/src/components/gitops/SyncCountdown.tsx +146 -0
- package/src/components/gitops/index.ts +4 -0
- package/src/components/logs/JsonLogLine.tsx +90 -0
- package/src/components/logs/LogCore.tsx +553 -0
- package/src/components/logs/LogToolbarSelects.tsx +74 -0
- package/src/components/logs/LogsViewer.tsx +146 -0
- package/src/components/logs/WorkloadLogsViewer.tsx +263 -0
- package/src/components/logs/index.ts +13 -0
- package/src/components/logs/useLogBuffer.ts +138 -0
- package/src/components/logs/useLogSearch.ts +151 -0
- package/src/components/logs/useLogStream.ts +61 -0
- package/src/components/resources/ResourcesView.tsx +5494 -0
- package/src/components/resources/index.ts +17 -0
- package/src/components/resources/renderers/AlertRenderer.tsx +166 -0
- package/src/components/resources/renderers/ArgoApplicationRenderer.tsx +233 -0
- package/src/components/resources/renderers/CNPGBackupRenderer.tsx +89 -0
- package/src/components/resources/renderers/CNPGClusterRenderer.tsx +194 -0
- package/src/components/resources/renderers/CNPGPoolerRenderer.tsx +79 -0
- package/src/components/resources/renderers/CNPGScheduledBackupRenderer.tsx +68 -0
- package/src/components/resources/renderers/CertificateRenderer.tsx +209 -0
- package/src/components/resources/renderers/CertificateRequestRenderer.tsx +123 -0
- package/src/components/resources/renderers/ChallengeRenderer.tsx +111 -0
- package/src/components/resources/renderers/ClusterComplianceReportRenderer.tsx +164 -0
- package/src/components/resources/renderers/ClusterExternalSecretRenderer.tsx +140 -0
- package/src/components/resources/renderers/ClusterIssuerRenderer.tsx +153 -0
- package/src/components/resources/renderers/ConfigAuditReportRenderer.tsx +221 -0
- package/src/components/resources/renderers/ConfigMapRenderer.tsx +124 -0
- package/src/components/resources/renderers/CronJobRenderer.tsx +86 -0
- package/src/components/resources/renderers/EventRenderer.tsx +175 -0
- package/src/components/resources/renderers/ExposedSecretReportRenderer.tsx +119 -0
- package/src/components/resources/renderers/ExternalSecretRenderer.tsx +172 -0
- package/src/components/resources/renderers/FluxHelmReleaseRenderer.tsx +242 -0
- package/src/components/resources/renderers/GRPCRouteRenderer.tsx +263 -0
- package/src/components/resources/renderers/GatewayClassRenderer.tsx +68 -0
- package/src/components/resources/renderers/GatewayRenderer.tsx +218 -0
- package/src/components/resources/renderers/GenericRenderer.tsx +476 -0
- package/src/components/resources/renderers/GitRepositoryRenderer.tsx +154 -0
- package/src/components/resources/renderers/HPARenderer.tsx +164 -0
- package/src/components/resources/renderers/HTTPRouteRenderer.tsx +303 -0
- package/src/components/resources/renderers/HelmRepositoryRenderer.tsx +167 -0
- package/src/components/resources/renderers/IngressClassRenderer.tsx +49 -0
- package/src/components/resources/renderers/IngressRenderer.tsx +104 -0
- package/src/components/resources/renderers/IstioAuthorizationPolicyRenderer.tsx +175 -0
- package/src/components/resources/renderers/IstioDestinationRuleRenderer.tsx +176 -0
- package/src/components/resources/renderers/IstioGatewayRenderer.tsx +125 -0
- package/src/components/resources/renderers/IstioPeerAuthenticationRenderer.tsx +84 -0
- package/src/components/resources/renderers/IstioServiceEntryRenderer.tsx +112 -0
- package/src/components/resources/renderers/IstioVirtualServiceRenderer.tsx +288 -0
- package/src/components/resources/renderers/JobRenderer.tsx +103 -0
- package/src/components/resources/renderers/KarpenterEC2NodeClassRenderer.tsx +157 -0
- package/src/components/resources/renderers/KarpenterNodeClaimRenderer.tsx +188 -0
- package/src/components/resources/renderers/KarpenterNodePoolRenderer.tsx +148 -0
- package/src/components/resources/renderers/KedaScaledJobRenderer.tsx +90 -0
- package/src/components/resources/renderers/KedaScaledObjectRenderer.tsx +136 -0
- package/src/components/resources/renderers/KedaTriggerAuthRenderer.tsx +151 -0
- package/src/components/resources/renderers/KnativeConfigurationRenderer.tsx +70 -0
- package/src/components/resources/renderers/KnativeEventingRenderer.tsx +309 -0
- package/src/components/resources/renderers/KnativeFlowRenderer.tsx +142 -0
- package/src/components/resources/renderers/KnativeNetworkingRenderer.tsx +232 -0
- package/src/components/resources/renderers/KnativeRevisionRenderer.tsx +97 -0
- package/src/components/resources/renderers/KnativeRouteRenderer.tsx +74 -0
- package/src/components/resources/renderers/KnativeServiceRenderer.tsx +138 -0
- package/src/components/resources/renderers/KnativeSourceRenderer.tsx +220 -0
- package/src/components/resources/renderers/KustomizationRenderer.tsx +151 -0
- package/src/components/resources/renderers/KyvernoPolicyReportRenderer.tsx +352 -0
- package/src/components/resources/renderers/LeaseRenderer.tsx +93 -0
- package/src/components/resources/renderers/NetworkPolicyRenderer.tsx +208 -0
- package/src/components/resources/renderers/NodeRenderer.tsx +282 -0
- package/src/components/resources/renderers/OCIRepositoryRenderer.tsx +153 -0
- package/src/components/resources/renderers/OrderRenderer.tsx +108 -0
- package/src/components/resources/renderers/PVCRenderer.tsx +98 -0
- package/src/components/resources/renderers/PersistentVolumeRenderer.tsx +138 -0
- package/src/components/resources/renderers/PodDisruptionBudgetRenderer.tsx +126 -0
- package/src/components/resources/renderers/PodMonitorRenderer.tsx +63 -0
- package/src/components/resources/renderers/PodRenderer.tsx +677 -0
- package/src/components/resources/renderers/PriorityClassRenderer.tsx +50 -0
- package/src/components/resources/renderers/PrometheusRuleRenderer.tsx +62 -0
- package/src/components/resources/renderers/ReplicaSetRenderer.tsx +71 -0
- package/src/components/resources/renderers/RoleBindingRenderer.tsx +97 -0
- package/src/components/resources/renderers/RoleRenderer.tsx +192 -0
- package/src/components/resources/renderers/RolloutRenderer.tsx +227 -0
- package/src/components/resources/renderers/RuntimeClassRenderer.tsx +75 -0
- package/src/components/resources/renderers/SbomReportRenderer.tsx +98 -0
- package/src/components/resources/renderers/SealedSecretRenderer.tsx +121 -0
- package/src/components/resources/renderers/SecretRenderer.tsx +321 -0
- package/src/components/resources/renderers/SecretStoreRenderer.tsx +111 -0
- package/src/components/resources/renderers/ServiceAccountRenderer.tsx +81 -0
- package/src/components/resources/renderers/ServiceMonitorRenderer.tsx +65 -0
- package/src/components/resources/renderers/ServiceRenderer.tsx +98 -0
- package/src/components/resources/renderers/SimpleRouteRenderer.tsx +195 -0
- package/src/components/resources/renderers/StorageClassRenderer.tsx +82 -0
- package/src/components/resources/renderers/TraefikIngressRouteRenderer.tsx +257 -0
- package/src/components/resources/renderers/VPARenderer.tsx +193 -0
- package/src/components/resources/renderers/VeleroBSLRenderer.tsx +73 -0
- package/src/components/resources/renderers/VeleroBackupRenderer.tsx +193 -0
- package/src/components/resources/renderers/VeleroRestoreRenderer.tsx +161 -0
- package/src/components/resources/renderers/VeleroScheduleRenderer.tsx +134 -0
- package/src/components/resources/renderers/VeleroVSLRenderer.tsx +36 -0
- package/src/components/resources/renderers/VulnerabilityReportRenderer.tsx +347 -0
- package/src/components/resources/renderers/WebhookConfigRenderer.tsx +156 -0
- package/src/components/resources/renderers/WorkflowRenderer.tsx +202 -0
- package/src/components/resources/renderers/WorkflowTemplateRenderer.tsx +91 -0
- package/src/components/resources/renderers/WorkloadRenderer.tsx +311 -0
- package/src/components/resources/renderers/argo-cells.tsx +118 -0
- package/src/components/resources/renderers/certmanager-cells.tsx +164 -0
- package/src/components/resources/renderers/cnpg-cells.tsx +161 -0
- package/src/components/resources/renderers/eso-cells.tsx +115 -0
- package/src/components/resources/renderers/flux-cells.tsx +253 -0
- package/src/components/resources/renderers/index.ts +105 -0
- package/src/components/resources/renderers/istio-cells.tsx +210 -0
- package/src/components/resources/renderers/karpenter-cells.tsx +107 -0
- package/src/components/resources/renderers/keda-cells.tsx +94 -0
- package/src/components/resources/renderers/knative-cells.tsx +396 -0
- package/src/components/resources/renderers/kyverno-cells.tsx +85 -0
- package/src/components/resources/renderers/prometheus-cells.tsx +74 -0
- package/src/components/resources/renderers/traefik-cells.tsx +120 -0
- package/src/components/resources/renderers/trivy-cells.tsx +153 -0
- package/src/components/resources/renderers/trivy-shared.tsx +67 -0
- package/src/components/resources/renderers/velero-cells.tsx +164 -0
- package/src/components/resources/resource-utils-argo.ts +155 -0
- package/src/components/resources/resource-utils-certmanager.ts +198 -0
- package/src/components/resources/resource-utils-cnpg.ts +344 -0
- package/src/components/resources/resource-utils-eso.ts +385 -0
- package/src/components/resources/resource-utils-flux.ts +186 -0
- package/src/components/resources/resource-utils-istio.ts +372 -0
- package/src/components/resources/resource-utils-karpenter.ts +150 -0
- package/src/components/resources/resource-utils-keda.ts +203 -0
- package/src/components/resources/resource-utils-knative.ts +218 -0
- package/src/components/resources/resource-utils-kyverno.ts +224 -0
- package/src/components/resources/resource-utils-prometheus.ts +159 -0
- package/src/components/resources/resource-utils-traefik.ts +180 -0
- package/src/components/resources/resource-utils-trivy.ts +146 -0
- package/src/components/resources/resource-utils-velero.ts +293 -0
- package/src/components/resources/resource-utils.ts +1558 -0
- package/src/components/shared/EditableYamlView.tsx +302 -0
- package/src/components/shared/ResourceActionsBar.tsx +924 -0
- package/src/components/shared/ResourceRendererDispatch.tsx +557 -0
- package/src/components/shared/index.ts +3 -0
- package/src/components/timeline/index.ts +1 -0
- package/src/components/timeline/shared.tsx +614 -0
- package/src/components/topology/GroupNode.tsx +198 -0
- package/src/components/topology/K8sResourceNode.tsx +440 -0
- package/src/components/topology/TopologyControls.tsx +62 -0
- package/src/components/topology/TopologyFilterSidebar.tsx +377 -0
- package/src/components/topology/TopologyGraph.tsx +748 -0
- package/src/components/topology/TopologySearch.tsx +304 -0
- package/src/components/topology/index.ts +7 -0
- package/src/components/topology/layout.ts +734 -0
- package/src/components/topology/layout.worker.ts +272 -0
- package/src/components/topology/topology.css +129 -0
- package/src/components/ui/CodeViewer.tsx +451 -0
- package/src/components/ui/ConfirmDialog.tsx +188 -0
- package/src/components/ui/ForceDeleteConfirmDialog.tsx +57 -0
- package/src/components/ui/HealthRing.tsx +72 -0
- package/src/components/ui/MetricsChart.tsx +259 -0
- package/src/components/ui/ResourceBar.tsx +68 -0
- package/src/components/ui/Toast.tsx +225 -0
- package/src/components/ui/Tooltip.tsx +165 -0
- package/src/components/ui/YamlEditor.tsx +280 -0
- package/src/components/ui/drawer-components.tsx +792 -0
- package/src/components/ui/index.ts +10 -0
- package/src/components/workload/ResourceDetailDrawer.tsx +158 -0
- package/src/components/workload/WorkloadView.tsx +1109 -0
- package/src/components/workload/index.ts +2 -0
- package/src/hooks/index.ts +9 -0
- package/src/hooks/useAnimatedUnmount.ts +30 -0
- package/src/hooks/useKeyboardShortcuts.tsx +336 -0
- package/src/hooks/useRefreshAnimation.ts +58 -0
- package/src/index.ts +35 -0
- package/src/types/core.ts +894 -0
- package/src/types/gitops.ts +458 -0
- package/src/types/index.ts +2 -0
- package/src/utils/animation.ts +40 -0
- package/src/utils/api-resources.ts +185 -0
- package/src/utils/badge-colors.ts +399 -0
- package/src/utils/context-name.ts +72 -0
- package/src/utils/download.ts +19 -0
- package/src/utils/format.ts +233 -0
- package/src/utils/index.ts +10 -0
- package/src/utils/log-format.ts +300 -0
- package/src/utils/navigation.ts +119 -0
- package/src/utils/resource-hierarchy.ts +630 -0
- package/src/utils/resource-icons.ts +206 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.json +24 -0
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
// Istio CRD utility functions
|
|
2
|
+
|
|
3
|
+
import type { StatusBadge } from './resource-utils'
|
|
4
|
+
import { healthColors } from './resource-utils'
|
|
5
|
+
|
|
6
|
+
// ============================================================================
|
|
7
|
+
// SHARED HELPERS
|
|
8
|
+
// ============================================================================
|
|
9
|
+
|
|
10
|
+
function parseIstioHost(host: string): { name: string; namespace: string } {
|
|
11
|
+
// Istio hosts can be: "reviews", "reviews.default", "reviews.default.svc.cluster.local"
|
|
12
|
+
const parts = host.split('.')
|
|
13
|
+
return {
|
|
14
|
+
name: parts[0] || host,
|
|
15
|
+
namespace: parts.length >= 2 ? parts[1] : '',
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// ============================================================================
|
|
20
|
+
// VIRTUALSERVICE UTILITIES
|
|
21
|
+
// ============================================================================
|
|
22
|
+
|
|
23
|
+
export function getVirtualServiceStatus(resource: any): StatusBadge {
|
|
24
|
+
const spec = resource.spec || {}
|
|
25
|
+
const httpRoutes = spec.http || []
|
|
26
|
+
const tcpRoutes = spec.tcp || []
|
|
27
|
+
const tlsRoutes = spec.tls || []
|
|
28
|
+
const hosts = spec.hosts || []
|
|
29
|
+
|
|
30
|
+
if (hosts.length === 0) {
|
|
31
|
+
return { text: 'No Hosts', color: healthColors.unhealthy, level: 'unhealthy' }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const totalRoutes = httpRoutes.length + tcpRoutes.length + tlsRoutes.length
|
|
35
|
+
if (totalRoutes === 0) {
|
|
36
|
+
return { text: 'No Routes', color: healthColors.unhealthy, level: 'unhealthy' }
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Check for fault injection on any route
|
|
40
|
+
const hasFaultInjection = httpRoutes.some((r: any) => r.fault)
|
|
41
|
+
if (hasFaultInjection) {
|
|
42
|
+
return { text: 'Fault Injection', color: healthColors.degraded, level: 'degraded' }
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Check for traffic mirroring
|
|
46
|
+
const hasMirror = httpRoutes.some((r: any) => r.mirror)
|
|
47
|
+
if (hasMirror) {
|
|
48
|
+
return { text: 'Mirroring', color: healthColors.degraded, level: 'degraded' }
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return { text: 'Active', color: healthColors.healthy, level: 'healthy' }
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function getVirtualServiceHosts(resource: any): string {
|
|
55
|
+
const hosts = resource.spec?.hosts || []
|
|
56
|
+
if (hosts.length === 0) return '-'
|
|
57
|
+
if (hosts.length > 3) return `${hosts.slice(0, 3).join(', ')} +${hosts.length - 3}`
|
|
58
|
+
return hosts.join(', ')
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function getVirtualServiceHostsList(resource: any): string[] {
|
|
62
|
+
return resource.spec?.hosts || []
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export function getVirtualServiceGateways(resource: any): string {
|
|
66
|
+
const gateways = resource.spec?.gateways || []
|
|
67
|
+
if (gateways.length === 0) return '-'
|
|
68
|
+
return gateways.join(', ')
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export function getVirtualServiceGatewaysList(resource: any): string[] {
|
|
72
|
+
return resource.spec?.gateways || []
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export function getVirtualServiceRouteCount(resource: any): number {
|
|
76
|
+
const spec = resource.spec || {}
|
|
77
|
+
return (spec.http || []).length + (spec.tcp || []).length + (spec.tls || []).length
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export function getVirtualServiceHttpRoutes(resource: any): Array<{
|
|
81
|
+
match?: any[]
|
|
82
|
+
route?: Array<{ destination: { host: string; port?: { number: number }; subset?: string }; weight?: number }>
|
|
83
|
+
timeout?: string
|
|
84
|
+
retries?: { attempts: number; perTryTimeout?: string; retryOn?: string }
|
|
85
|
+
fault?: { delay?: { percentage?: { value: number }; fixedDelay?: string }; abort?: { percentage?: { value: number }; httpStatus?: number } }
|
|
86
|
+
mirror?: { host: string; port?: { number: number } }
|
|
87
|
+
mirrorPercentage?: { value: number }
|
|
88
|
+
name?: string
|
|
89
|
+
}> {
|
|
90
|
+
return resource.spec?.http || []
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export function getVirtualServiceTcpRoutes(resource: any): any[] {
|
|
94
|
+
return resource.spec?.tcp || []
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function getVirtualServiceTlsRoutes(resource: any): any[] {
|
|
98
|
+
return resource.spec?.tls || []
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function getVirtualServiceDestinations(resource: any): Array<{ host: string; namespace: string; port?: number; subset?: string; weight?: number }> {
|
|
102
|
+
const destinations: Array<{ host: string; namespace: string; port?: number; subset?: string; weight?: number }> = []
|
|
103
|
+
const httpRoutes = resource.spec?.http || []
|
|
104
|
+
for (const route of httpRoutes) {
|
|
105
|
+
for (const dest of (route.route || [])) {
|
|
106
|
+
if (dest.destination?.host) {
|
|
107
|
+
const parsed = parseIstioHost(dest.destination.host)
|
|
108
|
+
destinations.push({
|
|
109
|
+
host: dest.destination.host,
|
|
110
|
+
namespace: parsed.namespace || resource.metadata?.namespace || '',
|
|
111
|
+
port: dest.destination.port?.number,
|
|
112
|
+
subset: dest.destination.subset,
|
|
113
|
+
weight: dest.weight,
|
|
114
|
+
})
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return destinations
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// ============================================================================
|
|
122
|
+
// DESTINATIONRULE UTILITIES
|
|
123
|
+
// ============================================================================
|
|
124
|
+
|
|
125
|
+
export function getDestinationRuleStatus(resource: any): StatusBadge {
|
|
126
|
+
const spec = resource.spec || {}
|
|
127
|
+
const host = spec.host
|
|
128
|
+
|
|
129
|
+
if (!host) {
|
|
130
|
+
return { text: 'No Host', color: healthColors.unhealthy, level: 'unhealthy' }
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const subsets = spec.subsets || []
|
|
134
|
+
const trafficPolicy = spec.trafficPolicy
|
|
135
|
+
|
|
136
|
+
if (subsets.length > 0) {
|
|
137
|
+
return { text: `${subsets.length} Subset${subsets.length !== 1 ? 's' : ''}`, color: healthColors.healthy, level: 'healthy' }
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (trafficPolicy) {
|
|
141
|
+
return { text: 'Configured', color: healthColors.healthy, level: 'healthy' }
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return { text: 'Active', color: healthColors.healthy, level: 'healthy' }
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export function getDestinationRuleHost(resource: any): string {
|
|
148
|
+
return resource.spec?.host || '-'
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
export function getDestinationRuleSubsetCount(resource: any): number {
|
|
152
|
+
return (resource.spec?.subsets || []).length
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export function getDestinationRuleSubsets(resource: any): Array<{ name: string; labels: Record<string, string>; trafficPolicy?: any }> {
|
|
156
|
+
return (resource.spec?.subsets || []).map((s: any) => ({
|
|
157
|
+
name: s.name || '',
|
|
158
|
+
labels: s.labels || {},
|
|
159
|
+
trafficPolicy: s.trafficPolicy,
|
|
160
|
+
}))
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export function getDestinationRuleTrafficPolicy(resource: any): {
|
|
164
|
+
connectionPool?: { tcp?: any; http?: any }
|
|
165
|
+
loadBalancer?: { simple?: string; consistentHash?: any }
|
|
166
|
+
outlierDetection?: any
|
|
167
|
+
tls?: { mode?: string }
|
|
168
|
+
} | null {
|
|
169
|
+
return resource.spec?.trafficPolicy || null
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
export function getDestinationRuleLoadBalancer(resource: any): string {
|
|
173
|
+
const lb = resource.spec?.trafficPolicy?.loadBalancer
|
|
174
|
+
if (!lb) return '-'
|
|
175
|
+
if (lb.simple) return lb.simple
|
|
176
|
+
if (lb.consistentHash) return 'ConsistentHash'
|
|
177
|
+
return '-'
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// ============================================================================
|
|
181
|
+
// ISTIO GATEWAY UTILITIES
|
|
182
|
+
// ============================================================================
|
|
183
|
+
|
|
184
|
+
export function getIstioGatewayStatus(resource: any): StatusBadge {
|
|
185
|
+
const servers = resource.spec?.servers || []
|
|
186
|
+
|
|
187
|
+
if (servers.length === 0) {
|
|
188
|
+
return { text: 'No Servers', color: healthColors.unhealthy, level: 'unhealthy' }
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
const hasTLS = servers.some((s: any) => s.tls)
|
|
192
|
+
if (hasTLS) {
|
|
193
|
+
return { text: 'TLS', color: healthColors.healthy, level: 'healthy' }
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
return { text: 'Active', color: healthColors.healthy, level: 'healthy' }
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export function getIstioGatewayServers(resource: any): Array<{
|
|
200
|
+
port: { number: number; name: string; protocol: string }
|
|
201
|
+
hosts: string[]
|
|
202
|
+
tls?: { mode?: string; credentialName?: string; serverCertificate?: string; privateKey?: string }
|
|
203
|
+
}> {
|
|
204
|
+
return (resource.spec?.servers || []).map((s: any) => ({
|
|
205
|
+
port: s.port || { number: 0, name: '', protocol: '' },
|
|
206
|
+
hosts: s.hosts || [],
|
|
207
|
+
tls: s.tls,
|
|
208
|
+
}))
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export function getIstioGatewayServerCount(resource: any): number {
|
|
212
|
+
return (resource.spec?.servers || []).length
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
export function getIstioGatewaySelector(resource: any): Record<string, string> {
|
|
216
|
+
return resource.spec?.selector || {}
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
export function getIstioGatewaySelectorString(resource: any): string {
|
|
220
|
+
const selector = resource.spec?.selector || {}
|
|
221
|
+
const entries = Object.entries(selector)
|
|
222
|
+
if (entries.length === 0) return '-'
|
|
223
|
+
return entries.map(([k, v]) => `${k}=${v}`).join(', ')
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// ============================================================================
|
|
227
|
+
// SERVICEENTRY UTILITIES
|
|
228
|
+
// ============================================================================
|
|
229
|
+
|
|
230
|
+
export function getServiceEntryStatus(resource: any): StatusBadge {
|
|
231
|
+
const spec = resource.spec || {}
|
|
232
|
+
const hosts = spec.hosts || []
|
|
233
|
+
|
|
234
|
+
if (hosts.length === 0) {
|
|
235
|
+
return { text: 'No Hosts', color: healthColors.unhealthy, level: 'unhealthy' }
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const location = spec.location || 'MESH_EXTERNAL'
|
|
239
|
+
if (location === 'MESH_EXTERNAL') {
|
|
240
|
+
return { text: 'External', color: healthColors.healthy, level: 'healthy' }
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
return { text: 'Internal', color: healthColors.healthy, level: 'healthy' }
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export function getServiceEntryHosts(resource: any): string {
|
|
247
|
+
const hosts = resource.spec?.hosts || []
|
|
248
|
+
if (hosts.length === 0) return '-'
|
|
249
|
+
if (hosts.length > 3) return `${hosts.slice(0, 3).join(', ')} +${hosts.length - 3}`
|
|
250
|
+
return hosts.join(', ')
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export function getServiceEntryHostsList(resource: any): string[] {
|
|
254
|
+
return resource.spec?.hosts || []
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export function getServiceEntryLocation(resource: any): string {
|
|
258
|
+
return resource.spec?.location || 'MESH_EXTERNAL'
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export function getServiceEntryPorts(resource: any): Array<{ number: number; name: string; protocol: string }> {
|
|
262
|
+
return (resource.spec?.ports || []).map((p: any) => ({
|
|
263
|
+
number: p.number || 0,
|
|
264
|
+
name: p.name || '',
|
|
265
|
+
protocol: p.protocol || '',
|
|
266
|
+
}))
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export function getServiceEntryPortsString(resource: any): string {
|
|
270
|
+
const ports = resource.spec?.ports || []
|
|
271
|
+
if (ports.length === 0) return '-'
|
|
272
|
+
return ports.map((p: any) => `${p.number}/${p.protocol || 'TCP'}`).join(', ')
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export function getServiceEntryResolution(resource: any): string {
|
|
276
|
+
return resource.spec?.resolution || 'NONE'
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export function getServiceEntryEndpoints(resource: any): Array<{ address: string; ports?: Record<string, number>; labels?: Record<string, string> }> {
|
|
280
|
+
return (resource.spec?.endpoints || []).map((e: any) => ({
|
|
281
|
+
address: e.address || '',
|
|
282
|
+
ports: e.ports,
|
|
283
|
+
labels: e.labels,
|
|
284
|
+
}))
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// ============================================================================
|
|
288
|
+
// PEERAUTHENTICATION UTILITIES
|
|
289
|
+
// ============================================================================
|
|
290
|
+
|
|
291
|
+
export function getPeerAuthenticationStatus(resource: any): StatusBadge {
|
|
292
|
+
const mode = resource.spec?.mtls?.mode || 'UNSET'
|
|
293
|
+
|
|
294
|
+
switch (mode) {
|
|
295
|
+
case 'STRICT':
|
|
296
|
+
return { text: 'Strict mTLS', color: healthColors.healthy, level: 'healthy' }
|
|
297
|
+
case 'PERMISSIVE':
|
|
298
|
+
return { text: 'Permissive', color: healthColors.degraded, level: 'degraded' }
|
|
299
|
+
case 'DISABLE':
|
|
300
|
+
return { text: 'Disabled', color: healthColors.unhealthy, level: 'unhealthy' }
|
|
301
|
+
default:
|
|
302
|
+
return { text: 'Unset', color: healthColors.unknown, level: 'unknown' }
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export function getPeerAuthenticationMode(resource: any): string {
|
|
307
|
+
return resource.spec?.mtls?.mode || 'UNSET'
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
export function getPeerAuthenticationSelector(resource: any): Record<string, string> {
|
|
311
|
+
return resource.spec?.selector?.matchLabels || {}
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
export function getPeerAuthenticationSelectorString(resource: any): string {
|
|
315
|
+
const labels = resource.spec?.selector?.matchLabels || {}
|
|
316
|
+
const entries = Object.entries(labels)
|
|
317
|
+
if (entries.length === 0) return 'Namespace-wide'
|
|
318
|
+
return entries.map(([k, v]) => `${k}=${v}`).join(', ')
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
export function getPeerAuthenticationPortLevelMtls(resource: any): Record<string, { mode: string }> {
|
|
322
|
+
return resource.spec?.portLevelMtls || {}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// ============================================================================
|
|
326
|
+
// AUTHORIZATIONPOLICY UTILITIES
|
|
327
|
+
// ============================================================================
|
|
328
|
+
|
|
329
|
+
export function getAuthorizationPolicyStatus(resource: any): StatusBadge {
|
|
330
|
+
const action = resource.spec?.action || 'ALLOW'
|
|
331
|
+
const rules = resource.spec?.rules || []
|
|
332
|
+
|
|
333
|
+
switch (action) {
|
|
334
|
+
case 'ALLOW':
|
|
335
|
+
return { text: `Allow (${rules.length} rule${rules.length !== 1 ? 's' : ''})`, color: healthColors.healthy, level: 'healthy' }
|
|
336
|
+
case 'DENY':
|
|
337
|
+
return { text: `Deny (${rules.length} rule${rules.length !== 1 ? 's' : ''})`, color: healthColors.unhealthy, level: 'unhealthy' }
|
|
338
|
+
case 'CUSTOM':
|
|
339
|
+
return { text: 'Custom', color: healthColors.degraded, level: 'degraded' }
|
|
340
|
+
case 'AUDIT':
|
|
341
|
+
return { text: 'Audit', color: healthColors.degraded, level: 'degraded' }
|
|
342
|
+
default:
|
|
343
|
+
return { text: action, color: healthColors.unknown, level: 'unknown' }
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
export function getAuthorizationPolicyAction(resource: any): string {
|
|
348
|
+
return resource.spec?.action || 'ALLOW'
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
export function getAuthorizationPolicyRuleCount(resource: any): number {
|
|
352
|
+
return (resource.spec?.rules || []).length
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
export function getAuthorizationPolicyRules(resource: any): Array<{
|
|
356
|
+
from?: Array<{ source: { principals?: string[]; namespaces?: string[]; ipBlocks?: string[] } }>
|
|
357
|
+
to?: Array<{ operation: { hosts?: string[]; ports?: string[]; methods?: string[]; paths?: string[] } }>
|
|
358
|
+
when?: Array<{ key: string; values?: string[]; notValues?: string[] }>
|
|
359
|
+
}> {
|
|
360
|
+
return resource.spec?.rules || []
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
export function getAuthorizationPolicySelector(resource: any): Record<string, string> {
|
|
364
|
+
return resource.spec?.selector?.matchLabels || {}
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
export function getAuthorizationPolicySelectorString(resource: any): string {
|
|
368
|
+
const labels = resource.spec?.selector?.matchLabels || {}
|
|
369
|
+
const entries = Object.entries(labels)
|
|
370
|
+
if (entries.length === 0) return 'Namespace-wide'
|
|
371
|
+
return entries.map(([k, v]) => `${k}=${v}`).join(', ')
|
|
372
|
+
}
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
// Karpenter CRD utility functions
|
|
2
|
+
|
|
3
|
+
import type { StatusBadge } from './resource-utils'
|
|
4
|
+
import { healthColors } from './resource-utils'
|
|
5
|
+
|
|
6
|
+
// ============================================================================
|
|
7
|
+
// KARPENTER NODEPOOL UTILITIES
|
|
8
|
+
// ============================================================================
|
|
9
|
+
|
|
10
|
+
export function getNodePoolStatus(resource: any): StatusBadge {
|
|
11
|
+
const conditions = resource.status?.conditions || []
|
|
12
|
+
const readyCond = conditions.find((c: any) => c.type === 'Ready')
|
|
13
|
+
|
|
14
|
+
if (readyCond?.status === 'True') {
|
|
15
|
+
return { text: 'Ready', color: healthColors.healthy, level: 'healthy' }
|
|
16
|
+
}
|
|
17
|
+
if (readyCond?.status === 'False') {
|
|
18
|
+
return { text: readyCond.reason || 'NotReady', color: healthColors.unhealthy, level: 'unhealthy' }
|
|
19
|
+
}
|
|
20
|
+
return { text: 'Unknown', color: healthColors.unknown, level: 'unknown' }
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function getNodePoolNodeClassRef(resource: any): string {
|
|
24
|
+
const ref = resource.spec?.template?.spec?.nodeClassRef
|
|
25
|
+
if (!ref) return '-'
|
|
26
|
+
return ref.name || `${ref.group}/${ref.kind}`
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function getNodePoolLimits(resource: any): string {
|
|
30
|
+
const limits = resource.spec?.limits || {}
|
|
31
|
+
const parts: string[] = []
|
|
32
|
+
if (limits.cpu) parts.push(`CPU: ${limits.cpu}`)
|
|
33
|
+
if (limits.memory) parts.push(`Mem: ${limits.memory}`)
|
|
34
|
+
return parts.length > 0 ? parts.join(', ') : '-'
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function getNodePoolDisruptionPolicy(resource: any): string {
|
|
38
|
+
return resource.spec?.disruption?.consolidationPolicy || 'WhenEmptyOrUnderutilized'
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function getNodePoolRequirements(resource: any): Array<{ key: string; operator: string; values: string[] }> {
|
|
42
|
+
return resource.spec?.template?.spec?.requirements || []
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function getNodePoolWeight(resource: any): number | undefined {
|
|
46
|
+
return resource.spec?.weight
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ============================================================================
|
|
50
|
+
// KARPENTER NODECLAIM UTILITIES
|
|
51
|
+
// ============================================================================
|
|
52
|
+
|
|
53
|
+
export function getNodeClaimStatus(resource: any): StatusBadge {
|
|
54
|
+
const conditions = resource.status?.conditions || []
|
|
55
|
+
|
|
56
|
+
// Check conditions in priority order: Ready > Launched > Initialized
|
|
57
|
+
const readyCond = conditions.find((c: any) => c.type === 'Ready')
|
|
58
|
+
if (readyCond?.status === 'True') {
|
|
59
|
+
return { text: 'Ready', color: healthColors.healthy, level: 'healthy' }
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const launchedCond = conditions.find((c: any) => c.type === 'Launched')
|
|
63
|
+
if (launchedCond?.status === 'True') {
|
|
64
|
+
const registeredCond = conditions.find((c: any) => c.type === 'Registered')
|
|
65
|
+
if (registeredCond?.status === 'True') {
|
|
66
|
+
return { text: 'Registered', color: healthColors.degraded, level: 'degraded' }
|
|
67
|
+
}
|
|
68
|
+
return { text: 'Launched', color: healthColors.degraded, level: 'degraded' }
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const initializedCond = conditions.find((c: any) => c.type === 'Initialized')
|
|
72
|
+
if (initializedCond?.status === 'True') {
|
|
73
|
+
return { text: 'Initialized', color: healthColors.degraded, level: 'degraded' }
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
if (readyCond?.status === 'False') {
|
|
77
|
+
return { text: readyCond.reason || 'NotReady', color: healthColors.unhealthy, level: 'unhealthy' }
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return { text: 'Pending', color: healthColors.unknown, level: 'unknown' }
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function getNodeClaimInstanceType(resource: any): string {
|
|
84
|
+
// v1beta1: status.instanceType; v1: label or spec.requirements fallback
|
|
85
|
+
return resource.status?.instanceType
|
|
86
|
+
|| resource.metadata?.labels?.['node.kubernetes.io/instance-type']
|
|
87
|
+
|| resource.spec?.requirements?.find((r: any) => r.key === 'node.kubernetes.io/instance-type')?.values?.[0]
|
|
88
|
+
|| '-'
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function getNodeClaimNodeName(resource: any): string {
|
|
92
|
+
return resource.status?.nodeName || '-'
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function getNodeClaimCapacity(resource: any): Record<string, string> {
|
|
96
|
+
return resource.status?.capacity || {}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function getNodeClaimNodePoolRef(resource: any): string {
|
|
100
|
+
return resource.metadata?.labels?.['karpenter.sh/nodepool'] || '-'
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function getNodeClaimRequirements(resource: any): Array<{ key: string; operator: string; values: string[] }> {
|
|
104
|
+
return resource.spec?.requirements || []
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function getNodeClaimNodeClassRef(resource: any): { group?: string; kind?: string; name?: string } | null {
|
|
108
|
+
return resource.spec?.nodeClassRef || null
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function getNodeClaimExpireAfter(resource: any): string | undefined {
|
|
112
|
+
return resource.spec?.expireAfter
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// ============================================================================
|
|
116
|
+
// KARPENTER EC2NODECLASS UTILITIES
|
|
117
|
+
// ============================================================================
|
|
118
|
+
|
|
119
|
+
export function getEC2NodeClassStatus(resource: any): StatusBadge {
|
|
120
|
+
const conditions = resource.status?.conditions || []
|
|
121
|
+
const readyCond = conditions.find((c: any) => c.type === 'Ready')
|
|
122
|
+
|
|
123
|
+
if (readyCond?.status === 'True') {
|
|
124
|
+
return { text: 'Ready', color: healthColors.healthy, level: 'healthy' }
|
|
125
|
+
}
|
|
126
|
+
if (readyCond?.status === 'False') {
|
|
127
|
+
return { text: readyCond.reason || 'NotReady', color: healthColors.unhealthy, level: 'unhealthy' }
|
|
128
|
+
}
|
|
129
|
+
return { text: 'Unknown', color: healthColors.unknown, level: 'unknown' }
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export function getEC2NodeClassAMI(resource: any): string {
|
|
133
|
+
const terms = resource.spec?.amiSelectorTerms || []
|
|
134
|
+
if (terms.length === 0) return '-'
|
|
135
|
+
// Show alias if available (e.g., "al2023@latest"), otherwise show ID
|
|
136
|
+
const first = terms[0]
|
|
137
|
+
return first.alias || first.id || first.name || '-'
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export function getEC2NodeClassRole(resource: any): string {
|
|
141
|
+
return resource.spec?.role || '-'
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function getEC2NodeClassVolumeSize(resource: any): string {
|
|
145
|
+
const mappings = resource.spec?.blockDeviceMappings || []
|
|
146
|
+
if (mappings.length === 0) return '-'
|
|
147
|
+
const first = mappings[0]
|
|
148
|
+
const size = first.ebs?.volumeSize
|
|
149
|
+
return size || '-'
|
|
150
|
+
}
|